Ver Fonte

Merge pull request #51 from coocood/master

Add resolver asn and ip targeting
Ask Bjørn Hansen há 11 anos atrás
pai
commit
c4a5ec7f10
7 ficheiros alterados com 98 adições e 24 exclusões
  1. 3 2
      .travis.yml
  2. 3 1
      dns/test.example.com.json
  3. 38 1
      geoip.go
  4. 44 17
      targeting.go
  5. 6 2
      targeting_test.go
  6. 3 0
      zones.go
  7. 1 1
      zones_test.go

+ 3 - 2
.travis.yml

@@ -1,12 +1,13 @@
 language: go
 go:
   - 1.1
-  - tip
+  - 1.2
 before_install:
   - sudo apt-get install libgeoip-dev bzr
 install:
   - mkdir -p $TRAVIS_BUILD_DIR/db
-  - curl -s http://geodns.bitnames.com/geoip/GeoLiteCity.dat.gz  | gzip -cd > $TRAVIS_BUILD_DIR/db/GeoIPCity.dat
+  - curl -s http://geodns.bitnames.com/geoip/GeoLiteCity.dat.gz | gzip -cd > $TRAVIS_BUILD_DIR/db/GeoIPCity.dat
+  - curl -s http://download.maxmind.com/download/geoip/database/asnum/GeoIPASNum.dat.gz | gzip -cd > $TRAVIS_BUILD_DIR/db/GeoIPASNum.dat
   - go get github.com/abh/dns
   - go get github.com/abh/geoip
   - go get launchpad.net/gocheck

+ 3 - 1
dns/test.example.com.json

@@ -5,7 +5,7 @@
     "stathat": true,
     "stathat_api": "abc-test"
   },
-  "targeting": "country continent @ regiongroup region",
+  "targeting": "country continent @ regiongroup region ip asn",
   "contact": "support.bitnames.com",
   "data" : {
     "":  {
@@ -46,6 +46,8 @@
       "ttl": "601"
     },
     "bar.no": { "a": [] },
+    "bar.as15169": { "a": [ ["192.168.1.4" ] ] },
+    "bar.[1.0.0.255]": { "a": [ ["192.168.1.3" ] ] },
     "0": {
       "a": [ [ "192.168.0.1", 10 ] ]
     },

+ 38 - 1
geoip.go

@@ -17,6 +17,10 @@ type GeoIP struct {
 	city         *geoip.GeoIP
 	cityLastLoad time.Time
 	hasCity      bool
+
+	asn         *geoip.GeoIP
+	hasAsn      bool
+	asnLastLoad time.Time
 }
 
 var geoIP = new(GeoIP)
@@ -61,6 +65,21 @@ func (g *GeoIP) GetCountryRegion(ip net.IP) (country, continent, regionGroup, re
 	return
 }
 
+func (g *GeoIP) GetASN(ip net.IP) (asn string, netmask int) {
+	if g.asn == nil {
+		log.Println("No asn database available")
+		return
+	}
+	name, netmask := g.asn.GetName(ip.String())
+	if len(name) > 0 {
+		index := strings.Index(name, " ")
+		if index > 0 {
+			asn = strings.ToLower(name[:index])
+		}
+	}
+	return
+}
+
 func (g *GeoIP) setDirectory() {
 	if len(Config.GeoIP.Directory) > 0 {
 		geoip.SetCustomDirectory(Config.GeoIP.Directory)
@@ -97,8 +116,26 @@ func (g *GeoIP) setupGeoIPCity() {
 		log.Printf("Could not open city GeoIP database: %s\n", err)
 		return
 	}
-	g.countryLastLoad = time.Now()
+	g.cityLastLoad = time.Now()
 	g.hasCity = true
 	g.city = gi
 
 }
+
+func (g *GeoIP) setupGeoIPASN() {
+	if g.asn != nil {
+		return
+	}
+
+	g.setDirectory()
+
+	gi, err := geoip.OpenType(geoip.GEOIP_ASNUM_EDITION)
+	if gi == nil || err != nil {
+		log.Printf("Could not open ASN GeoIP database: %s\n", err)
+		return
+	}
+	g.asnLastLoad = time.Now()
+	g.hasAsn = true
+	g.asn = gi
+
+}

+ 44 - 17
targeting.go

@@ -14,39 +14,56 @@ const (
 	TargetCountry
 	TargetRegionGroup
 	TargetRegion
+	TargetASN
+	TargetIP
 )
 
 func (t TargetOptions) GetTargets(ip net.IP) ([]string, int) {
 
 	targets := make([]string, 0)
 
-	var country, continent string
+	var country, continent, region, regionGroup, asn string
 	var netmask int
 
-	switch {
-	case t >= TargetRegionGroup:
-		var region, regionGroup string
+	if t&TargetASN > 0 {
+		asn, netmask = geoIP.GetASN(ip)
+	}
+
+	if t&TargetRegion > 0 || t&TargetRegionGroup > 0 {
 		country, continent, regionGroup, region, netmask = geoIP.GetCountryRegion(ip)
-		if t&TargetRegion > 0 && len(region) > 0 {
-			targets = append(targets, region)
-		}
-		if t&TargetRegionGroup > 0 && len(regionGroup) > 0 {
-			targets = append(targets, regionGroup)
-		}
 
-	case t >= TargetContinent:
+	} else if t&TargetCountry > 0 || t&TargetContinent > 0 {
 		country, continent, netmask = geoIP.GetCountry(ip)
 	}
 
-	if len(country) > 0 {
-		if t&TargetCountry > 0 {
-			targets = append(targets, country)
-		}
-		if t&TargetContinent > 0 && len(continent) > 0 {
-			targets = append(targets, continent)
+	if t&TargetIP > 0 {
+		ipStr := ip.String()
+		targets = append(targets, "["+ipStr+"]")
+		dotIndex := strings.LastIndex(ipStr, ".")
+		if dotIndex > 0 {
+			targets = append(targets, "["+ipStr[:dotIndex]+".0]")
 		}
 	}
 
+	if t&TargetASN > 0 && len(asn) > 0 {
+		targets = append(targets, asn)
+	}
+
+	if t&TargetRegion > 0 && len(region) > 0 {
+		targets = append(targets, region)
+	}
+	if t&TargetRegionGroup > 0 && len(regionGroup) > 0 {
+		targets = append(targets, regionGroup)
+	}
+
+	if t&TargetCountry > 0 && len(country) > 0 {
+		targets = append(targets, country)
+	}
+
+	if t&TargetContinent > 0 && len(continent) > 0 {
+		targets = append(targets, continent)
+	}
+
 	if t&TargetGlobal > 0 {
 		targets = append(targets, "@")
 	}
@@ -70,6 +87,12 @@ func (t TargetOptions) String() string {
 	if t&TargetRegion > 0 {
 		targets = append(targets, "region")
 	}
+	if t&TargetASN > 0 {
+		targets = append(targets, "asn")
+	}
+	if t&TargetIP > 0 {
+		targets = append(targets, "ip")
+	}
 	return strings.Join(targets, " ")
 }
 
@@ -88,6 +111,10 @@ func parseTargets(v string) (tgt TargetOptions, err error) {
 			x = TargetRegionGroup
 		case "region":
 			x = TargetRegion
+		case "asn":
+			x = TargetASN
+		case "ip":
+			x = TargetIP
 		default:
 			err = fmt.Errorf("Unknown targeting option '%s'", t)
 		}

+ 6 - 2
targeting_test.go

@@ -29,10 +29,10 @@ func (s *TargetingSuite) TestTargetParse(c *C) {
 	c.Check(str, Equals, "@ country")
 	c.Check(err.Error(), Equals, "Unknown targeting option 'foo'")
 
-	tgt, err = parseTargets("@ continent country")
+	tgt, err = parseTargets("@ continent country asn")
 	c.Assert(err, IsNil)
 	str = tgt.String()
-	c.Check(str, Equals, "@ continent country")
+	c.Check(str, Equals, "@ continent country asn")
 }
 func (s *TargetingSuite) TestGetTargets(c *C) {
 
@@ -40,6 +40,7 @@ func (s *TargetingSuite) TestGetTargets(c *C) {
 
 	geoIP.setupGeoIPCity()
 	geoIP.setupGeoIPCountry()
+	geoIP.setupGeoIPASN()
 
 	tgt, _ := parseTargets("@ continent country")
 	targets, _ := tgt.GetTargets(ip)
@@ -58,4 +59,7 @@ func (s *TargetingSuite) TestGetTargets(c *C) {
 	targets, _ = tgt.GetTargets(ip)
 	c.Check(targets, DeepEquals, []string{"us-ca", "us-west", "us", "north-america", "@"})
 
+	tgt, _ = parseTargets("@ continent regiongroup country region asn ip")
+	targets, _ = tgt.GetTargets(ip)
+	c.Check(targets, DeepEquals, []string{"207.171.7.51", "207.171.7.0", "as53582", "us-ca", "us-west", "us", "north-america", "@"})
 }

+ 3 - 0
zones.go

@@ -210,6 +210,9 @@ func readZoneFile(zoneName, fileName string) (zone *Zone, zerr error) {
 	case zone.Options.Targeting >= TargetContinent:
 		geoIP.setupGeoIPCountry()
 	}
+	if zone.Options.Targeting&TargetASN > 0 {
+		geoIP.setupGeoIPASN()
+	}
 
 	return zone, nil
 }

+ 1 - 1
zones_test.go

@@ -41,7 +41,7 @@ func (s *ConfigSuite) TestReadConfigs(c *C) {
 
 	c.Check(tz.Options.MaxHosts, Equals, 2)
 	c.Check(tz.Options.Contact, Equals, "support.bitnames.com")
-	c.Check(tz.Options.Targeting.String(), Equals, "@ continent country regiongroup region")
+	c.Check(tz.Options.Targeting.String(), Equals, "@ continent country regiongroup region asn ip")
 
 	// Got logging option
 	c.Check(tz.Logging.StatHat, Equals, true)