123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- // Package geoip2 provides an easy-to-use API for the MaxMind GeoIP2 and
- // GeoLite2 databases; this package does not support GeoIP Legacy databases.
- //
- // The structs provided by this package match the internal structure of
- // the data in the MaxMind databases.
- //
- // See github.com/oschwald/maxminddb-golang for more advanced used cases.
- package geoip2
- import (
- "fmt"
- "net"
- "github.com/oschwald/maxminddb-golang"
- )
- // The City struct corresponds to the data in the GeoIP2/GeoLite2 City
- // databases.
- type City struct {
- City struct {
- GeoNameID uint `maxminddb:"geoname_id"`
- Names map[string]string `maxminddb:"names"`
- } `maxminddb:"city"`
- Continent struct {
- Code string `maxminddb:"code"`
- GeoNameID uint `maxminddb:"geoname_id"`
- Names map[string]string `maxminddb:"names"`
- } `maxminddb:"continent"`
- Country struct {
- GeoNameID uint `maxminddb:"geoname_id"`
- IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
- IsoCode string `maxminddb:"iso_code"`
- Names map[string]string `maxminddb:"names"`
- } `maxminddb:"country"`
- Location struct {
- AccuracyRadius uint16 `maxminddb:"accuracy_radius"`
- Latitude float64 `maxminddb:"latitude"`
- Longitude float64 `maxminddb:"longitude"`
- MetroCode uint `maxminddb:"metro_code"`
- TimeZone string `maxminddb:"time_zone"`
- } `maxminddb:"location"`
- Postal struct {
- Code string `maxminddb:"code"`
- } `maxminddb:"postal"`
- RegisteredCountry struct {
- GeoNameID uint `maxminddb:"geoname_id"`
- IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
- IsoCode string `maxminddb:"iso_code"`
- Names map[string]string `maxminddb:"names"`
- } `maxminddb:"registered_country"`
- RepresentedCountry struct {
- GeoNameID uint `maxminddb:"geoname_id"`
- IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
- IsoCode string `maxminddb:"iso_code"`
- Names map[string]string `maxminddb:"names"`
- Type string `maxminddb:"type"`
- } `maxminddb:"represented_country"`
- Subdivisions []struct {
- GeoNameID uint `maxminddb:"geoname_id"`
- IsoCode string `maxminddb:"iso_code"`
- Names map[string]string `maxminddb:"names"`
- } `maxminddb:"subdivisions"`
- Traits struct {
- IsAnonymousProxy bool `maxminddb:"is_anonymous_proxy"`
- IsSatelliteProvider bool `maxminddb:"is_satellite_provider"`
- } `maxminddb:"traits"`
- }
- // The Country struct corresponds to the data in the GeoIP2/GeoLite2
- // Country databases.
- type Country struct {
- Continent struct {
- Code string `maxminddb:"code"`
- GeoNameID uint `maxminddb:"geoname_id"`
- Names map[string]string `maxminddb:"names"`
- } `maxminddb:"continent"`
- Country struct {
- GeoNameID uint `maxminddb:"geoname_id"`
- IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
- IsoCode string `maxminddb:"iso_code"`
- Names map[string]string `maxminddb:"names"`
- } `maxminddb:"country"`
- RegisteredCountry struct {
- GeoNameID uint `maxminddb:"geoname_id"`
- IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
- IsoCode string `maxminddb:"iso_code"`
- Names map[string]string `maxminddb:"names"`
- } `maxminddb:"registered_country"`
- RepresentedCountry struct {
- GeoNameID uint `maxminddb:"geoname_id"`
- IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
- IsoCode string `maxminddb:"iso_code"`
- Names map[string]string `maxminddb:"names"`
- Type string `maxminddb:"type"`
- } `maxminddb:"represented_country"`
- Traits struct {
- IsAnonymousProxy bool `maxminddb:"is_anonymous_proxy"`
- IsSatelliteProvider bool `maxminddb:"is_satellite_provider"`
- } `maxminddb:"traits"`
- }
- // The AnonymousIP struct corresponds to the data in the GeoIP2
- // Anonymous IP database.
- type AnonymousIP struct {
- IsAnonymous bool `maxminddb:"is_anonymous"`
- IsAnonymousVPN bool `maxminddb:"is_anonymous_vpn"`
- IsHostingProvider bool `maxminddb:"is_hosting_provider"`
- IsPublicProxy bool `maxminddb:"is_public_proxy"`
- IsTorExitNode bool `maxminddb:"is_tor_exit_node"`
- }
- // The ASN struct corresponds to the data in the GeoLite2 ASN database.
- type ASN struct {
- AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
- AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"`
- }
- // The ConnectionType struct corresponds to the data in the GeoIP2
- // Connection-Type database.
- type ConnectionType struct {
- ConnectionType string `maxminddb:"connection_type"`
- }
- // The Domain struct corresponds to the data in the GeoIP2 Domain database.
- type Domain struct {
- Domain string `maxminddb:"domain"`
- }
- // The ISP struct corresponds to the data in the GeoIP2 ISP database.
- type ISP struct {
- AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
- AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"`
- ISP string `maxminddb:"isp"`
- Organization string `maxminddb:"organization"`
- }
- type databaseType int
- const (
- isAnonymousIP = 1 << iota
- isASN
- isCity
- isConnectionType
- isCountry
- isDomain
- isEnterprise
- isISP
- )
- // Reader holds the maxminddb.Reader struct. It can be created using the
- // Open and FromBytes functions.
- type Reader struct {
- mmdbReader *maxminddb.Reader
- databaseType databaseType
- }
- // InvalidMethodError is returned when a lookup method is called on a
- // database that it does not support. For instance, calling the ISP method
- // on a City database.
- type InvalidMethodError struct {
- Method string
- DatabaseType string
- }
- func (e InvalidMethodError) Error() string {
- return fmt.Sprintf(`geoip2: the %s method does not support the %s database`,
- e.Method, e.DatabaseType)
- }
- // UnknownDatabaseTypeError is returned when an unknown database type is
- // opened.
- type UnknownDatabaseTypeError struct {
- DatabaseType string
- }
- func (e UnknownDatabaseTypeError) Error() string {
- return fmt.Sprintf(`geoip2: reader does not support the "%s" database type`,
- e.DatabaseType)
- }
- // Open takes a string path to a file and returns a Reader struct or an error.
- // The database file is opened using a memory map. Use the Close method on the
- // Reader object to return the resources to the system.
- func Open(file string) (*Reader, error) {
- reader, err := maxminddb.Open(file)
- if err != nil {
- return nil, err
- }
- dbType, err := getDBType(reader)
- return &Reader{reader, dbType}, err
- }
- // FromBytes takes a byte slice corresponding to a GeoIP2/GeoLite2 database
- // file and returns a Reader struct or an error. Note that the byte slice is
- // use directly; any modification of it after opening the database will result
- // in errors while reading from the database.
- func FromBytes(bytes []byte) (*Reader, error) {
- reader, err := maxminddb.FromBytes(bytes)
- if err != nil {
- return nil, err
- }
- dbType, err := getDBType(reader)
- return &Reader{reader, dbType}, err
- }
- func getDBType(reader *maxminddb.Reader) (databaseType, error) {
- switch reader.Metadata.DatabaseType {
- case "GeoIP2-Anonymous-IP":
- return isAnonymousIP, nil
- case "GeoLite2-ASN":
- return isASN, nil
- // We allow City lookups on Country for back compat
- case "GeoLite2-City",
- "GeoIP2-City",
- "GeoIP2-City-Africa",
- "GeoIP2-City-Asia-Pacific",
- "GeoIP2-City-Europe",
- "GeoIP2-City-North-America",
- "GeoIP2-City-South-America",
- "GeoIP2-Precision-City",
- "GeoLite2-Country",
- "GeoIP2-Country":
- return isCity | isCountry, nil
- case "GeoIP2-Connection-Type":
- return isConnectionType, nil
- case "GeoIP2-Domain":
- return isDomain, nil
- case "GeoIP2-Enterprise":
- return isEnterprise | isCity | isCountry, nil
- case "GeoIP2-ISP", "GeoIP2-Precision-ISP":
- return isISP, nil
- default:
- return 0, UnknownDatabaseTypeError{reader.Metadata.DatabaseType}
- }
- }
- // City takes an IP address as a net.IP struct and returns a City struct
- // and/or an error. Although this can be used with other databases, this
- // method generally should be used with the GeoIP2 or GeoLite2 City databases.
- func (r *Reader) City(ipAddress net.IP) (*City, error) {
- if isCity&r.databaseType == 0 {
- return nil, InvalidMethodError{"City", r.Metadata().DatabaseType}
- }
- var city City
- err := r.mmdbReader.Lookup(ipAddress, &city)
- return &city, err
- }
- // Country takes an IP address as a net.IP struct and returns a Country struct
- // and/or an error. Although this can be used with other databases, this
- // method generally should be used with the GeoIP2 or GeoLite2 Country
- // databases.
- func (r *Reader) Country(ipAddress net.IP) (*Country, error) {
- if isCountry&r.databaseType == 0 {
- return nil, InvalidMethodError{"Country", r.Metadata().DatabaseType}
- }
- var country Country
- err := r.mmdbReader.Lookup(ipAddress, &country)
- return &country, err
- }
- // AnonymousIP takes an IP address as a net.IP struct and returns a
- // AnonymousIP struct and/or an error.
- func (r *Reader) AnonymousIP(ipAddress net.IP) (*AnonymousIP, error) {
- if isAnonymousIP&r.databaseType == 0 {
- return nil, InvalidMethodError{"AnonymousIP", r.Metadata().DatabaseType}
- }
- var anonIP AnonymousIP
- err := r.mmdbReader.Lookup(ipAddress, &anonIP)
- return &anonIP, err
- }
- // ASN takes an IP address as a net.IP struct and returns a ASN struct and/or
- // an error
- func (r *Reader) ASN(ipAddress net.IP) (*ASN, error) {
- if isASN&r.databaseType == 0 {
- return nil, InvalidMethodError{"ASN", r.Metadata().DatabaseType}
- }
- var val ASN
- err := r.mmdbReader.Lookup(ipAddress, &val)
- return &val, err
- }
- // ConnectionType takes an IP address as a net.IP struct and returns a
- // ConnectionType struct and/or an error
- func (r *Reader) ConnectionType(ipAddress net.IP) (*ConnectionType, error) {
- if isConnectionType&r.databaseType == 0 {
- return nil, InvalidMethodError{"ConnectionType", r.Metadata().DatabaseType}
- }
- var val ConnectionType
- err := r.mmdbReader.Lookup(ipAddress, &val)
- return &val, err
- }
- // Domain takes an IP address as a net.IP struct and returns a
- // Domain struct and/or an error
- func (r *Reader) Domain(ipAddress net.IP) (*Domain, error) {
- if isDomain&r.databaseType == 0 {
- return nil, InvalidMethodError{"Domain", r.Metadata().DatabaseType}
- }
- var val Domain
- err := r.mmdbReader.Lookup(ipAddress, &val)
- return &val, err
- }
- // ISP takes an IP address as a net.IP struct and returns a ISP struct and/or
- // an error
- func (r *Reader) ISP(ipAddress net.IP) (*ISP, error) {
- if isISP&r.databaseType == 0 {
- return nil, InvalidMethodError{"ISP", r.Metadata().DatabaseType}
- }
- var val ISP
- err := r.mmdbReader.Lookup(ipAddress, &val)
- return &val, err
- }
- // Metadata takes no arguments and returns a struct containing metadata about
- // the MaxMind database in use by the Reader.
- func (r *Reader) Metadata() maxminddb.Metadata {
- return r.mmdbReader.Metadata
- }
- // Close unmaps the database file from virtual memory and returns the
- // resources to the system.
- func (r *Reader) Close() error {
- return r.mmdbReader.Close()
- }
|