-
Notifications
You must be signed in to change notification settings - Fork 1
/
rr_set.go
86 lines (73 loc) · 2.35 KB
/
rr_set.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
/*
* Copyright 2024 Johan Stenstam, johan.stenstam@internetstiftelsen.se
*/
package tapir
import (
"bytes"
"fmt"
"github.com/miekg/dns"
)
// RRArray represents an array of rrs
// It implements Swapper interface, and is sortable.
type RRArray []dns.RR
// Len returns the length of an RRArray.
func (array RRArray) Len() int {
return len(array)
}
// Swap swaps elements on positions i and j from RRArray
func (array RRArray) Swap(i, j int) {
array[i], array[j] = array[j], array[i]
}
// Less returns true if the element in the position i of RRArray is less than the element in position j of RRArray.
func (array RRArray) Less(i, j int) bool {
// RR Canonical order:
// 1.- Canonical Owner Name (RFC 3034 6.1)
// 2.- RR Class
// 3.- Type
// 4.- RRData (as left-aligned canonical form)
si := dns.SplitDomainName(array[i].Header().Name)
sj := dns.SplitDomainName(array[j].Header().Name)
// Comparing tags, right to left
ii, ij := len(si)-1, len(sj)-1
for ii >= 0 && ij >= 0 {
if si[ii] != sj[ij] {
return si[ii] < sj[ij]
}
ii--
ij--
}
// Now one is a subdomain (or the same domain) of the other
if ii != ij {
return ii < ij
}
// Equal subdomain
if array[i].Header().Class != array[j].Header().Class {
return array[i].Header().Class < array[j].Header().Class
} else if array[i].Header().Rrtype != array[j].Header().Rrtype {
return array[i].Header().Rrtype < array[j].Header().Rrtype
} else {
return compareRRData(array[i], array[j])
}
}
func compareRRData(rri, rrj dns.RR) bool {
bytei := make([]byte, dns.MaxMsgSize)
sizei, err := dns.PackRR(rri, bytei, 0, nil, false)
if err != nil {
return false
}
rrdatai := bytei[uint16(sizei)-rri.Header().Rdlength : sizei] // We remove the header from the representation
bytej := make([]byte, dns.MaxMsgSize)
sizej, err := dns.PackRR(rrj, bytej, 0, nil, false)
if err != nil {
return false
}
rrdataj := bytej[uint16(sizej)-rrj.Header().Rdlength : sizej] // We remove the header from the representation
return bytes.Compare(rrdatai, rrdataj) < 0
}
// String returns a string representation of the RRArray, based on the name, class and Rrtype of the first element.
func (array RRArray) String() string {
if len(array) == 0 {
return "<empty_setlist>"
}
return fmt.Sprintf("%s#%s#%s", array[0].Header().Name, dns.ClassToString[array[0].Header().Class], dns.TypeToString[array[0].Header().Rrtype])
}