Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 91 additions & 55 deletions geoip.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
package geoip

/*
#cgo pkg-config: geoip
#cgo pkg-config: geoip
#include <stdio.h>
#include <errno.h>
#include <GeoIP.h>
Expand Down Expand Up @@ -139,37 +139,6 @@ func OpenType(dbType int) (*GeoIP, error) {
return OpenTypeFlag(dbType, GEOIP_MEMORY_CACHE)
}

// Takes an IPv4 address string and returns the organization name for that IP.
// Requires the GeoIP organization database.
func (gi *GeoIP) GetOrg(ip string) string {
name, _ := gi.GetName(ip)
return name
}

// Works on the ASN, Netspeed, Organization and probably other
// databases, takes and IP string and returns a "name" and the
// netmask.
func (gi *GeoIP) GetName(ip string) (name string, netmask int) {
if gi.db == nil {
return
}

gi.mu.Lock()
defer gi.mu.Unlock()

cip := C.CString(ip)
defer C.free(unsafe.Pointer(cip))
cname := C.GeoIP_name_by_addr(gi.db, cip)

if cname != nil {
name = C.GoString(cname)
defer C.free(unsafe.Pointer(cname))
netmask = int(C.GeoIP_last_netmask(gi.db))
return
}
return
}

type GeoIPRecord struct {
CountryCode string
CountryCode3 string
Expand All @@ -185,25 +154,8 @@ type GeoIPRecord struct {
ContinentCode string
}

// Returns the "City Record" for an IP address. Requires the GeoCity(Lite)
// database - http://www.maxmind.com/en/city
func (gi *GeoIP) GetRecord(ip string) *GeoIPRecord {
if gi.db == nil {
return nil
}

cip := C.CString(ip)
defer C.free(unsafe.Pointer(cip))

gi.mu.Lock()
record := C.GeoIP_record_by_addr(gi.db, cip)
gi.mu.Unlock()

if record == nil {
return nil
}
// defer C.free(unsafe.Pointer(record))
defer C.GeoIPRecord_delete(record)
// Populate GeoIPRecord
func populateGeoIPRecords(databaseType C.char, record *C.GeoIPRecord) *GeoIPRecord {
rec := new(GeoIPRecord)
rec.CountryCode = C.GoString(record.country_code)
rec.CountryCode3 = C.GoString(record.country_code3)
Expand All @@ -216,7 +168,7 @@ func (gi *GeoIP) GetRecord(ip string) *GeoIPRecord {
rec.CharSet = int(record.charset)
rec.ContinentCode = C.GoString(record.continent_code)

if gi.db.databaseType != C.GEOIP_CITY_EDITION_REV0 {
if databaseType != C.GEOIP_CITY_EDITION_REV0 {
/* DIRTY HACK BELOW:
The GeoIPRecord struct in GeoIPCity.h contains an int32 union of metro_code and dma_code.
The union is unnamed, so cgo names it anon0 and assumes it's a 4-byte array.
Expand All @@ -225,10 +177,52 @@ func (gi *GeoIP) GetRecord(ip string) *GeoIPRecord {
rec.MetroCode = int(*union_int)
rec.AreaCode = int(record.area_code)
}

return rec
}

// Returns the "City Record" for an IPv4 address. Requires the GeoCity(Lite)
// database - http://www.maxmind.com/en/city
func (gi *GeoIP) GetRecord(ip string) *GeoIPRecord {
if gi.db == nil {
return nil
}

cip := C.CString(ip)
defer C.free(unsafe.Pointer(cip))

gi.mu.Lock()
record := C.GeoIP_record_by_addr(gi.db, cip)
gi.mu.Unlock()

if record == nil {
return nil
}
defer C.GeoIPRecord_delete(record)

return populateGeoIPRecords(gi.db.databaseType, record)
}

// Same as GetRecord() but for IPv6.
func (gi *GeoIP) GetRecordV6(ip string) *GeoIPRecord {
if gi.db == nil {
return nil
}

cip := C.CString(ip)
defer C.free(unsafe.Pointer(cip))

gi.mu.Lock()
record := C.GeoIP_record_by_addr_v6(gi.db, cip)
gi.mu.Unlock()

if record == nil {
return nil
}
defer C.GeoIPRecord_delete(record)

return populateGeoIPRecords(gi.db.databaseType, record)
}

// Returns the country code and region code for an IP address. Requires
// the GeoIP Region database.
func (gi *GeoIP) GetRegion(ip string) (string, string) {
Expand Down Expand Up @@ -274,6 +268,30 @@ func GetRegionName(countryCode, regionCode string) string {
return regionName
}

// Works on the ASN, Netspeed, Organization and probably other
// databases, takes and IP string and returns a "name" and the
// netmask.
func (gi *GeoIP) GetName(ip string) (name string, netmask int) {
if gi.db == nil {
return
}

gi.mu.Lock()
defer gi.mu.Unlock()

cip := C.CString(ip)
defer C.free(unsafe.Pointer(cip))
cname := C.GeoIP_name_by_addr(gi.db, cip)

if cname != nil {
name = C.GoString(cname)
defer C.free(unsafe.Pointer(cname))
netmask = int(C.GeoIP_last_netmask(gi.db))
return
}
return
}

// Same as GetName() but for IPv6 addresses.
func (gi *GeoIP) GetNameV6(ip string) (name string, netmask int) {
if gi.db == nil {
Expand All @@ -296,6 +314,19 @@ func (gi *GeoIP) GetNameV6(ip string) (name string, netmask int) {
return
}

// Takes an IPv4 address string and returns the organization name for that IP.
// Requires the GeoIP organization database.
func (gi *GeoIP) GetOrg(ip string) string {
name, _ := gi.GetName(ip)
return name
}

// Same as GetOrg() but for IPv6.
func (gi *GeoIP) GetOrgV6(ip string) string {
name, _ := gi.GetNameV6(ip)
return name
}

// Takes an IPv4 address string and returns the country code for that IP
// and the netmask for that IP range.
func (gi *GeoIP) GetCountry(ip string) (cc string, netmask int) {
Expand All @@ -318,9 +349,9 @@ func (gi *GeoIP) GetCountry(ip string) (cc string, netmask int) {
return
}

// GetCountry_v6 works the same as GetCountry except for IPv6 addresses, be sure to
// GetCountryV6 works the same as GetCountry except for IPv6 addresses, be sure to
// load a database with IPv6 data to get any results.
func (gi *GeoIP) GetCountry_v6(ip string) (cc string, netmask int) {
func (gi *GeoIP) GetCountryV6(ip string) (cc string, netmask int) {
if gi.db == nil {
return
}
Expand All @@ -338,3 +369,8 @@ func (gi *GeoIP) GetCountry_v6(ip string) (cc string, netmask int) {
}
return
}

// Deprecated, use GetCountryV6() instead.
func (gi *GeoIP) GetCountry_v6(ip string) (cc string, netmask int) {
return gi.GetCountryV6(ip)
}