types.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. package main
  2. import (
  3. "github.com/abh/geodns/countries"
  4. "github.com/miekg/dns"
  5. "strings"
  6. "time"
  7. )
  8. type Options struct {
  9. Serial int
  10. Ttl int
  11. MaxHosts int
  12. Contact string
  13. }
  14. type Record struct {
  15. RR dns.RR
  16. Weight int
  17. }
  18. type Records []Record
  19. func (s Records) Len() int { return len(s) }
  20. func (s Records) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
  21. type RecordsByWeight struct{ Records }
  22. func (s RecordsByWeight) Less(i, j int) bool { return s.Records[i].Weight > s.Records[j].Weight }
  23. type Label struct {
  24. Label string
  25. MaxHosts int
  26. Ttl int
  27. Records map[uint16]Records
  28. Weight map[uint16]int
  29. }
  30. type labels map[string]*Label
  31. type Zones map[string]*Zone
  32. type Zone struct {
  33. Origin string
  34. Labels labels
  35. LenLabels int
  36. Options Options
  37. LastRead time.Time
  38. }
  39. type qTypes []uint16
  40. func (l *Label) firstRR(dnsType uint16) dns.RR {
  41. return l.Records[dnsType][0].RR
  42. }
  43. func (z *Zone) AddLabel(k string) *Label {
  44. k = strings.ToLower(k)
  45. z.Labels[k] = new(Label)
  46. label := z.Labels[k]
  47. label.Label = k
  48. label.Ttl = z.Options.Ttl
  49. label.MaxHosts = z.Options.MaxHosts
  50. label.Records = make(map[uint16]Records)
  51. label.Weight = make(map[uint16]int)
  52. return label
  53. }
  54. func (z *Zone) SoaRR() dns.RR {
  55. return z.Labels[""].firstRR(dns.TypeSOA)
  56. }
  57. func (z *Zone) findLabels(s, cc string, qts qTypes) (*Label, uint16) {
  58. selectors := []string{}
  59. if len(cc) > 0 {
  60. continent := countries.CountryContinent[cc]
  61. var s_cc string
  62. if len(s) > 0 {
  63. s_cc = s + "." + cc
  64. if len(continent) > 0 {
  65. continent = s + "." + continent
  66. }
  67. } else {
  68. s_cc = cc
  69. }
  70. selectors = append(selectors, s_cc, continent)
  71. }
  72. selectors = append(selectors, s)
  73. for _, name := range selectors {
  74. if label, ok := z.Labels[name]; ok {
  75. for _, qtype := range qts {
  76. switch qtype {
  77. case dns.TypeANY:
  78. // short-circuit mostly to avoid subtle bugs later
  79. // to be correct we should run through all the selectors and
  80. // pick types not already picked
  81. return z.Labels[s], qtype
  82. case dns.TypeMF:
  83. if label.Records[dns.TypeMF] != nil {
  84. name = label.firstRR(dns.TypeMF).(*dns.MF).Mf
  85. // TODO: need to avoid loops here somehow
  86. return z.findLabels(name, cc, qts)
  87. }
  88. default:
  89. // return the label if it has the right record
  90. if label.Records[qtype] != nil && len(label.Records[qtype]) > 0 {
  91. return label, qtype
  92. }
  93. }
  94. }
  95. }
  96. }
  97. return z.Labels[s], 0
  98. }