### Install mmdbwriter Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/quickstart.md Install the mmdbwriter library using go get. ```bash go get github.com/maxmind/mmdbwriter ``` -------------------------------- ### ASN Writer Example Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/COMPLETION_SUMMARY.txt Shows how to build an MMDB file containing Autonomous System Number (ASN) data. ```go package main import ( "log" "github.com/maxmind/mmdbwriter" "github.com/maxmind/mmdbwriter/mmdbtype" ) func main() { // Initialize MMDB writer for ASN data. w, err := mmdbwriter.New( mmdbwriter.Options{ RecordSize: 28, DatabaseType: "ASN", }, ) if err != nil { log.Fatalf("failed to create writer: %v", err) } // Insert data for an IP range, associating it with an ASN. _ = w.Insert("192.0.0.0/24", mmdbtype.Map{ "autonomous_system_number": uint(15169), "organization": "Google LLC", }) // Write the MMDB data to standard output. _, err = w.WriteTo(os.Stdout) if err != nil { log.Fatalf("failed to write database: %v", err) } } ``` -------------------------------- ### Create a New Database Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/quickstart.md This minimal example demonstrates how to create a new mmdbwriter database, insert network data, and write it to a file. ```go package main import ( "log" "net" "os" "github.com/maxmind/mmdbwriter" "github.com/maxmind/mmdbwriter/mmdbtype" ) func main() { // Create a new tree tree, err := mmdbwriter.New(mmdbwriter.Options{ DatabaseType: "My-Database", }) if err != nil { log.Fatal(err) } // Insert data for a network network, _ := net.ParseCIDR("1.1.1.0/24") data := mmdbtype.Map{ "country": mmdbtype.String("US"), "city": mmdbtype.String("Los Angeles"), } if err := tree.Insert(network, data); err != nil { log.Fatal(err) } // Write to file file, err := os.Create("output.mmdb") if err != nil { log.Fatal(err) } defer file.Close() if _, err := tree.WriteTo(file); err != nil { log.Fatal(err) } } ``` -------------------------------- ### Build Database from CSV Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/quickstart.md This example demonstrates building an ASN database from a CSV file, parsing network, ASN, and organization data. ```go package main import ( "encoding/csv" "errors" "io" "log" "net" "os" "strconv" "github.com/maxmind/mmdbwriter" "github.com/maxmind/mmdbwriter/mmdbtype" ) func main() { tree, _ := mmdbwriter.New(mmdbwriter.Options{ DatabaseType: "ASN-DB", }) file, _ := os.Open("asn-data.csv") defer file.Close() reader := csv.NewReader(file) reader.Read() // Skip header for { record, err := reader.Read() if errors.Is(err, io.EOF) { break } if err != nil { log.Fatal(err) } // Format: network, asn, organization _, network, _ := net.ParseCIDR(record[0]) asn, _ := strconv.Atoi(record[1]) data := mmdbtype.Map{ "asn": mmdbtype.Uint32(uint32(asn)), "organization": mmdbtype.String(record[2]), } tree.Insert(network, data) } out, _ := os.Create("asn.mmdb") defer out.Close() tree.WriteTo(out) } ``` -------------------------------- ### Create New MMDB File Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/README.md Demonstrates the basic setup for creating a new MMDB file using the mmdbwriter package. Includes initialization with options. ```go package main import ( "github.com/maxmind/mmdbwriter" "github.com/maxmind/mmdbwriter/mmdbtype" ) func main() { tree, _ := mmdbwriter.New(mmdbwriter.Options{ DatabaseType: "MyDB", }) // ... rest of example } ``` -------------------------------- ### City Rewriter Example Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/COMPLETION_SUMMARY.txt Demonstrates rewriting an existing MMDB file, specifically for city data. ```go package main import ( "log" "os" "github.com/maxmind/mmdbwriter" "github.com/maxmind/mmdbwriter/inserter" "github.com/maxmind/mmdbwriter/mmdbtype" ) func main() { // Open an existing MMDB file for reading. r, err := os.Open("city.mmdb") if err != nil { log.Fatalf("failed to open database: %v", err) } defer r.Close() // Load the existing MMDB data into a new writer. // Use DeepMergeWith to recursively merge data if networks overlap. w, err := mmdbwriter.Load(r, mmdbwriter.Options{ Inserter: inserter.DeepMergeWith, }) if err != nil { log.Fatalf("failed to load database: %v", err) } // Insert new or updated data for a specific IP network. _ = w.Insert("1.1.1.0/24", mmdbtype.Map{ "city": mmdbtype.Map{ "name": "Test City", }, "country": mmdbtype.Map{ "iso_code": "XX", }, }) // Write the modified MMDB data to a new file. out, err := os.Create("city-rewritten.mmdb") if err != nil { log.Fatalf("failed to create output file: %v", err) } defer out.Close() _, err = w.WriteTo(out) if err != nil { log.Fatalf("failed to write database: %v", err) } } ``` -------------------------------- ### Country Writer Example Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/COMPLETION_SUMMARY.txt Demonstrates how to create a new MMDB file for country data from scratch. ```go package main import ( "log" "github.com/maxmind/mmdbwriter" "github.com/maxmind/mmdbwriter/mmdbtype" ) func main() { // Create a new MMDB writer with default options. w, err := mmdbwriter.New( mmdbwriter.Options{ // Use the default "replace" // insertion strategy. RecordSize: 24, DatabaseType: "Country", }, ) if err != nil { log.Fatalf("failed to create writer: %v", err) } // Insert data for a specific IP network. // The data is a map containing country information. _ = w.Insert("1.1.1.0/24", mmdbtype.Map{ "country": mmdbtype.Map{ "iso_code": "US", "names": mmdbtype.Map{ "en": "United States", }, }, }) // Serialize the data to an MMDB file. // The data will be written to standard output. _, err = w.WriteTo(os.Stdout) if err != nil { log.Fatalf("failed to write database: %v", err) } } ``` -------------------------------- ### Load and Modify an Existing Database Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/quickstart.md This example shows how to load an existing mmdb database, add or modify data for a network, and write the changes to a new file. ```go package main import ( "log" "net" "os" "github.com/maxmind/mmdbwriter" "github.com/maxmind/mmdbwriter/mmdbtype" ) func main() { // Load an existing database tree, err := mmdbwriter.Load("original.mmdb", mmdbwriter.Options{ DatabaseType: "Enhanced-Database", }) if err != nil { log.Fatal(err) } // Add or modify data network, _ := net.ParseCIDR("8.8.8.0/24") data := mmdbtype.Map{ "provider": mmdbtype.String("Google"), } if err := tree.Insert(network, data); err != nil { log.Fatal(err) } // Write to new file file, err := os.Create("modified.mmdb") if err != nil { log.Fatal(err) } defer file.Close() if _, err := tree.WriteTo(file); err != nil { log.Fatal(err) } } ``` -------------------------------- ### Create a Simple Geographic Database Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/examples.md Create a MaxMind DB with geographic data for IP networks. This example demonstrates inserting data for different networks and writing it to a file. ```go package main import ( "log" "net" "os" "github.com/maxmind/mmdbwriter" "github.com/maxmind/mmdbwriter/mmdbtype" ) func main() { // Create a new tree for geographic data tree, err := mmdbwriter.New(mmdbwriter.Options{ DatabaseType: "GeoIP-Simple", Description: map[string]string{ "en": "Simple geographic database", }, Languages: []string{"en"}, }) if err != nil { log.Fatal(err) } // Insert data for different networks networks := map[string]string{ "1.1.1.0/24": "United States", "8.8.8.0/24": "United States", "208.67.222.0/24": "United States", } for cidr, country := range networks { _, network, err := net.ParseCIDR(cidr) if err != nil { log.Fatal(err) } data := mmdbtype.Map{ "country": mmdbtype.String(country), } if err := tree.Insert(network, data); err != nil { log.Fatal(err) } } // Write to file file, err := os.Create("simple-geo.mmdb") if err != nil { log.Fatal(err) } defer file.Close() bytesWritten, err := tree.WriteTo(file) if err != nil { log.Fatal(err) } log.Printf("Wrote %d bytes to simple-geo.mmdb\n", bytesWritten) } ``` -------------------------------- ### DeepMergeWith Example Usage Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/inserter.md Demonstrates inserting and deep merging complex nested structures using DeepMergeWith. Shows how maps and slices are merged recursively and how new keys/elements are added. ```go tree, _ := mmdbwriter.New(mmdbwriter.Options{ Inserter: inserter.DeepMergeWith, }) network, _ := net.ParseCIDR("1.0.0.0/8") // Insert complex nested structure tree.Insert(network, mmdbtype.Map{ "geo": mmdbtype.Map{ "country": mmdbtype.String("US"), "region": mmdbtype.String("CA"), }, "services": mmdbtype.Slice{ mmdbtype.String("DNS"), }, }) // Deep merge with new nested data tree.Insert(network, mmdbtype.Map{ "geo": mmdbtype.Map{ "city": mmdbtype.String("San Francisco"), // New key at nested level }, "services": mmdbtype.Slice{ mmdbtype.String("HTTP"), // Replaces at index 0 mmdbtype.String("HTTPS"), // Adds at index 1 }, }) ``` -------------------------------- ### Custom Inserter Function Example Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/api-overview.md Defines a custom inserter function for handling data insertion logic, allowing for custom merge or transformation of existing data. ```Go func myInserter(value mmdbtype.DataType) inserter.Func { return func(existing mmdbtype.DataType) (mmdbtype.DataType, error) { // Custom merge logic return result, nil } } ``` -------------------------------- ### Build ASN Database from CSV Data Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/examples.md Build a MaxMind DB from CSV input for ASN data. This example parses a CSV file with network, ASN, and organization information, then inserts it into the database. ```go package main import ( "encoding/csv" "errors" "io" "log" "net" "os" "strconv" "github.com/maxmind/mmdbwriter" "github.com/maxmind/mmdbwriter/mmdbtype" ) func main() { // Create tree for ASN data tree, err := mmdbwriter.New(mmdbwriter.Options{ DatabaseType: "ASN", Description: map[string]string{ "en": "ASN Database", }, RecordSize: 24, // More compact for ASN data }) if err != nil { log.Fatal(err) } // Open CSV file (format: network,asn,organization) file, err := os.Open("asn-data.csv") if err != nil { log.Fatal(err) } defer file.Close() reader := csv.NewReader(file) lineNum := 0 for { record, err := reader.Read() if errors.Is(err, io.EOF) { break } if err != nil { log.Fatalf("Line %d: %v", lineNum, err) } if lineNum == 0 { lineNum++ // Skip header continue } // Parse CSV row if len(record) < 3 { log.Printf("Skipping line %d: insufficient fields\n", lineNum) lineNum++ continue } _, network, err := net.ParseCIDR(record[0]) if err != nil { log.Printf("Line %d: invalid CIDR %s: %v\n", lineNum, record[0], err) lineNum++ continue } asn, err := strconv.Atoi(record[1]) if err != nil { log.Printf("Line %d: invalid ASN %s: %v\n", lineNum, record[1], err) lineNum++ continue } // Build record data := mmdbtype.Map{} if asn != 0 { data["autonomous_system_number"] = mmdbtype.Uint32(uint32(asn)) } if record[2] != "" { data["autonomous_system_organization"] = mmdbtype.String(record[2]) } // Insert into tree if err := tree.Insert(network, data); err != nil { log.Fatalf("Line %d: insert failed: %v\n", lineNum, err) } if lineNum%10000 == 0 { log.Printf("Processed %d lines\n", lineNum) } lineNum++ } // Write output out, err := os.Create("asn-output.mmdb") if err != nil { log.Fatal(err) } defer out.Close() bytesWritten, err := tree.WriteTo(out) if err != nil { log.Fatal(err) } log.Printf("Wrote %d bytes, processed %d records\n", bytesWritten, lineNum) } ``` -------------------------------- ### Retrieve Data for an IP Address Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/tree.md Use Get to retrieve the most specific network and its associated data for a given IP address. If no data is explicitly associated, it returns the network determined by the tree structure and nil data. ```go func (t *Tree) Get(ip net.IP) (*net.IPNet, mmdbtype.DataType) ``` ```go ip := net.ParseIP("1.1.1.1") network, data := tree.Get(ip) if data != nil { fmt.Printf("Found %v in network %s\n", data, network.String()) } else { fmt.Printf("No data for %s (in network %s)\n", ip, network.String()) } ``` -------------------------------- ### DeepMerge Recursive Behavior Example Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/inserter.md Illustrates the recursive merging behavior of DeepMerge for deeply nested map structures. Shows how values are updated and new fields are added at any depth. ```go // DeepMerge handles nested structures at any depth original := mmdbtype.Map{ "data": mmdbtype.Map{ "nested": mmdbtype.Map{ "value": mmdbtype.String("old"), }, }, } new := mmdbtype.Map{ "data": mmdbtype.Map{ "nested": mmdbtype.Map{ "value": mmdbtype.String("new"), "extra": mmdbtype.String("added"), }, }, } // All levels are merged recursively ``` -------------------------------- ### Retrieve and Type-Assert Data from Tree Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/types.md Shows how to retrieve data from an MMDB tree using Get() and perform type assertions to access nested map values and string types. ```go network, data := tree.Get(net.ParseIP("8.8.8.8")) if data != nil { if record, ok := data.(mmdbtype.Map); ok { if org, exists := record["organization"]; exists { if orgStr, ok := org.(mmdbtype.String); ok { fmt.Println("Organization:", orgStr) } } } } ``` -------------------------------- ### Load Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/REFERENCE.md Loads an existing MaxMind DB file and creates a new Tree with its data. This function allows you to start with an existing database and modify it. Unset configuration fields in the provided options will inherit values from the loaded file. ```APIDOC ## Load ### Description Loads an existing MaxMind DB file and creates a new Tree with its data. ### Method func Load(path string, opts Options) (*Tree, error) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - `path string` — Path to existing MMDB file - `opts Options` — Configuration (unset fields inherit from file) ### Return Values - `*Tree` — New tree with file contents, or nil on error - `error` — Load/parse error, or nil on success ### Errors - File open errors - Parse errors - Decode errors - Unmarshaling errors ### Behavior - Opens and reads the MMDB file - Inherits metadata if not set in opts: - DatabaseType - Description - IPVersion - Languages - RecordSize - Creates new Tree with inherited settings - Decodes all networks and data from file - Returns populated Tree ready for modification ### Example ```go tree, err := mmdbwriter.Load("original.mmdb", mmdbwriter.Options{}) ``` ``` -------------------------------- ### Insert Data for an IP Range Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/tree.md Use InsertRange to insert a single data value for all subnets within a specified IP range [start, end]. The function decomposes the range into minimal CIDR subnets and uses the configured inserter. The start and end IPs must be of the same version and start must be less than or equal to end. ```go func (t *Tree) InsertRange(start net.IP, end net.IP, value mmdbtype.DataType) error ``` ```go start := net.ParseIP("192.0.2.0") end := net.ParseIP("192.0.2.255") record := mmdbtype.String("Example Range") err := tree.InsertRange(start, end, record) if err != nil { log.Fatal(err) } ``` -------------------------------- ### Get Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/tree.md Retrieves the network and associated data value for the given IP address. ```APIDOC ## Get ### Description Retrieves the network and associated data value for the given IP address. ### Method func (t *Tree) Get(ip net.IP) (*net.IPNet, mmdbtype.DataType) ### Parameters #### Path Parameters - **ip** (net.IP) - Required - The IP address to look up ### Return - `*net.IPNet` — The matching network (CIDR notation). If no data is associated, this will be the network determined by the tree structure - `mmdbtype.DataType` — The associated data value, or nil if no data exists for the IP ### Behavior - Returns the most specific (longest prefix) network that contains the IP - Returns nil data if the IP is in a reserved or empty network (unless data was explicitly inserted) ### Example ```go ip := net.ParseIP("1.1.1.1") network, data := tree.Get(ip) if data != nil { fmt.Printf("Found %v in network %s\n", data, network.String()) } else { fmt.Printf("No data for %s (in network %s)\n", ip, network.String()) } ``` ``` -------------------------------- ### Create New Tree Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/tree.md Use the `New` function to create a new Tree instance. Configure it using `Options`, which include settings like DatabaseType, Description, IPVersion, RecordSize, and Languages. Defaults are applied if options are not explicitly provided. ```go tree, err := mmdbwriter.New(mmdbwriter.Options{ DatabaseType: "My-Database", Description: map[string]string{ "en": "My custom database", }, IPVersion: 6, RecordSize: 28, Languages: []string{"en", "fr"}, }) if err != nil { log.Fatal(err) } ``` -------------------------------- ### InsertRange Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/tree.md Inserts a data value for all subnets within the given IP range [start, end] inclusive. ```APIDOC ## InsertRange ### Description Inserts a data value for all subnets within the given IP range `[start, end]` inclusive. ### Method func (t *Tree) InsertRange(start net.IP, end net.IP, value mmdbtype.DataType) error ### Parameters #### Path Parameters - **start** (net.IP) - Required - Start IP address (inclusive) - **end** (net.IP) - Required - End IP address (inclusive) - **value** (mmdbtype.DataType) - Required - The data value to insert ### Return - `error` — An error if the range is invalid or insertion fails ### Behavior - Decomposes the range into minimal CIDR subnets - Each subnet is inserted using the configured inserter function - Range must be valid (start <= end) and both must be the same IP version ### Example ```go start := net.ParseIP("192.0.2.0") end := net.ParseIP("192.0.2.255") record := mmdbtype.String("Example Range") err := tree.InsertRange(start, end, record) if err != nil { log.Fatal(err) } ``` ``` -------------------------------- ### Create Compact Database Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/quickstart.md Initialize a new database writer with options for a compact database type and a smaller record size for reduced file size. ```go tree, _ := mmdbwriter.New(mmdbwriter.Options{ DatabaseType: "Compact-DB", RecordSize: 24, // Smaller size, more compact }) ``` -------------------------------- ### Define Options Structure Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/REFERENCE.md Configuration parameters for Tree initialization. Includes settings for build epoch, database type, IP version, and insertion strategies. ```go type Options struct { BuildEpoch int64 DatabaseType string Description map[string]string DisableIPv4Aliasing bool IncludeReservedNetworks bool IPVersion int Languages []string RecordSize int DisableMetadataPointers bool Inserter inserter.FuncGenerator KeyGenerator KeyGenerator } ``` -------------------------------- ### Get Unmarshaler Result Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/unmarshaler.md Returns the most recently unmarshaled value. Returns nil if nothing has been decoded yet or if Clear() was called. ```go unmarshaler := mmdbtype.NewUnmarshaler() decoder.Read(unmarshaler) // Decodes and stores result internally result := unmarshaler.Result() if result != nil { fmt.Printf("Decoded value: %v\n", result) } ``` -------------------------------- ### Create and Write a New MMDB File Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/api-overview.md Demonstrates how to create a new MMDB tree, insert data, and write it to a file. Uses default options. ```go tree, _ := mmdbwriter.New(mmdbwriter.Options{ DatabaseType: "MyDB", }) tree.Insert(net.ParseCIDR("1.1.1.0/24"), mmdbtype.String("data")) file, _ := os.Create("out.mmdb") tree.WriteTo(file) ``` -------------------------------- ### Create Multilingual Database Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/examples.md Create a database with localized descriptions for different languages. Ensure the 'Languages' field in Options matches the keys in the 'Description' map. ```go package main import ( "log" "net" "os" "github.com/maxmind/mmdbwriter" "github.com/maxmind/mmdbwriter/mmdbtype" ) func main() { tree, err := mmdbwriter.New(mmdbwriter.Options{ DatabaseType: "City-DB", Description: map[string]string{ "en": "City information database", "fr": "Base de données d'informations sur les villes", "de": "Datenbank mit Stadtinformationen", "es": "Base de datos de información de ciudades", }, Languages: []string{"en", "fr", "de", "es"}, }) if err != nil { log.Fatal(err) } network, _ := net.ParseCIDR("1.1.1.0/24") // Record with localized city names data := mmdbtype.Map{ "city_names": mmdbtype.Map{ "en": mmdbtype.String("San Francisco"), "fr": mmdbtype.String("San Francisco"), "de": mmdbtype.String("San Francisco"), "es": mmdbtype.String("San Francisco"), }, "country": mmdbtype.String("US"), "timezone": mmdbtype.String("America/Los_Angeles"), } if err := tree.Insert(network, data); err != nil { log.Fatal(err) } file, err := os.Create("city-multilingual.mmdb") if err != nil { log.Fatal(err) } defer file.Close() if _, err := tree.WriteTo(file); err != nil { log.Fatal(err) } log.Println("Created multilingual database") } ``` -------------------------------- ### Default KeyGenerator Initialization Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/keygenerator.md Demonstrates initializing a new Tree with the default KeyGenerator, which uses SHA-256 serialization for key generation. ```go tree, _ := mmdbwriter.New(mmdbwriter.Options{ // KeyGenerator defaults to SHA-256 serialization }) ``` -------------------------------- ### Create Database with Custom Build Timestamp Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/examples.md Create a database with a specific build date by setting the 'BuildEpoch' option. This allows for precise versioning and tracking of database creation. ```go package main import ( "log" "net" "os" "time" "github.com/maxmind/mmdbwriter" "github.com/maxmind/mmdbwriter/mmdbtype" ) func main() { // Set build time to January 1, 2024 UTC buildTime := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC) tree, err := mmdbwriter.New(mmdbwriter.Options{ DatabaseType: "Snapshot-2024-01-01", BuildEpoch: buildTime.Unix(), Description: map[string]string{ "en": "Database snapshot from 2024-01-01", }, }) if err != nil { log.Fatal(err) } network, _ := net.ParseCIDR("1.1.1.0/24") tree.Insert(network, mmdbtype.String("data")) file, err := os.Create("snapshot-2024-01-01.mmdb") if err != nil { log.Fatal(err) } defer file.Close() if _, err := tree.WriteTo(file); err != nil { log.Fatal(err) } log.Println("Created database with specific build timestamp") } ``` -------------------------------- ### Example of a Bad KeyGenerator Causing Corruption Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/keygenerator.md Illustrates a critical error where a KeyGenerator always returns the same key, leading to silent data overwrites and database corruption. ```go // BAD: This key generator always returns "a" badGen := func(v mmdbtype.DataType) ([]byte, error) { return []byte("a"), nil // All values get the same key! } tree, _ := mmdbwriter.New(mmdbwriter.Options{ KeyGenerator: badGen, }) tree.Insert(net.ParseCIDR("1.1.1.0/24"), mmdbtype.String("Value1")) tree.Insert(net.ParseCIDR("2.2.2.0/24"), mmdbtype.String("Value2")) // Both networks will point to Value2 (Value1 was overwritten) // This is a silent corruption! ``` -------------------------------- ### Options Struct Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/REFERENCE.md Defines configuration parameters for initializing and customizing the Tree. ```APIDOC ## Options Struct ### Fields: - **BuildEpoch** (int64): Build timestamp in Unix epoch format. Defaults to the current time. - **DatabaseType** (string): An identifier for the database type. - **Description** (map[string]string): Localized descriptions for the database. - **DisableIPv4Aliasing** (bool): If true, disables IPv4-aliasing in IPv6 trees. Defaults to false. - **IncludeReservedNetworks** (bool): If true, allows insertion of reserved IP networks. Defaults to false. - **IPVersion** (int): The IP version to use (4 or 6). Defaults to 6. - **Languages** ([]string): A list of supported locale codes. - **RecordSize** (int): The record size in bits (24, 28, or 32). Defaults to 28. - **DisableMetadataPointers** (bool): If true, disables metadata pointers. Defaults to false. - **Inserter** (inserter.FuncGenerator): The strategy for handling insertions. Defaults to `inserter.ReplaceWith`. - **KeyGenerator** (KeyGenerator): The strategy for generating unique keys for data deduplication. Defaults to `defaultKeyGen`. ``` -------------------------------- ### Create New Tree Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/INDEX.md Initializes a new MaxMind DB writer tree with specified options. Configure database type, IP version, and record size. ```go tree, err := mmdbwriter.New(mmdbwriter.Options{ DatabaseType: "MyDatabase", IPVersion: 6, RecordSize: 28, }) ``` -------------------------------- ### TopLevelMergeWith key overwriting example Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/inserter.md Demonstrates how TopLevelMergeWith overwrites existing keys when merging Map values. If a key exists in both the old and new Map, the value from the new Map is used. ```go tree, _ := mmdbwriter.New(mmdbwriter.Options{ Inserter: inserter.TopLevelMergeWith, }) network, _ := net.ParseCIDR("1.0.0.0/8") tree.Insert(network, mmdbtype.Map{ "type": mmdbtype.String("ISP"), }) tree.Insert(network, mmdbtype.Map{ "type": mmdbtype.String("DATACENTER"), // Overwrites previous "type" }) // Result: "DATACENTER" ``` -------------------------------- ### Create Compact IPv4 Database Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/examples.md Create a small IPv4-only database using the smallest record size. This is useful for minimizing database size when only IPv4 is needed. ```go package main import ( "log" "net" "os" "github.com/maxmind/mmdbwriter" "github.com/maxmind/mmdbwriter/mmdbtype" ) func main() { tree, err := mmdbwriter.New(mmdbwriter.Options{ DatabaseType: "IPv4-Compact", IPVersion: 4, // IPv4 only RecordSize: 24, // Smallest record size }) if err != nil { log.Fatal(err) } // Insert IPv4 data networks := []string{ "8.8.8.0/24", "8.8.4.0/24", "1.1.1.0/24", } for _, cidr := range networks { _, network, _ := net.ParseCIDR(cidr) data := mmdbtype.String("DNS") tree.Insert(network, data) } file, err := os.Create("ipv4-compact.mmdb") if err != nil { log.Fatal(err) } defer file.Close() bytesWritten, err := tree.WriteTo(file) if err != nil { log.Fatal(err) } log.Printf("Created compact IPv4 database: %d bytes\n", bytesWritten) } ``` -------------------------------- ### Configuration: Custom Build Timestamp Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/quickstart.md Sets a custom build timestamp for the database using the BuildEpoch option, providing a specific Unix epoch time. ```go import "time" epoch := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC).Unix() tree, _ := mmdbwriter.New(mmdbwriter.Options{ DatabaseType: "Snapshot-2024-01-01", BuildEpoch: epoch, }) ``` -------------------------------- ### Create Multilingual Database Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/quickstart.md Configure a new database writer to support multilingual descriptions by specifying descriptions in multiple languages and the languages to be used. ```go tree, _ := mmdbwriter.New(mmdbwriter.Options{ DatabaseType: "Geo-DB", Description: map[string]string{ "en": "Geographic database", "fr": "Base de données géographique", "de": "Geografische Datenbank", }, Languages: []string{"en", "fr", "de"}, }) ``` -------------------------------- ### Use Custom Merge Strategy Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/options.md Configure the MaxMind DB writer Tree to use a custom merge strategy for conflict resolution during Insert operations. This example uses `inserter.TopLevelMergeWith` to merge top-level map keys instead of replacing them. ```go tree, err := mmdbwriter.New(mmdbwriter.Options{ DatabaseType: "Merged-Data", Inserter: inserter.TopLevelMergeWith, // Merges top-level map keys instead of replacing }) if err != nil { log.Fatal(err) } ``` -------------------------------- ### Main Package Import Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/INDEX.md Imports the main mmdbwriter package for core functionality. ```go import "github.com/maxmind/mmdbwriter" ``` -------------------------------- ### Configuration: IPv4 Only Database Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/quickstart.md Creates a new database specifically for IPv4 addresses by setting the IPVersion option to 4. ```go tree, _ := mmdbwriter.New(mmdbwriter.Options{ DatabaseType: "IPv4-DB", IPVersion: 4, }) ``` -------------------------------- ### Insert Data for an IP Range with Custom Function Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/tree.md Use InsertRangeFunc to insert data for an IP range using a custom insertion function. This allows for dynamic value generation or conflict resolution across the entire range. The range must be valid (start <= end) and IPs must be of the same version. ```go func (t *Tree) InsertRangeFunc(start net.IP, end net.IP, inserterFunc inserter.Func) error ``` ```go start := net.ParseIP("10.0.0.0") end := net.ParseIP("10.255.255.255") err := tree.InsertRangeFunc(start, end, inserter.ReplaceWith(mmdbtype.String("Private"))) if err != nil { log.Fatal(err) } ``` -------------------------------- ### Load MMDB Data with Options Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/INDEX.md Loads MMDB data from a specified path, allowing for custom options during the loading process. ```go mmdbwriter.Load(path, opts) ``` -------------------------------- ### New Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/REFERENCE.md Creates a new Tree for building a MaxMind DB. It allows for custom options to configure the database, such as the database type and IP version. It also handles default settings for build epoch, IPv4 aliasing, reserved networks, key generation, and insertion strategies if not explicitly provided. ```APIDOC ## New ### Description Creates a new Tree for building a MaxMind DB. ### Method func New(opts Options) (*Tree, error) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - `opts Options` — Configuration options ### Return Values - `*Tree` — New tree instance, or nil on error - `error` — Initialization error, or nil on success ### Errors - "unsupported IPVersion: " - Other initialization errors ### Behavior - Sets BuildEpoch to current time if 0 - Enables IPv4 aliasing if IPVersion=6 and DisableIPv4Aliasing=false - Inserts reserved networks if IncludeReservedNetworks=false - Uses default KeyGenerator if not provided - Uses ReplaceWith inserter if not provided ### Example ```go tree, err := mmdbwriter.New(mmdbwriter.Options{ DatabaseType: "MyDB", IPVersion: 6, }) ``` ``` -------------------------------- ### Create a new empty Tree Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/api-overview.md Use this function to initialize an empty mmdbwriter Tree with specified options. ```Go func New(opts Options) (*Tree, error) ``` -------------------------------- ### Insertion Strategies Import Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/INDEX.md Imports the inserter package for custom data merging strategies. ```go import "github.com/maxmind/mmdbwriter/inserter" ``` -------------------------------- ### Including Reserved Networks Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/errors.md Demonstrates how to enable the inclusion of reserved networks during mmdbwriter tree creation, which can prevent ReservedNetworkError. ```Go tree, err := mmdbwriter.New(mmdbwriter.Options{ IncludeReservedNetworks: true, }) ``` -------------------------------- ### Equality Comparison for String and Map Types Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/types.md Shows how to use the Equal() method to compare values of mmdbtype.String and mmdbtype.Map for equality, not reference identity. ```go a := mmdbtype.String("test") b := mmdbtype.String("test") fmt.Println(a.Equal(b)) // true map1 := mmdbtype.Map{"k": mmdbtype.String("v")} map2 := mmdbtype.Map{"k": mmdbtype.String("v")} fmt.Println(map1.Equal(map2)) // true ``` -------------------------------- ### Custom Merge Strategy: Replace (Default) Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/quickstart.md Illustrates the default 'Replace' merge strategy where each insert completely replaces previous data for the same network. ```go // Each insert completely replaces previous data tree, _ := mmdbwriter.New(mmdbwriter.Options{ DatabaseType: "Replace-DB", // Inserter defaults to ReplaceWith }) tree.Insert(net.ParseCIDR("1.0.0.0/8"), mmdbtype.String("First")) tree.Insert(net.ParseCIDR("1.0.0.0/8"), mmdbtype.String("Second")) // Replaces "First" ``` -------------------------------- ### Load Existing Tree Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/tree.md Use the `Load` function to create a Tree from an existing MaxMind DB file. Configuration options can be provided to override metadata from the loaded database. All networks and data are imported into the new Tree. ```go tree, err := mmdbwriter.Load("original.mmdb", mmdbwriter.Options{ DatabaseType: "Enhanced-Database", }) if err != nil { log.Fatal(err) } // Now modify and write the tree ``` -------------------------------- ### Create Basic IPv4 Database Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/options.md Use this snippet to create a new MaxMind DB writer Tree for IPv4 databases. Specify the DatabaseType and IPVersion. ```go tree, err := mmdbwriter.New(mmdbwriter.Options{ DatabaseType: "Country-Database", IPVersion: 4, }) if err != nil { log.Fatal(err) } ``` -------------------------------- ### Insert IP Range Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/quickstart.md Demonstrates inserting a range of IP addresses with associated data into the database. ```go start := net.ParseIP("192.0.2.0") end := net.ParseIP("192.0.2.255") value := mmdbtype.String("Example Network") if err := tree.InsertRange(start, end, value); err != nil { log.Fatal(err) } ``` -------------------------------- ### Import mmdbtype Package Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/types.md Import the necessary package for using MaxMind DB data types. ```go import "github.com/maxmind/mmdbwriter/mmdbtype" ``` -------------------------------- ### Load Existing Database and Create New Tree Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/unmarshaler.md Loads an existing MaxMind DB file and creates a new writer tree with its data. Metadata is inherited from the original database unless explicitly overridden. This is useful for modifying and rewriting existing databases. ```go import ( "github.com/oschwald/maxminddb-golang/v2" "github.com/maxmind/mmdbwriter" "github.com/maxmind/mmdbwriter/mmdbtype" "go4.org/netipx" ) // Load an existing database and create a new tree with its data tree, err := mmdbwriter.Load("original.mmdb", mmdbwriter.Options{ // Metadata is inherited from the original unless overridden }) if err != nil { log.Fatal(err) } // Now you can modify the tree and write it to a new file // ... bytesWritten, err := tree.WriteTo(newFile) ``` -------------------------------- ### Using a Custom KeyGenerator in Tree Constructor Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/keygenerator.md Shows how to provide a custom KeyGenerator instance to the mmdbwriter.New function via the Options struct. ```go customKeyGen := &myKeyGenerator{} tree, _ := mmdbwriter.New(mmdbwriter.Options{ KeyGenerator: customKeyGen, }) // All inserts will use customKeyGen network, _ := net.ParseCIDR("1.1.1.0/24") tree.Insert(network, value) // Uses customKeyGen.Key() ``` -------------------------------- ### Load Existing Database Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/INDEX.md Loads an existing MaxMind DB file into a writer tree. This allows for modification or querying of existing databases. ```go tree, err := mmdbwriter.Load("existing.mmdb", mmdbwriter.Options{}) ``` -------------------------------- ### Include Reserved Networks Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/quickstart.md Create a database writer that allows insertion into private and reserved network ranges by setting the IncludeReservedNetworks option to true. ```go // Allow insertion into private networks tree, _ := mmdbwriter.New(mmdbwriter.Options{ DatabaseType: "Private-DB", IncludeReservedNetworks: true, }) ``` -------------------------------- ### Import mmdbwriter inserter package Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/inserter.md Import the necessary inserter package for MaxMind DB writer functionality. ```go import "github.com/maxmind/mmdbwriter/inserter" ``` -------------------------------- ### Load and Modify an Existing MMDB File Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/api-overview.md Shows how to load an existing MMDB file, modify its contents by inserting new data, and write the changes to a new file. ```go tree, _ := mmdbwriter.Load("original.mmdb", mmdbwriter.Options{}) tree.Insert(net.ParseCIDR("2.2.2.0/24"), mmdbtype.String("new")) file, _ := os.Create("modified.mmdb") tree.WriteTo(file) ``` -------------------------------- ### Handling AliasedNetworkError Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/errors.md Demonstrates how to check for and handle an AliasedNetworkError when inserting networks into an IPv6 tree. ```Go network, _ := net.ParseCIDR("::ffff:0:0/24") err := tree.Insert(network, data) if err != nil { var aliasErr *mmdbwriter.AliasedNetworkError if errors.As(err, &aliasErr) { fmt.Printf("Cannot insert %s (aliased network: %s) ", aliasErr.InsertedNetwork, aliasErr.AliasedNetwork) } } ``` -------------------------------- ### Error Handling for Network Insertions Source: https://github.com/maxmind/mmdbwriter/blob/main/_autodocs/examples.md Demonstrates how to properly handle and distinguish between different error types during network insertions, such as aliased or reserved networks. Use errors.As to check for specific error types like AliasedNetworkError and ReservedNetworkError. ```go package main import ( "errors" "log" "net" "os" "github.com/maxmind/mmdbwriter" "github.com/maxmind/mmdbwriter/mmdbtype" ) func main() { tree, err := mmdbwriter.New(mmdbwriter.Options{ DatabaseType: "Error-Test", }) if err != nil { log.Fatal(err) } testNetworks := []string{ "1.1.1.0/24", "192.168.0.0/16", // Reserved by default "::ffff:0:0/96", // Aliased in IPv6 tree } for _, cidr := range testNetworks { _, network, err := net.ParseCIDR(cidr) if err != nil { log.Printf("Parse error for %s: %v\n", cidr, err) continue } err = tree.Insert(network, mmdbtype.String("test")) var aliasErr *mmdbwriter.AliasedNetworkError var reservedErr *mmdbwriter.ReservedNetworkError switch { case errors.As(err, &aliasErr): log.Printf("Network %s is aliased\n", cidr) log.Printf(" Aliased network: %s\n", aliasErr.AliasedNetwork) log.Printf(" Attempted insert: %s\n", aliasErr.InsertedNetwork) case errors.As(err, &reservedErr): log.Printf("Network %s is reserved\n", cidr) log.Printf(" Reserved network: %s\n", reservedErr.ReservedNetwork) log.Printf(" Attempted insert: %s\n", reservedErr.InsertedNetwork) case err != nil: log.Printf("Error inserting %s: %v\n", cidr, err) default: log.Printf("Successfully inserted %s\n", cidr) } } file, err := os.Create("error-test.mmdb") if err != nil { log.Fatal(err) } defer file.Close() if _, err := tree.WriteTo(file); err != nil { log.Fatal(err) } } ```