sanitize.go (2028B)
1 package dns 2 3 // Dedup removes identical RRs from rrs. It preserves the original ordering. 4 // The lowest TTL of any duplicates is used in the remaining one. Dedup modifies 5 // rrs. 6 // m is used to store the RRs temporary. If it is nil a new map will be allocated. 7 func Dedup(rrs []RR, m map[string]RR) []RR { 8 9 if m == nil { 10 m = make(map[string]RR) 11 } 12 // Save the keys, so we don't have to call normalizedString twice. 13 keys := make([]*string, 0, len(rrs)) 14 15 for _, r := range rrs { 16 key := normalizedString(r) 17 keys = append(keys, &key) 18 if mr, ok := m[key]; ok { 19 // Shortest TTL wins. 20 rh, mrh := r.Header(), mr.Header() 21 if mrh.Ttl > rh.Ttl { 22 mrh.Ttl = rh.Ttl 23 } 24 continue 25 } 26 27 m[key] = r 28 } 29 // If the length of the result map equals the amount of RRs we got, 30 // it means they were all different. We can then just return the original rrset. 31 if len(m) == len(rrs) { 32 return rrs 33 } 34 35 j := 0 36 for i, r := range rrs { 37 // If keys[i] lives in the map, we should copy and remove it. 38 if _, ok := m[*keys[i]]; ok { 39 delete(m, *keys[i]) 40 rrs[j] = r 41 j++ 42 } 43 44 if len(m) == 0 { 45 break 46 } 47 } 48 49 return rrs[:j] 50 } 51 52 // normalizedString returns a normalized string from r. The TTL 53 // is removed and the domain name is lowercased. We go from this: 54 // DomainName<TAB>TTL<TAB>CLASS<TAB>TYPE<TAB>RDATA to: 55 // lowercasename<TAB>CLASS<TAB>TYPE... 56 func normalizedString(r RR) string { 57 // A string Go DNS makes has: domainname<TAB>TTL<TAB>... 58 b := []byte(r.String()) 59 60 // find the first non-escaped tab, then another, so we capture where the TTL lives. 61 esc := false 62 ttlStart, ttlEnd := 0, 0 63 for i := 0; i < len(b) && ttlEnd == 0; i++ { 64 switch { 65 case b[i] == '\\': 66 esc = !esc 67 case b[i] == '\t' && !esc: 68 if ttlStart == 0 { 69 ttlStart = i 70 continue 71 } 72 if ttlEnd == 0 { 73 ttlEnd = i 74 } 75 case b[i] >= 'A' && b[i] <= 'Z' && !esc: 76 b[i] += 32 77 default: 78 esc = false 79 } 80 } 81 82 // remove TTL. 83 copy(b[ttlStart:], b[ttlEnd:]) 84 cut := ttlEnd - ttlStart 85 return string(b[:len(b)-cut]) 86 }