targeting.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. package targeting
  2. import (
  3. "fmt"
  4. "log"
  5. "net"
  6. "strings"
  7. "github.com/abh/geodns/targeting/geo"
  8. )
  9. type TargetOptions int
  10. const (
  11. TargetGlobal = 1 << iota
  12. TargetContinent
  13. TargetCountry
  14. TargetRegionGroup
  15. TargetRegion
  16. TargetASN
  17. TargetIP
  18. )
  19. var cidr48Mask net.IPMask
  20. func init() {
  21. cidr48Mask = net.CIDRMask(48, 128)
  22. }
  23. var g geo.Provider
  24. // Setup sets the global geo provider
  25. func Setup(gn geo.Provider) error {
  26. g = gn
  27. return nil
  28. }
  29. // Geo returns the global geo provider
  30. func Geo() geo.Provider {
  31. return g
  32. }
  33. func (t TargetOptions) getGeoTargets(ip net.IP, hasClosest bool) ([]string, int, *geo.Location) {
  34. targets := make([]string, 0)
  35. if t&TargetASN > 0 {
  36. asn, _, err := g.GetASN(ip)
  37. if err != nil {
  38. log.Printf("GetASN error: %s", err)
  39. }
  40. if len(asn) > 0 {
  41. targets = append(targets, asn)
  42. }
  43. }
  44. var country, continent, region, regionGroup string
  45. var netmask int
  46. var location *geo.Location
  47. if t&TargetRegion > 0 || t&TargetRegionGroup > 0 || hasClosest {
  48. var err error
  49. location, err = g.GetLocation(ip)
  50. if location == nil || err != nil {
  51. return targets, 0, nil
  52. }
  53. // log.Printf("Location for '%s' (err: %s): %+v", ip, err, location)
  54. country = location.Country
  55. continent = location.Continent
  56. region = location.Region
  57. regionGroup = location.RegionGroup
  58. // continent, regionGroup, region, netmask,
  59. } else if t&TargetCountry > 0 || t&TargetContinent > 0 {
  60. country, continent, netmask = g.GetCountry(ip)
  61. }
  62. if t&TargetRegion > 0 && len(region) > 0 {
  63. targets = append(targets, region)
  64. }
  65. if t&TargetRegionGroup > 0 && len(regionGroup) > 0 {
  66. targets = append(targets, regionGroup)
  67. }
  68. if t&TargetCountry > 0 && len(country) > 0 {
  69. targets = append(targets, country)
  70. }
  71. if t&TargetContinent > 0 && len(continent) > 0 {
  72. targets = append(targets, continent)
  73. }
  74. return targets, netmask, location
  75. }
  76. func (t TargetOptions) GetTargets(ip net.IP, hasClosest bool) ([]string, int, *geo.Location) {
  77. targets := make([]string, 0)
  78. var location *geo.Location
  79. var netmask int
  80. if t&TargetIP > 0 {
  81. ipStr := ip.String()
  82. targets = append(targets, "["+ipStr+"]")
  83. ip4 := ip.To4()
  84. if ip4 != nil {
  85. if ip4[3] != 0 {
  86. ip4[3] = 0
  87. targets = append(targets, "["+ip4.String()+"]")
  88. }
  89. } else {
  90. // v6 address, also target the /48 address
  91. ip48 := ip.Mask(cidr48Mask)
  92. targets = append(targets, "["+ip48.String()+"]")
  93. }
  94. }
  95. if g != nil {
  96. var geotargets []string
  97. geotargets, netmask, location = t.getGeoTargets(ip, hasClosest)
  98. targets = append(targets, geotargets...)
  99. }
  100. if t&TargetGlobal > 0 {
  101. targets = append(targets, "@")
  102. }
  103. return targets, netmask, location
  104. }
  105. func (t TargetOptions) String() string {
  106. targets := make([]string, 0)
  107. if t&TargetGlobal > 0 {
  108. targets = append(targets, "@")
  109. }
  110. if t&TargetContinent > 0 {
  111. targets = append(targets, "continent")
  112. }
  113. if t&TargetCountry > 0 {
  114. targets = append(targets, "country")
  115. }
  116. if t&TargetRegionGroup > 0 {
  117. targets = append(targets, "regiongroup")
  118. }
  119. if t&TargetRegion > 0 {
  120. targets = append(targets, "region")
  121. }
  122. if t&TargetASN > 0 {
  123. targets = append(targets, "asn")
  124. }
  125. if t&TargetIP > 0 {
  126. targets = append(targets, "ip")
  127. }
  128. return strings.Join(targets, " ")
  129. }
  130. func ParseTargets(v string) (tgt TargetOptions, err error) {
  131. targets := strings.Split(v, " ")
  132. for _, t := range targets {
  133. var x TargetOptions
  134. switch t {
  135. case "@":
  136. x = TargetGlobal
  137. case "country":
  138. x = TargetCountry
  139. case "continent":
  140. x = TargetContinent
  141. case "regiongroup":
  142. x = TargetRegionGroup
  143. case "region":
  144. x = TargetRegion
  145. case "asn":
  146. x = TargetASN
  147. case "ip":
  148. x = TargetIP
  149. default:
  150. err = fmt.Errorf("Unknown targeting option '%s'", t)
  151. }
  152. tgt = tgt | x
  153. }
  154. return
  155. }