Skip to content

Synse/maxminddb-golang

 
 

Repository files navigation

MaxMind DB Reader for Go

Go Reference

This is a Go reader for the MaxMind DB format. Although this can be used to read GeoLite2 and GeoIP2 databases, geoip2 provides a higher-level API for doing so.

This is not an official MaxMind API.

Installation

go get github.com/oschwald/maxminddb-golang/v2

Version 2.0 Features

Version 2.0 includes significant improvements:

  • Modern API: Uses netip.Addr instead of net.IP for better performance
  • Custom Unmarshaling: Implement Unmarshaler interface for zero-allocation decoding
  • Network Iteration: Iterate over all networks in a database with Networks() and NetworksWithin()
  • Enhanced Performance: Optimized data structures and decoding paths
  • Go 1.23+ Support: Takes advantage of modern Go features including iterators
  • Better Error Handling: More detailed error types and improved debugging

Quick Start

package main

import (
	"fmt"
	"log"
	"net/netip"

	"github.com/oschwald/maxminddb-golang/v2"
)

func main() {
	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 (%s)\n", record.Country.Names["en"], record.Country.ISOCode)
	fmt.Printf("City: %s\n", record.City.Names["en"])
}

Usage Patterns

Basic Lookup

db, err := maxminddb.Open("GeoLite2-City.mmdb")
if err != nil {
	log.Fatal(err)
}
defer db.Close()

var record any
ip := netip.MustParseAddr("1.2.3.4")
err = db.Lookup(ip).Decode(&record)

Custom Struct Decoding

type City struct {
	Country struct {
		ISOCode string `maxminddb:"iso_code"`
		Names   struct {
			English string `maxminddb:"en"`
			German  string `maxminddb:"de"`
		} `maxminddb:"names"`
	} `maxminddb:"country"`
}

var city City
err = db.Lookup(ip).Decode(&city)

High-Performance Custom Unmarshaling

type FastCity struct {
	CountryISO string
	CityName   string
}

func (c *FastCity) UnmarshalMaxMindDB(d *maxminddb.Decoder) error {
	mapIter, size, err := d.ReadMap()
	if err != nil {
		return err
	}
	// Pre-allocate with correct capacity for better performance
	_ = size // Use for pre-allocation if storing map data
	for key, err := range mapIter {
		if err != nil {
			return err
		}
		switch string(key) {
		case "country":
			countryIter, _, err := d.ReadMap()
			if err != nil {
				return err
			}
			for countryKey, countryErr := range countryIter {
				if countryErr != nil {
					return countryErr
				}
				if string(countryKey) == "iso_code" {
					c.CountryISO, err = d.ReadString()
					if err != nil {
						return err
					}
				} else {
					if err := d.SkipValue(); err != nil {
						return err
					}
				}
			}
		default:
			if err := d.SkipValue(); err != nil {
				return err
			}
		}
	}
	return nil
}

Network Iteration

// Iterate over all networks in the 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)
}

// Iterate over networks within a specific prefix
prefix := netip.MustParsePrefix("192.168.0.0/16")
for result := range db.NetworksWithin(prefix) {
	// Process networks within 192.168.0.0/16
}

Path-Based Decoding

var countryCode string
err = db.Lookup(ip).DecodePath(&countryCode, "country", "iso_code")

var cityName string
err = db.Lookup(ip).DecodePath(&cityName, "city", "names", "en")

Supported Database Types

This library supports all MaxMind DB (.mmdb) format databases, including:

MaxMind Official Databases:

  • GeoLite/GeoIP City: Comprehensive location data including city, country, subdivisions
  • GeoLite/GeoIP Country: Country-level geolocation data
  • GeoLite ASN: Autonomous System Number and organization data
  • GeoIP Anonymous IP: Anonymous network and proxy detection
  • GeoIP Enterprise: Enhanced City data with additional business fields
  • GeoIP ISP: Internet service provider information
  • GeoIP Domain: Second-level domain data
  • GeoIP Connection Type: Connection type identification

Third-Party Databases:

  • DB-IP databases: Compatible with DB-IP's .mmdb format databases
  • IPinfo databases: Works with IPinfo's MaxMind DB format files
  • Custom databases: Any database following the MaxMind DB file format specification

The library is format-agnostic and will work with any valid .mmdb file regardless of the data provider.

Performance Tips

  1. Reuse Reader instances: The Reader is thread-safe and should be reused across goroutines
  2. Use specific structs: Only decode the fields you need rather than using any
  3. Implement Unmarshaler: For high-throughput applications, implement custom unmarshaling
  4. Consider caching: Use Result.Offset() as a cache key for database records

Getting Database Files

Free GeoLite2 Databases

Download from MaxMind's GeoLite page.

Documentation

Requirements

  • Go 1.23 or later
  • MaxMind DB file in .mmdb format

Contributing

Contributions welcome! Please fork the repository and open a pull request with your changes.

License

This is free software, licensed under the ISC License.

About

MaxMind DB Reader for Go

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Go 100.0%