Documentation
¶
Overview ¶
Package maxminddb provides a reader for the MaxMind DB file format.
This package provides an API for reading MaxMind GeoIP2 and GeoLite2 databases in the MaxMind DB file format (.mmdb files). The API is designed to be simple to use while providing high performance for IP geolocation lookups and related data.
Basic Usage ¶
The most common use case is looking up geolocation data for an IP address:
db, err := maxminddb.Open("GeoLite2-City.mmdb") if err != nil { log.Fatal(err) } defer db.Close() ip, err := netip.ParseAddr("81.2.69.142") if err != nil { log.Fatal(err) } var record struct { Country struct { ISOCode string `maxminddb:"iso_code"` Names map[string]string `maxminddb:"names"` } `maxminddb:"country"` City struct { Names map[string]string `maxminddb:"names"` } `maxminddb:"city"` } err = db.Lookup(ip).Decode(&record) if err != nil { log.Fatal(err) } fmt.Printf("Country: %s\n", record.Country.Names["en"]) fmt.Printf("City: %s\n", record.City.Names["en"])
Database Types ¶
This library supports all MaxMind database types:
- GeoLite2/GeoIP2 City: Comprehensive location data including city, country, subdivisions
- GeoLite2/GeoIP2 Country: Country-level geolocation data
- GeoLite2 ASN: Autonomous System Number and organization data
- GeoIP2 Anonymous IP: Anonymous network and proxy detection
- GeoIP2 Enterprise: Enhanced City data with additional business fields
- GeoIP2 ISP: Internet service provider information
- GeoIP2 Domain: Second-level domain data
- GeoIP2 Connection Type: Connection type identification
Performance ¶
For maximum performance in high-throughput applications, consider:
- Using custom struct types that only include the fields you need
- Implementing the Unmarshaler interface for custom decoding
- Reusing the Reader instance across multiple goroutines (it's thread-safe)
Custom Unmarshaling ¶
For custom decoding logic, you can implement the mmdbdata.Unmarshaler interface, similar to how encoding/json's json.Unmarshaler works. Types implementing this interface will automatically use custom decoding logic when used with Reader.Lookup:
type FastCity struct { CountryISO string CityName string } func (c *FastCity) UnmarshalMaxMindDB(d *mmdbdata.Decoder) error { // Custom decoding logic using d.ReadMap(), d.ReadString(), etc. // Allows fine-grained control over how MaxMind DB data is decoded // See mmdbdata package documentation and ExampleUnmarshaler for complete examples }
Network Iteration ¶
You can iterate over all networks in a database:
for result := range db.Networks() { var record struct { Country struct { ISOCode string `maxminddb:"iso_code"` } `maxminddb:"country"` } err := result.Decode(&record) if err != nil { log.Fatal(err) } fmt.Printf("%s: %s\n", result.Prefix(), record.Country.ISOCode) }
Database Files ¶
MaxMind provides both free (GeoLite2) and commercial (GeoIP2) databases:
- Free: https://dev.maxmind.com/geoip/geolite2-free-geolocation-data
- Commercial: https://www.maxmind.com/en/geoip2-databases
Thread Safety ¶
All Reader methods are thread-safe. The Reader can be safely shared across multiple goroutines.
Index ¶
- type InvalidDatabaseError
- type Metadata
- type NetworksOption
- type Reader
- func (r *Reader) Close() error
- func (r *Reader) Lookup(ip netip.Addr) Result
- func (r *Reader) LookupOffset(offset uintptr) Result
- func (r *Reader) Networks(options ...NetworksOption) iter.Seq[Result]
- func (r *Reader) NetworksWithin(prefix netip.Prefix, options ...NetworksOption) iter.Seq[Result]
- func (r *Reader) Verify() error
- type ReaderOption
- type Result
- type UnmarshalTypeError
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type InvalidDatabaseError ¶
type InvalidDatabaseError = mmdberrors.InvalidDatabaseError
InvalidDatabaseError is returned when the database contains invalid data and cannot be parsed.
type Metadata ¶
type Metadata struct { // Description contains localized database descriptions. // Keys are language codes (e.g., "en", "zh-CN"), values are UTF-8 descriptions. Description map[string]string `maxminddb:"description"` // DatabaseType indicates the structure of data records associated with IP addresses. // Names starting with "GeoIP" are reserved for MaxMind databases. DatabaseType string `maxminddb:"database_type"` // Languages lists locale codes for which this database may contain localized data. // Records should not contain localized data for locales not in this array. Languages []string `maxminddb:"languages"` // BinaryFormatMajorVersion is the major version of the MaxMind DB binary format. // Current supported version is 2. BinaryFormatMajorVersion uint `maxminddb:"binary_format_major_version"` // BinaryFormatMinorVersion is the minor version of the MaxMind DB binary format. // Current supported version is 0. BinaryFormatMinorVersion uint `maxminddb:"binary_format_minor_version"` // BuildEpoch contains the database build timestamp as Unix epoch seconds. // Use BuildTime() method for a time.Time representation. BuildEpoch uint `maxminddb:"build_epoch"` // IPVersion indicates the IP version support: // 4: IPv4 addresses only // 6: Both IPv4 and IPv6 addresses IPVersion uint `maxminddb:"ip_version"` // NodeCount is the number of nodes in the search tree. NodeCount uint `maxminddb:"node_count"` // RecordSize is the size in bits of each record in the search tree. // Valid values are 24, 28, or 32. RecordSize uint `maxminddb:"record_size"` }
Metadata holds the metadata decoded from the MaxMind DB file.
Key fields include:
- DatabaseType: indicates the structure of data records (e.g., "GeoIP2-City")
- Description: localized descriptions in various languages
- Languages: locale codes for which the database may contain localized data
- BuildEpoch: database build timestamp as Unix epoch seconds
- IPVersion: supported IP version (4 for IPv4-only, 6 for IPv4/IPv6)
- NodeCount: number of nodes in the search tree
- RecordSize: size in bits of each record in the search tree (24, 28, or 32)
For detailed field descriptions, see the MaxMind DB specification: https://maxmind.github.io/MaxMind-DB/
type NetworksOption ¶
type NetworksOption func(*networkOptions)
NetworksOption are options for Networks and NetworksWithin.
func IncludeAliasedNetworks ¶
func IncludeAliasedNetworks() NetworksOption
IncludeAliasedNetworks is an option for Networks and NetworksWithin that makes them iterate over aliases of the IPv4 subtree in an IPv6 database, e.g., ::ffff:0:0/96, 2001::/32, and 2002::/16.
func IncludeNetworksWithoutData ¶
func IncludeNetworksWithoutData() NetworksOption
IncludeNetworksWithoutData is an option for Networks and NetworksWithin that makes them include networks without any data in the iteration.
type Reader ¶
type Reader struct { Metadata Metadata // contains filtered or unexported fields }
Reader holds the data corresponding to the MaxMind DB file. Its only public field is Metadata, which contains the metadata from the MaxMind DB file.
All of the methods on Reader are thread-safe. The struct may be safely shared across goroutines.
func FromBytes ¶
func FromBytes(buffer []byte, options ...ReaderOption) (*Reader, error)
FromBytes takes a byte slice corresponding to a MaxMind DB file and any options. It returns a Reader structure or an error.
func Open ¶
func Open(file string, options ...ReaderOption) (*Reader, error)
Open takes a string path to a MaxMind DB file and any options. It returns a Reader structure or an error. The database file is opened using a memory map on supported platforms. On platforms without memory map support, such as WebAssembly or Google App Engine, or if the memory map attempt fails due to lack of support from the filesystem, the database is loaded into memory. Use the Close method on the Reader object to return the resources to the system.
func (*Reader) Lookup ¶
Lookup retrieves the database record for ip and returns a Result, which can be used to decode the data.
Example (Interface) ¶
This example demonstrates how to decode to an any.
db, err := maxminddb.Open("test-data/test-data/GeoIP2-City-Test.mmdb") if err != nil { log.Fatal(err) } defer db.Close() //nolint:errcheck // error doesn't matter addr := netip.MustParseAddr("81.2.69.142") var record any err = db.Lookup(addr).Decode(&record) if err != nil { log.Panic(err) } fmt.Printf("%v", record) //nolint:lll
Output: map[city:map[geoname_id:2643743 names:map[de:London en:London es:Londres fr:Londres ja:ロンドン pt-BR:Londres ru:Лондон]] continent:map[code:EU geoname_id:6255148 names:map[de:Europa en:Europe es:Europa fr:Europe ja:ヨーロッパ pt-BR:Europa ru:Европа zh-CN:欧洲]] country:map[geoname_id:2635167 iso_code:GB names:map[de:Vereinigtes Königreich en:United Kingdom es:Reino Unido fr:Royaume-Uni ja:イギリス pt-BR:Reino Unido ru:Великобритания zh-CN:英国]] location:map[accuracy_radius:10 latitude:51.5142 longitude:-0.0931 time_zone:Europe/London] registered_country:map[geoname_id:6252001 iso_code:US names:map[de:USA en:United States es:Estados Unidos fr:États-Unis ja:アメリカ合衆国 pt-BR:Estados Unidos ru:США zh-CN:美国]] subdivisions:[map[geoname_id:6269131 iso_code:ENG names:map[en:England es:Inglaterra fr:Angleterre pt-BR:Inglaterra]]]]
Example (Struct) ¶
This example shows how to decode to a struct.
db, err := maxminddb.Open("test-data/test-data/GeoIP2-City-Test.mmdb") if err != nil { log.Fatal(err) } defer db.Close() //nolint:errcheck // error doesn't matter addr := netip.MustParseAddr("81.2.69.142") var record struct { Country struct { ISOCode string `maxminddb:"iso_code"` } `maxminddb:"country"` } // Or any appropriate struct err = db.Lookup(addr).Decode(&record) if err != nil { log.Panic(err) } fmt.Print(record.Country.ISOCode)
Output: GB
func (*Reader) LookupOffset ¶
LookupOffset returns the Result for the specified offset. Note that netip.Prefix returned by Networks will be invalid when using LookupOffset.
func (*Reader) Networks ¶
func (r *Reader) Networks(options ...NetworksOption) iter.Seq[Result]
Networks returns an iterator that can be used to traverse the networks in the database.
Please note that a MaxMind DB may map IPv4 networks into several locations in an IPv6 database. This iterator will only iterate over these once by default. To iterate over all the IPv4 network locations, use the IncludeAliasedNetworks option.
Networks without data are excluded by default. To include them, use IncludeNetworksWithoutData.
Example ¶
This example demonstrates how to iterate over all networks in the database.
db, err := maxminddb.Open("test-data/test-data/GeoIP2-Connection-Type-Test.mmdb") if err != nil { log.Fatal(err) } defer db.Close() //nolint:errcheck // error doesn't matter for result := range db.Networks() { record := struct { ConnectionType string `maxminddb:"connection_type"` }{} err := result.Decode(&record) if err != nil { log.Panic(err) } fmt.Printf("%s: %s\n", result.Prefix(), record.ConnectionType) }
Output: 1.0.0.0/24: Cable/DSL 1.0.1.0/24: Cellular 1.0.2.0/23: Cable/DSL 1.0.4.0/22: Cable/DSL 1.0.8.0/21: Cable/DSL 1.0.16.0/20: Cable/DSL 1.0.32.0/19: Cable/DSL 1.0.64.0/18: Cable/DSL 1.0.128.0/17: Cable/DSL 2.125.160.216/29: Cable/DSL 67.43.156.0/24: Cellular 80.214.0.0/20: Cellular 96.1.0.0/16: Cable/DSL 96.10.0.0/15: Cable/DSL 96.69.0.0/16: Cable/DSL 96.94.0.0/15: Cable/DSL 108.96.0.0/11: Cellular 149.101.100.0/28: Cellular 175.16.199.0/24: Cable/DSL 187.156.138.0/24: Cable/DSL 201.243.200.0/24: Corporate 207.179.48.0/20: Cellular 216.160.83.56/29: Corporate 2003::/24: Cable/DSL
func (*Reader) NetworksWithin ¶
NetworksWithin returns an iterator that can be used to traverse the networks in the database which are contained in a given prefix.
Please note that a MaxMind DB may map IPv4 networks into several locations in an IPv6 database. This iterator will only iterate over these once by default. To iterate over all the IPv4 network locations, use the IncludeAliasedNetworks option.
If the provided prefix is contained within a network in the database, the iterator will iterate over exactly one network, the containing network.
Networks without data are excluded by default. To include them, use IncludeNetworksWithoutData.
Example ¶
This example demonstrates how to iterate over all networks in the database which are contained within an arbitrary network.
db, err := maxminddb.Open("test-data/test-data/GeoIP2-Connection-Type-Test.mmdb") if err != nil { log.Fatal(err) } defer db.Close() //nolint:errcheck // error doesn't matter prefix, err := netip.ParsePrefix("1.0.0.0/8") if err != nil { log.Panic(err) } for result := range db.NetworksWithin(prefix) { record := struct { ConnectionType string `maxminddb:"connection_type"` }{} err := result.Decode(&record) if err != nil { log.Panic(err) } fmt.Printf("%s: %s\n", result.Prefix(), record.ConnectionType) }
Output: 1.0.0.0/24: Cable/DSL 1.0.1.0/24: Cellular 1.0.2.0/23: Cable/DSL 1.0.4.0/22: Cable/DSL 1.0.8.0/21: Cable/DSL 1.0.16.0/20: Cable/DSL 1.0.32.0/19: Cable/DSL 1.0.64.0/18: Cable/DSL 1.0.128.0/17: Cable/DSL
func (*Reader) Verify ¶
Verify performs comprehensive validation of the MaxMind DB file.
This method validates:
- Metadata section: format versions, required fields, and value constraints
- Search tree: traverses all networks to verify tree structure integrity
- Data section separator: validates the 16-byte separator between tree and data
- Data section: verifies all data records referenced by the search tree
The verifier is stricter than the MaxMind DB specification and may return errors on some databases that are still readable by normal operations. This method is useful for:
- Validating database files after download or generation
- Debugging database corruption issues
- Ensuring database integrity in critical applications
Note: Verification traverses the entire database and may be slow on large files. The method is thread-safe and can be called on an active Reader.
Example ¶
This example demonstrates how to validate a MaxMind DB file and access metadata.
db, err := maxminddb.Open("test-data/test-data/GeoIP2-City-Test.mmdb") if err != nil { log.Fatal(err) } defer db.Close() //nolint:errcheck // error doesn't matter // Verify database integrity if err := db.Verify(); err != nil { log.Printf("Database validation failed: %v", err) return } // Access metadata information metadata := db.Metadata fmt.Printf("Database type: %s\n", metadata.DatabaseType) fmt.Printf("Build time: %s\n", metadata.BuildTime().UTC().Format("2006-01-02 15:04:05")) fmt.Printf("IP version: IPv%d\n", metadata.IPVersion) fmt.Printf("Languages: %v\n", metadata.Languages) if desc, ok := metadata.Description["en"]; ok { fmt.Printf("Description: %s\n", desc) }
Output: Database type: GeoIP2-City Build time: 2022-07-26 14:53:10 IP version: IPv6 Languages: [en zh] Description: GeoIP2 City Test Database (fake GeoIP2 data, for example purposes only)
type ReaderOption ¶
type ReaderOption func(*readerOptions)
ReaderOption are options for Open and FromBytes.
This was added to allow for future options, e.g., for caching, without causing a breaking API change.
type Result ¶
type Result struct {
// contains filtered or unexported fields
}
Result holds the result of the database lookup.
func (Result) Decode ¶
Decode unmarshals the data from the data section into the value pointed to by v. If v is nil or not a pointer, an error is returned. If the data in the database record cannot be stored in v because of type differences, an UnmarshalTypeError is returned. If the database is invalid or otherwise cannot be read, an InvalidDatabaseError is returned.
An error will also be returned if there was an error during the Reader.Lookup call.
If the Reader.Lookup call did not find a value for the IP address, no error will be returned and v will be unchanged.
func (Result) DecodePath ¶
DecodePath unmarshals a value from data section into v, following the specified path.
The v parameter should be a pointer to the value where the decoded data will be stored. If v is nil or not a pointer, an error is returned. If the data in the database record cannot be stored in v because of type differences, an UnmarshalTypeError is returned.
The path is a variadic list of keys (strings) and/or indices (ints) that describe the nested structure to traverse in the data to reach the desired value.
For maps, string path elements are used as keys. For arrays, int path elements are used as indices. A negative offset will return values from the end of the array, e.g., -1 will return the last element.
If the path is empty, the entire data structure is decoded into v.
Returns an error if:
- the path is invalid
- the data cannot be decoded into the type of v
- v is not a pointer or the database record cannot be stored in v due to type mismatch
- the Result does not contain valid data
Example usage:
var city string err := result.DecodePath(&city, "location", "city", "names", "en") var geonameID int err := result.DecodePath(&geonameID, "subdivisions", 0, "geoname_id")
func (Result) Err ¶
Err provides a way to check whether there was an error during the lookup without calling Result.Decode. If there was an error, it will also be returned from Result.Decode.
func (Result) Found ¶
Found will return true if the IP was found in the search tree. It will return false if the IP was not found or if there was an error.
func (Result) Offset ¶
Offset returns the offset of the record in the database. This can be passed to (*Reader).LookupOffset. It can also be used as a unique identifier for the data record in the particular database to cache the data record across lookups. Note that while the offset uniquely identifies the data record, other data in Result may differ between lookups. The offset is only valid for the current database version. If you update the database file, you must invalidate any cache associated with the previous version.
type UnmarshalTypeError ¶
type UnmarshalTypeError = mmdberrors.UnmarshalTypeError
UnmarshalTypeError is returned when the value in the database cannot be assigned to the specified data type.
Directories
¶
Path | Synopsis |
---|---|
internal
|
|
decoder
Package decoder decodes values in the data section.
|
Package decoder decodes values in the data section. |
mmdberrors
Package mmdberrors is an internal package for the errors used in this module.
|
Package mmdberrors is an internal package for the errors used in this module. |
Package mmdbdata provides low-level types and interfaces for custom MaxMind DB decoding.
|
Package mmdbdata provides low-level types and interfaces for custom MaxMind DB decoding. |