You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

sanitize.go 2.0KB

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