├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── const.go ├── db ├── .gitignore └── download ├── ex └── geoip-demo.go ├── geoip.go ├── geoip_test.go └── test-db ├── GeoIP.dat ├── GeoIPCity.dat └── GeoIPRegion.dat /.gitignore: -------------------------------------------------------------------------------- 1 | geoip-demo 2 | *~ 3 | /db/GeoLiteCity.dat 4 | 5 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 6 | *.o 7 | *.a 8 | *.so 9 | 10 | # Folders 11 | _obj 12 | _test 13 | 14 | # Architecture specific extensions/prefixes 15 | *.[568vq] 16 | [568vq].out 17 | 18 | *.cgo1.go 19 | *.cgo2.c 20 | _cgo_defun.c 21 | _cgo_gotypes.go 22 | _cgo_export.* 23 | 24 | _testmain.go 25 | 26 | *.exe 27 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.3 5 | - 1.4 6 | - tip 7 | 8 | before_install: 9 | - sudo apt-get install libgeoip-dev bzr 10 | 11 | install: 12 | - mkdir -p $TRAVIS_BUILD_DIR/db 13 | - curl http://geodns.bitnames.com/geoip/GeoLiteCity.dat.gz | gzip -cd > $TRAVIS_BUILD_DIR/db/GeoLiteCity.dat 14 | - go get gopkg.in/check.v1 15 | 16 | script: 17 | - cd $TRAVIS_BUILD_DIR && go test -gocheck.v 18 | - go test -gocheck.v -gocheck.b -gocheck.btime=2s 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2012 Stiletto 2 | Copyright (C) 2012-2013 Ask Bjørn Hansen, Develooper LLC 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is furnished to do 9 | so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GeoIP API for Go 2 | 3 | This package wraps the [libgeoip C library](http://www.maxmind.com/app/c) for 4 | access from Go (golang). [![Build Status](https://travis-ci.org/abh/geoip.png?branch=master)](https://travis-ci.org/abh/geoip) 5 | 6 | Install with `go get github.com/abh/geoip` and use [godoc 7 | geoip](http://godoc.org/github.com/abh/geoip) to read the documentation. 8 | 9 | There's a small example in the `ex/` subdirectory. 10 | 11 | You can download the free [GeoLite 12 | Country](http://www.maxmind.com/app/geoip_country) database or you can 13 | [subscribe to updates](http://www.maxmind.com/app/country). 14 | 15 | ## Examples 16 | 17 | file := "/usr/share/GeoIP/GeoIP.dat" 18 | 19 | gi, err := geoip.Open(file) 20 | if err != nil { 21 | fmt.Printf("Could not open GeoIP database\n") 22 | } 23 | 24 | if gi != nil { 25 | country, netmask := gi.GetCountry("207.171.7.51") 26 | } 27 | 28 | // Setup gi6 by opening the optional IPv6 database and then... 29 | country := gi6.GetCountry_v6("2607:f238:2::5") 30 | fmt.Println(country) 31 | 32 | 33 | ## Contact 34 | 35 | Copyright 2012-2013 Ask Bjørn Hansen . The package 36 | is MIT licensed, see the LICENSE file. Originally based on example code 37 | from blasux@blasux.ru. 38 | -------------------------------------------------------------------------------- /const.go: -------------------------------------------------------------------------------- 1 | package geoip 2 | 3 | // GeoIPDBTypes enum in GeoIP.h 4 | const ( 5 | GEOIP_COUNTRY_EDITION = 1 6 | GEOIP_REGION_EDITION_REV0 = 7 7 | GEOIP_CITY_EDITION_REV0 = 6 8 | GEOIP_ORG_EDITION = 5 9 | GEOIP_ISP_EDITION = 4 10 | GEOIP_CITY_EDITION_REV1 = 2 11 | GEOIP_REGION_EDITION_REV1 = 3 12 | GEOIP_PROXY_EDITION = 8 13 | GEOIP_ASNUM_EDITION = 9 14 | GEOIP_NETSPEED_EDITION = 10 15 | GEOIP_DOMAIN_EDITION = 11 16 | GEOIP_COUNTRY_EDITION_V6 = 12 17 | GEOIP_LOCATIONA_EDITION = 13 18 | GEOIP_ACCURACYRADIUS_EDITION = 14 19 | GEOIP_CITYCONFIDENCE_EDITION = 15 20 | GEOIP_CITYCONFIDENCEDIST_EDITION = 16 21 | GEOIP_LARGE_COUNTRY_EDITION = 17 22 | GEOIP_LARGE_COUNTRY_EDITION_V6 = 18 23 | GEOIP_ASNUM_EDITION_V6 = 21 24 | GEOIP_ISP_EDITION_V6 = 22 25 | GEOIP_ORG_EDITION_V6 = 23 26 | GEOIP_DOMAIN_EDITION_V6 = 24 27 | GEOIP_LOCATIONA_EDITION_V6 = 25 28 | GEOIP_REGISTRAR_EDITION = 26 29 | GEOIP_REGISTRAR_EDITION_V6 = 27 30 | GEOIP_USERTYPE_EDITION = 28 31 | GEOIP_USERTYPE_EDITION_V6 = 29 32 | GEOIP_CITY_EDITION_REV1_V6 = 30 33 | GEOIP_CITY_EDITION_REV0_V6 = 31 34 | GEOIP_NETSPEED_EDITION_REV1 = 32 35 | GEOIP_NETSPEED_EDITION_REV1_V6 = 33 36 | ) 37 | 38 | // GeoIPOptions enum in GeoIP.h 39 | const ( 40 | GEOIP_STANDARD = 0 41 | GEOIP_MEMORY_CACHE = 1 42 | GEOIP_CHECK_CACHE = 2 43 | GEOIP_INDEX_CACHE = 4 44 | GEOIP_MMAP_CACHE = 8 45 | ) 46 | -------------------------------------------------------------------------------- /db/.gitignore: -------------------------------------------------------------------------------- 1 | *.dat.gz 2 | -------------------------------------------------------------------------------- /db/download: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use v5.12.0; 4 | use LWP::Simple qw(mirror); 5 | use File::Basename qw(basename); 6 | 7 | my @files = qw( 8 | http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz 9 | http://geolite.maxmind.com/download/geoip/database/GeoIPv6.dat.gz 10 | http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz 11 | http://geolite.maxmind.com/download/geoip/database/GeoLiteCityv6-beta/GeoLiteCityv6.dat.gz 12 | http://download.maxmind.com/download/geoip/database/asnum/GeoIPASNum.dat.gz 13 | http://download.maxmind.com/download/geoip/database/asnum/GeoIPASNumv6.dat.gz 14 | ); 15 | 16 | for my $url (@files) { 17 | my $file = basename($url); 18 | my ($dat_name) = ($file =~ m/(.*)\.gz/); 19 | my $rv = mirror($url, $file); 20 | if ($rv == 200) { 21 | system("gzip -cd $file > $dat_name"); 22 | } 23 | elsif ($rv == 304) { 24 | # already updated 25 | } 26 | else { 27 | say "$url:", $rv; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ex/geoip-demo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/abh/geoip" 7 | ) 8 | 9 | func main() { 10 | 11 | file6 := "../db/GeoIPv6.dat" 12 | 13 | gi6, err := geoip.Open(file6) 14 | if err != nil { 15 | fmt.Printf("Could not open GeoIPv6 database: %s\n", err) 16 | } 17 | 18 | gi, err := geoip.Open() 19 | if err != nil { 20 | fmt.Printf("Could not open GeoIP database: %s\n", err) 21 | } 22 | 23 | giasn, err := geoip.Open("../db/GeoIPASNum.dat") 24 | if err != nil { 25 | fmt.Printf("Could not open GeoIPASN database: %s\n", err) 26 | } 27 | 28 | giasn6, err := geoip.Open("../db/GeoIPASNumv6.dat") 29 | if err != nil { 30 | fmt.Printf("Could not open GeoIPASN database: %s\n", err) 31 | } 32 | 33 | if giasn != nil { 34 | ip := "207.171.7.51" 35 | asn, netmask := giasn.GetName(ip) 36 | fmt.Printf("%s: %s (netmask /%d)\n", ip, asn, netmask) 37 | 38 | } 39 | 40 | if gi != nil { 41 | test4(*gi, "207.171.7.51") 42 | test4(*gi, "127.0.0.1") 43 | } 44 | if gi6 != nil { 45 | ip := "2607:f238:2::5" 46 | country, netmask := gi6.GetCountry_v6(ip) 47 | var asn string 48 | var asn_netmask int 49 | if giasn6 != nil { 50 | asn, asn_netmask = giasn6.GetNameV6(ip) 51 | } 52 | fmt.Printf("%s: %s/%d %s/%d\n", ip, country, netmask, asn, asn_netmask) 53 | 54 | } 55 | 56 | } 57 | 58 | func test4(g *geoip.GeoIP, ip string) { 59 | test(func(s string) (string, int) { return g.GetCountry(s) }, ip) 60 | } 61 | 62 | func test(f func(string) (string, int), ip string) { 63 | country, netmask := f(ip) 64 | fmt.Printf("ip: %s is [%s] (netmask %d)\n", ip, country, netmask) 65 | 66 | } 67 | -------------------------------------------------------------------------------- /geoip.go: -------------------------------------------------------------------------------- 1 | /* Go (cgo) interface to libgeoip */ 2 | package geoip 3 | 4 | /* 5 | #cgo pkg-config: geoip 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | //typedef GeoIP* GeoIP_pnt 12 | */ 13 | import "C" 14 | 15 | import ( 16 | "fmt" 17 | "log" 18 | "os" 19 | "runtime" 20 | "sync" 21 | "unsafe" 22 | ) 23 | 24 | type GeoIP struct { 25 | db *C.GeoIP 26 | 27 | // We don't use GeoIP's thread-safe API calls, which means there is a 28 | // single global netmask variable that gets clobbered in the main 29 | // lookup routine. Any calls which have _GeoIP_seek_record_gl need to 30 | // be wrapped in this mutex. 31 | 32 | mu sync.Mutex 33 | } 34 | 35 | func (gi *GeoIP) free() { 36 | if gi == nil { 37 | return 38 | } 39 | if gi.db == nil { 40 | gi = nil 41 | return 42 | } 43 | C.GeoIP_delete(gi.db) 44 | gi = nil 45 | return 46 | } 47 | 48 | // Default convenience wrapper around OpenDb 49 | func Open(files ...string) (*GeoIP, error) { 50 | return OpenDb(files, GEOIP_MEMORY_CACHE) 51 | } 52 | 53 | // Opens a GeoIP database by filename with specified GeoIPOptions flag. 54 | // All formats supported by libgeoip are supported though there are only 55 | // functions to access some of the databases in this API. 56 | // If you don't pass a filename, it will try opening the database from 57 | // a list of common paths. 58 | func OpenDb(files []string, flag int) (*GeoIP, error) { 59 | if len(files) == 0 { 60 | files = []string{ 61 | "/usr/share/GeoIP/GeoIP.dat", // Linux default 62 | "/usr/share/local/GeoIP/GeoIP.dat", // source install? 63 | "/usr/local/share/GeoIP/GeoIP.dat", // FreeBSD 64 | "/opt/local/share/GeoIP/GeoIP.dat", // MacPorts 65 | "/usr/share/GeoIP/GeoIP.dat", // ArchLinux 66 | } 67 | } 68 | 69 | g := &GeoIP{} 70 | runtime.SetFinalizer(g, (*GeoIP).free) 71 | 72 | var err error 73 | 74 | for _, file := range files { 75 | 76 | // libgeoip prints errors if it can't open the file, so check first 77 | if _, err := os.Stat(file); err != nil { 78 | if os.IsExist(err) { 79 | log.Println(err) 80 | } 81 | continue 82 | } 83 | 84 | cbase := C.CString(file) 85 | defer C.free(unsafe.Pointer(cbase)) 86 | 87 | g.db, err = C.GeoIP_open(cbase, C.int(flag)) 88 | if g.db != nil && err != nil { 89 | break 90 | } 91 | } 92 | if err != nil { 93 | return nil, fmt.Errorf("Error opening GeoIP database (%s): %s", files, err) 94 | } 95 | 96 | if g.db == nil { 97 | return nil, fmt.Errorf("Didn't open GeoIP database (%s)", files) 98 | } 99 | 100 | C.GeoIP_set_charset(g.db, C.GEOIP_CHARSET_UTF8) 101 | return g, nil 102 | } 103 | 104 | // SetCustomDirectory sets the default location for the GeoIP .dat files used when 105 | // calling OpenType() 106 | func SetCustomDirectory(dir string) { 107 | cdir := C.CString(dir) 108 | // GeoIP doesn't copy the string, so don't free it when we're done here. 109 | // defer C.free(unsafe.Pointer(cdir)) 110 | C.GeoIP_setup_custom_directory(cdir) 111 | } 112 | 113 | // OpenType opens a specified GeoIP database type in the default location with the 114 | // specified GeoIPOptions flag. Constants are defined for each database type 115 | // (for example GEOIP_COUNTRY_EDITION). 116 | func OpenTypeFlag(dbType int, flag int) (*GeoIP, error) { 117 | g := &GeoIP{} 118 | runtime.SetFinalizer(g, (*GeoIP).free) 119 | 120 | var err error 121 | 122 | g.db, err = C.GeoIP_open_type(C.int(dbType), C.int(flag)) 123 | if err != nil { 124 | return nil, fmt.Errorf("Error opening GeoIP database (%d): %s", dbType, err) 125 | } 126 | 127 | if g.db == nil { 128 | return nil, fmt.Errorf("Didn't open GeoIP database (%d)", dbType) 129 | } 130 | 131 | C.GeoIP_set_charset(g.db, C.GEOIP_CHARSET_UTF8) 132 | 133 | return g, nil 134 | } 135 | 136 | // OpenType opens a specified GeoIP database type in the default location 137 | // and the 'memory cache' flag. Use OpenTypeFlag() to specify flag. 138 | func OpenType(dbType int) (*GeoIP, error) { 139 | return OpenTypeFlag(dbType, GEOIP_MEMORY_CACHE) 140 | } 141 | 142 | // Takes an IPv4 address string and returns the organization name for that IP. 143 | // Requires the GeoIP organization database. 144 | func (gi *GeoIP) GetOrg(ip string) string { 145 | name, _ := gi.GetName(ip) 146 | return name 147 | } 148 | 149 | // Works on the ASN, Netspeed, Organization and probably other 150 | // databases, takes and IP string and returns a "name" and the 151 | // netmask. 152 | func (gi *GeoIP) GetName(ip string) (name string, netmask int) { 153 | if gi.db == nil { 154 | return 155 | } 156 | 157 | gi.mu.Lock() 158 | defer gi.mu.Unlock() 159 | 160 | cip := C.CString(ip) 161 | defer C.free(unsafe.Pointer(cip)) 162 | cname := C.GeoIP_name_by_addr(gi.db, cip) 163 | 164 | if cname != nil { 165 | name = C.GoString(cname) 166 | defer C.free(unsafe.Pointer(cname)) 167 | netmask = int(C.GeoIP_last_netmask(gi.db)) 168 | return 169 | } 170 | return 171 | } 172 | 173 | type GeoIPRecord struct { 174 | CountryCode string 175 | CountryCode3 string 176 | CountryName string 177 | Region string 178 | City string 179 | PostalCode string 180 | Latitude float32 181 | Longitude float32 182 | MetroCode int 183 | AreaCode int 184 | CharSet int 185 | ContinentCode string 186 | } 187 | 188 | // Returns the "City Record" for an IP address. Requires the GeoCity(Lite) 189 | // database - http://www.maxmind.com/en/city 190 | func (gi *GeoIP) GetRecord(ip string) *GeoIPRecord { 191 | if gi.db == nil { 192 | return nil 193 | } 194 | 195 | cip := C.CString(ip) 196 | defer C.free(unsafe.Pointer(cip)) 197 | 198 | gi.mu.Lock() 199 | record := C.GeoIP_record_by_addr(gi.db, cip) 200 | gi.mu.Unlock() 201 | 202 | if record == nil { 203 | return nil 204 | } 205 | // defer C.free(unsafe.Pointer(record)) 206 | defer C.GeoIPRecord_delete(record) 207 | rec := new(GeoIPRecord) 208 | rec.CountryCode = C.GoString(record.country_code) 209 | rec.CountryCode3 = C.GoString(record.country_code3) 210 | rec.CountryName = C.GoString(record.country_name) 211 | rec.Region = C.GoString(record.region) 212 | rec.City = C.GoString(record.city) 213 | rec.PostalCode = C.GoString(record.postal_code) 214 | rec.Latitude = float32(record.latitude) 215 | rec.Longitude = float32(record.longitude) 216 | rec.CharSet = int(record.charset) 217 | rec.ContinentCode = C.GoString(record.continent_code) 218 | 219 | if gi.db.databaseType != C.GEOIP_CITY_EDITION_REV0 { 220 | /* DIRTY HACK BELOW: 221 | The GeoIPRecord struct in GeoIPCity.h contains an int32 union of metro_code and dma_code. 222 | The union is unnamed, so cgo names it anon0 and assumes it's a 4-byte array. 223 | */ 224 | union_int := (*int32)(unsafe.Pointer(&record.anon0)) 225 | rec.MetroCode = int(*union_int) 226 | rec.AreaCode = int(record.area_code) 227 | } 228 | 229 | return rec 230 | } 231 | 232 | // Returns the country code and region code for an IP address. Requires 233 | // the GeoIP Region database. 234 | func (gi *GeoIP) GetRegion(ip string) (string, string) { 235 | if gi.db == nil { 236 | return "", "" 237 | } 238 | 239 | cip := C.CString(ip) 240 | defer C.free(unsafe.Pointer(cip)) 241 | 242 | gi.mu.Lock() 243 | region := C.GeoIP_region_by_addr(gi.db, cip) 244 | gi.mu.Unlock() 245 | 246 | if region == nil { 247 | return "", "" 248 | } 249 | 250 | countryCode := C.GoString(®ion.country_code[0]) 251 | regionCode := C.GoString(®ion.region[0]) 252 | defer C.free(unsafe.Pointer(region)) 253 | 254 | return countryCode, regionCode 255 | } 256 | 257 | // Returns the region name given a country code and region code 258 | func GetRegionName(countryCode, regionCode string) string { 259 | 260 | cc := C.CString(countryCode) 261 | defer C.free(unsafe.Pointer(cc)) 262 | 263 | rc := C.CString(regionCode) 264 | defer C.free(unsafe.Pointer(rc)) 265 | 266 | region := C.GeoIP_region_name_by_code(cc, rc) 267 | if region == nil { 268 | return "" 269 | } 270 | 271 | // it's a static string constant, don't free this 272 | regionName := C.GoString(region) 273 | 274 | return regionName 275 | } 276 | 277 | // Same as GetName() but for IPv6 addresses. 278 | func (gi *GeoIP) GetNameV6(ip string) (name string, netmask int) { 279 | if gi.db == nil { 280 | return 281 | } 282 | 283 | gi.mu.Lock() 284 | defer gi.mu.Unlock() 285 | 286 | cip := C.CString(ip) 287 | defer C.free(unsafe.Pointer(cip)) 288 | cname := C.GeoIP_name_by_addr_v6(gi.db, cip) 289 | 290 | if cname != nil { 291 | name = C.GoString(cname) 292 | defer C.free(unsafe.Pointer(cname)) 293 | netmask = int(C.GeoIP_last_netmask(gi.db)) 294 | return 295 | } 296 | return 297 | } 298 | 299 | // Takes an IPv4 address string and returns the country code for that IP 300 | // and the netmask for that IP range. 301 | func (gi *GeoIP) GetCountry(ip string) (cc string, netmask int) { 302 | if gi.db == nil { 303 | return 304 | } 305 | 306 | gi.mu.Lock() 307 | defer gi.mu.Unlock() 308 | 309 | cip := C.CString(ip) 310 | defer C.free(unsafe.Pointer(cip)) 311 | ccountry := C.GeoIP_country_code_by_addr(gi.db, cip) 312 | 313 | if ccountry != nil { 314 | cc = C.GoString(ccountry) 315 | netmask = int(C.GeoIP_last_netmask(gi.db)) 316 | return 317 | } 318 | return 319 | } 320 | 321 | // GetCountry_v6 works the same as GetCountry except for IPv6 addresses, be sure to 322 | // load a database with IPv6 data to get any results. 323 | func (gi *GeoIP) GetCountry_v6(ip string) (cc string, netmask int) { 324 | if gi.db == nil { 325 | return 326 | } 327 | 328 | gi.mu.Lock() 329 | defer gi.mu.Unlock() 330 | 331 | cip := C.CString(ip) 332 | defer C.free(unsafe.Pointer(cip)) 333 | ccountry := C.GeoIP_country_code_by_addr_v6(gi.db, cip) 334 | if ccountry != nil { 335 | cc = C.GoString(ccountry) 336 | netmask = int(C.GeoIP_last_netmask(gi.db)) 337 | return 338 | } 339 | return 340 | } 341 | -------------------------------------------------------------------------------- /geoip_test.go: -------------------------------------------------------------------------------- 1 | package geoip 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | . "gopkg.in/check.v1" 8 | ) 9 | 10 | // Hook up gocheck into the gotest runner. 11 | func Test(t *testing.T) { TestingT(t) } 12 | 13 | type GeoIPSuite struct { 14 | } 15 | 16 | var _ = Suite(&GeoIPSuite{}) 17 | 18 | func (s *GeoIPSuite) Testv4(c *C) { 19 | gi, err := Open() 20 | if gi == nil || err != nil { 21 | fmt.Printf("Could not open GeoIP database: %s\n", err) 22 | return 23 | } 24 | 25 | c.Check(gi, NotNil) 26 | 27 | country, netmask := gi.GetCountry("64.17.254.216") 28 | c.Check(country, Equals, "US") 29 | c.Check(netmask, Equals, 17) 30 | 31 | country, netmask = gi.GetCountry("222.230.136.0") 32 | c.Check(country, Equals, "JP") 33 | c.Check(netmask, Equals, 16) 34 | } 35 | 36 | func (s *GeoIPSuite) TestOpenType(c *C) { 37 | 38 | SetCustomDirectory("test-db") 39 | 40 | // Open Country database 41 | gi, err := OpenType(GEOIP_COUNTRY_EDITION) 42 | c.Check(err, IsNil) 43 | c.Assert(gi, NotNil) 44 | country, _ := gi.GetCountry("81.2.69.160") 45 | c.Check(country, Equals, "GB") 46 | } 47 | 48 | func (s *GeoIPSuite) Benchmark_GetCountry(c *C) { 49 | gi, err := Open() 50 | if gi == nil || err != nil { 51 | fmt.Printf("Could not open GeoIP database: %s\n", err) 52 | return 53 | } 54 | 55 | for i := 0; i < c.N; i++ { 56 | gi.GetCountry("207.171.7.51") 57 | } 58 | } 59 | 60 | func (s *GeoIPSuite) Testv4Record(c *C) { 61 | gi, err := Open("test-db/GeoIPCity.dat") 62 | if gi == nil || err != nil { 63 | fmt.Printf("Could not open GeoIP database: %s\n", err) 64 | return 65 | } 66 | 67 | c.Check(gi, NotNil) 68 | 69 | record := gi.GetRecord("66.92.181.240") 70 | c.Assert(record, NotNil) 71 | c.Check( 72 | *record, 73 | Equals, 74 | GeoIPRecord{ 75 | CountryCode: "US", 76 | CountryCode3: "USA", 77 | CountryName: "United States", 78 | Region: "CA", 79 | City: "Fremont", 80 | PostalCode: "94538", 81 | Latitude: 37.5079, 82 | Longitude: -121.96, 83 | AreaCode: 510, 84 | MetroCode: 807, 85 | CharSet: 1, 86 | ContinentCode: "NA", 87 | }, 88 | ) 89 | } 90 | 91 | func (s *GeoIPSuite) Benchmark_GetRecord(c *C) { 92 | 93 | gi, err := Open("db/GeoLiteCity.dat") 94 | if gi == nil || err != nil { 95 | fmt.Printf("Could not open GeoIP database: %s\n", err) 96 | return 97 | } 98 | 99 | for i := 0; i < c.N; i++ { 100 | record := gi.GetRecord("207.171.7.51") 101 | if record == nil { 102 | panic("") 103 | } 104 | } 105 | } 106 | 107 | func (s *GeoIPSuite) Testv4Region(c *C) { 108 | gi, err := Open("test-db/GeoIPRegion.dat") 109 | if gi == nil || err != nil { 110 | fmt.Printf("Could not open GeoIP database: %s\n", err) 111 | return 112 | } 113 | 114 | country, region := gi.GetRegion("64.17.254.223") 115 | c.Check(country, Equals, "US") 116 | c.Check(region, Equals, "CA") 117 | } 118 | 119 | func (s *GeoIPSuite) TestRegionName(c *C) { 120 | regionName := GetRegionName("NL", "07") 121 | c.Check(regionName, Equals, "Noord-Holland") 122 | regionName = GetRegionName("CA", "ON") 123 | c.Check(regionName, Equals, "Ontario") 124 | } 125 | -------------------------------------------------------------------------------- /test-db/GeoIP.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abh/geoip/07cea4480daa3f28edd2856f2a0490fbe83842eb/test-db/GeoIP.dat -------------------------------------------------------------------------------- /test-db/GeoIPCity.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abh/geoip/07cea4480daa3f28edd2856f2a0490fbe83842eb/test-db/GeoIPCity.dat -------------------------------------------------------------------------------- /test-db/GeoIPRegion.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abh/geoip/07cea4480daa3f28edd2856f2a0490fbe83842eb/test-db/GeoIPRegion.dat --------------------------------------------------------------------------------