2022-08-18 01:16:43 +02:00
|
|
|
// 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 Enterprise struct corresponds to the data in the GeoIP2 Enterprise
|
|
|
|
// database.
|
|
|
|
type Enterprise struct {
|
|
|
|
Continent struct {
|
2023-07-13 22:34:10 +02:00
|
|
|
Names map[string]string `maxminddb:"names"`
|
2022-08-18 01:16:43 +02:00
|
|
|
Code string `maxminddb:"code"`
|
|
|
|
GeoNameID uint `maxminddb:"geoname_id"`
|
|
|
|
} `maxminddb:"continent"`
|
2023-07-13 22:34:10 +02:00
|
|
|
City struct {
|
|
|
|
Names map[string]string `maxminddb:"names"`
|
|
|
|
GeoNameID uint `maxminddb:"geoname_id"`
|
|
|
|
Confidence uint8 `maxminddb:"confidence"`
|
|
|
|
} `maxminddb:"city"`
|
2022-08-18 01:16:43 +02:00
|
|
|
Postal struct {
|
|
|
|
Code string `maxminddb:"code"`
|
|
|
|
Confidence uint8 `maxminddb:"confidence"`
|
|
|
|
} `maxminddb:"postal"`
|
2023-07-13 22:34:10 +02:00
|
|
|
Subdivisions []struct {
|
|
|
|
Names map[string]string `maxminddb:"names"`
|
|
|
|
IsoCode string `maxminddb:"iso_code"`
|
|
|
|
GeoNameID uint `maxminddb:"geoname_id"`
|
|
|
|
Confidence uint8 `maxminddb:"confidence"`
|
|
|
|
} `maxminddb:"subdivisions"`
|
|
|
|
RepresentedCountry struct {
|
|
|
|
Names map[string]string `maxminddb:"names"`
|
2022-08-18 01:16:43 +02:00
|
|
|
IsoCode string `maxminddb:"iso_code"`
|
2023-07-13 22:34:10 +02:00
|
|
|
Type string `maxminddb:"type"`
|
|
|
|
GeoNameID uint `maxminddb:"geoname_id"`
|
|
|
|
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
|
|
|
} `maxminddb:"represented_country"`
|
|
|
|
Country struct {
|
2022-08-18 01:16:43 +02:00
|
|
|
Names map[string]string `maxminddb:"names"`
|
2023-07-13 22:34:10 +02:00
|
|
|
IsoCode string `maxminddb:"iso_code"`
|
|
|
|
GeoNameID uint `maxminddb:"geoname_id"`
|
2022-08-18 01:16:43 +02:00
|
|
|
Confidence uint8 `maxminddb:"confidence"`
|
|
|
|
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
2023-07-13 22:34:10 +02:00
|
|
|
} `maxminddb:"country"`
|
|
|
|
RegisteredCountry struct {
|
|
|
|
Names map[string]string `maxminddb:"names"`
|
|
|
|
IsoCode string `maxminddb:"iso_code"`
|
2022-08-18 01:16:43 +02:00
|
|
|
GeoNameID uint `maxminddb:"geoname_id"`
|
2023-07-13 22:34:10 +02:00
|
|
|
Confidence uint8 `maxminddb:"confidence"`
|
2022-08-18 01:16:43 +02:00
|
|
|
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
2023-07-13 22:34:10 +02:00
|
|
|
} `maxminddb:"registered_country"`
|
2022-08-18 01:16:43 +02:00
|
|
|
Traits struct {
|
|
|
|
AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"`
|
|
|
|
ConnectionType string `maxminddb:"connection_type"`
|
|
|
|
Domain string `maxminddb:"domain"`
|
|
|
|
ISP string `maxminddb:"isp"`
|
|
|
|
MobileCountryCode string `maxminddb:"mobile_country_code"`
|
|
|
|
MobileNetworkCode string `maxminddb:"mobile_network_code"`
|
|
|
|
Organization string `maxminddb:"organization"`
|
|
|
|
UserType string `maxminddb:"user_type"`
|
2023-07-13 22:34:10 +02:00
|
|
|
AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
|
|
|
|
StaticIPScore float64 `maxminddb:"static_ip_score"`
|
|
|
|
IsAnonymousProxy bool `maxminddb:"is_anonymous_proxy"`
|
|
|
|
IsLegitimateProxy bool `maxminddb:"is_legitimate_proxy"`
|
|
|
|
IsSatelliteProvider bool `maxminddb:"is_satellite_provider"`
|
2022-08-18 01:16:43 +02:00
|
|
|
} `maxminddb:"traits"`
|
2023-07-13 22:34:10 +02:00
|
|
|
Location struct {
|
|
|
|
TimeZone string `maxminddb:"time_zone"`
|
|
|
|
Latitude float64 `maxminddb:"latitude"`
|
|
|
|
Longitude float64 `maxminddb:"longitude"`
|
|
|
|
MetroCode uint `maxminddb:"metro_code"`
|
|
|
|
AccuracyRadius uint16 `maxminddb:"accuracy_radius"`
|
|
|
|
} `maxminddb:"location"`
|
2022-08-18 01:16:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// The City struct corresponds to the data in the GeoIP2/GeoLite2 City
|
|
|
|
// databases.
|
|
|
|
type City struct {
|
|
|
|
City struct {
|
|
|
|
Names map[string]string `maxminddb:"names"`
|
2023-07-13 22:34:10 +02:00
|
|
|
GeoNameID uint `maxminddb:"geoname_id"`
|
2022-08-18 01:16:43 +02:00
|
|
|
} `maxminddb:"city"`
|
2023-07-13 22:34:10 +02:00
|
|
|
Postal struct {
|
|
|
|
Code string `maxminddb:"code"`
|
|
|
|
} `maxminddb:"postal"`
|
2022-08-18 01:16:43 +02:00
|
|
|
Continent struct {
|
2023-07-13 22:34:10 +02:00
|
|
|
Names map[string]string `maxminddb:"names"`
|
2022-08-18 01:16:43 +02:00
|
|
|
Code string `maxminddb:"code"`
|
|
|
|
GeoNameID uint `maxminddb:"geoname_id"`
|
|
|
|
} `maxminddb:"continent"`
|
2023-07-13 22:34:10 +02:00
|
|
|
Subdivisions []struct {
|
|
|
|
Names map[string]string `maxminddb:"names"`
|
|
|
|
IsoCode string `maxminddb:"iso_code"`
|
|
|
|
GeoNameID uint `maxminddb:"geoname_id"`
|
|
|
|
} `maxminddb:"subdivisions"`
|
|
|
|
RepresentedCountry struct {
|
|
|
|
Names map[string]string `maxminddb:"names"`
|
|
|
|
IsoCode string `maxminddb:"iso_code"`
|
|
|
|
Type string `maxminddb:"type"`
|
2022-08-18 01:16:43 +02:00
|
|
|
GeoNameID uint `maxminddb:"geoname_id"`
|
|
|
|
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
2023-07-13 22:34:10 +02:00
|
|
|
} `maxminddb:"represented_country"`
|
|
|
|
Country struct {
|
2022-08-18 01:16:43 +02:00
|
|
|
Names map[string]string `maxminddb:"names"`
|
2023-07-13 22:34:10 +02:00
|
|
|
IsoCode string `maxminddb:"iso_code"`
|
|
|
|
GeoNameID uint `maxminddb:"geoname_id"`
|
|
|
|
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
2022-08-18 01:16:43 +02:00
|
|
|
} `maxminddb:"country"`
|
2023-07-13 22:34:10 +02:00
|
|
|
RegisteredCountry struct {
|
|
|
|
Names map[string]string `maxminddb:"names"`
|
|
|
|
IsoCode string `maxminddb:"iso_code"`
|
|
|
|
GeoNameID uint `maxminddb:"geoname_id"`
|
|
|
|
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
|
|
|
} `maxminddb:"registered_country"`
|
2022-08-18 01:16:43 +02:00
|
|
|
Location struct {
|
2023-07-13 22:34:10 +02:00
|
|
|
TimeZone string `maxminddb:"time_zone"`
|
2022-08-18 01:16:43 +02:00
|
|
|
Latitude float64 `maxminddb:"latitude"`
|
|
|
|
Longitude float64 `maxminddb:"longitude"`
|
|
|
|
MetroCode uint `maxminddb:"metro_code"`
|
2023-07-13 22:34:10 +02:00
|
|
|
AccuracyRadius uint16 `maxminddb:"accuracy_radius"`
|
2022-08-18 01:16:43 +02:00
|
|
|
} `maxminddb:"location"`
|
|
|
|
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 {
|
2023-07-13 22:34:10 +02:00
|
|
|
Names map[string]string `maxminddb:"names"`
|
2022-08-18 01:16:43 +02:00
|
|
|
Code string `maxminddb:"code"`
|
|
|
|
GeoNameID uint `maxminddb:"geoname_id"`
|
|
|
|
} `maxminddb:"continent"`
|
|
|
|
Country struct {
|
2023-07-13 22:34:10 +02:00
|
|
|
Names map[string]string `maxminddb:"names"`
|
|
|
|
IsoCode string `maxminddb:"iso_code"`
|
2022-08-18 01:16:43 +02:00
|
|
|
GeoNameID uint `maxminddb:"geoname_id"`
|
|
|
|
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
|
|
|
} `maxminddb:"country"`
|
|
|
|
RegisteredCountry struct {
|
2023-07-13 22:34:10 +02:00
|
|
|
Names map[string]string `maxminddb:"names"`
|
|
|
|
IsoCode string `maxminddb:"iso_code"`
|
2022-08-18 01:16:43 +02:00
|
|
|
GeoNameID uint `maxminddb:"geoname_id"`
|
|
|
|
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
|
|
|
} `maxminddb:"registered_country"`
|
|
|
|
RepresentedCountry struct {
|
|
|
|
Names map[string]string `maxminddb:"names"`
|
2023-07-13 22:34:10 +02:00
|
|
|
IsoCode string `maxminddb:"iso_code"`
|
2022-08-18 01:16:43 +02:00
|
|
|
Type string `maxminddb:"type"`
|
2023-07-13 22:34:10 +02:00
|
|
|
GeoNameID uint `maxminddb:"geoname_id"`
|
|
|
|
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
|
2022-08-18 01:16:43 +02:00
|
|
|
} `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"`
|
|
|
|
IsResidentialProxy bool `maxminddb:"is_residential_proxy"`
|
|
|
|
IsTorExitNode bool `maxminddb:"is_tor_exit_node"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// The ASN struct corresponds to the data in the GeoLite2 ASN database.
|
|
|
|
type ASN struct {
|
|
|
|
AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"`
|
2023-07-13 22:34:10 +02:00
|
|
|
AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
|
2022-08-18 01:16:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
|
|
|
AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"`
|
|
|
|
ISP string `maxminddb:"isp"`
|
|
|
|
MobileCountryCode string `maxminddb:"mobile_country_code"`
|
|
|
|
MobileNetworkCode string `maxminddb:"mobile_network_code"`
|
|
|
|
Organization string `maxminddb:"organization"`
|
2023-07-13 22:34:10 +02:00
|
|
|
AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
|
2022-08-18 01:16:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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 %q 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
|
|
|
|
// used 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 "DBIP-ASN-Lite (compat=GeoLite2-ASN)",
|
|
|
|
"GeoLite2-ASN":
|
|
|
|
return isASN, nil
|
|
|
|
// We allow City lookups on Country for back compat
|
|
|
|
case "DBIP-City-Lite",
|
|
|
|
"DBIP-Country-Lite",
|
|
|
|
"DBIP-Country",
|
|
|
|
"DBIP-Location (compat=City)",
|
|
|
|
"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 "DBIP-ISP (compat=Enterprise)",
|
|
|
|
"DBIP-Location-ISP (compat=Enterprise)",
|
|
|
|
"GeoIP2-Enterprise":
|
|
|
|
return isEnterprise | isCity | isCountry, nil
|
2023-07-13 22:34:10 +02:00
|
|
|
case "GeoIP2-ISP", "GeoIP2-Precision-ISP":
|
2022-08-18 01:16:43 +02:00
|
|
|
return isISP | isASN, nil
|
|
|
|
default:
|
|
|
|
return 0, UnknownDatabaseTypeError{reader.Metadata.DatabaseType}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Enterprise takes an IP address as a net.IP struct and returns an Enterprise
|
|
|
|
// struct and/or an error. This is intended to be used with the GeoIP2
|
|
|
|
// Enterprise database.
|
|
|
|
func (r *Reader) Enterprise(ipAddress net.IP) (*Enterprise, error) {
|
|
|
|
if isEnterprise&r.databaseType == 0 {
|
|
|
|
return nil, InvalidMethodError{"Enterprise", r.Metadata().DatabaseType}
|
|
|
|
}
|
|
|
|
var enterprise Enterprise
|
|
|
|
err := r.mmdbReader.Lookup(ipAddress, &enterprise)
|
|
|
|
return &enterprise, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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()
|
|
|
|
}
|