ip2country

package module
v0.1.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 2, 2025 License: MIT Imports: 14 Imported by: 0

README

ip2country

Go Report Card Go Reference

🇷🇺 Read in Russian

A fast and efficient Go library for IP to country lookup.

This package is designed to work with the free IP-to-Country CSV database from DB-IP. It parses the start_ip,end_ip,country_code format and provides a fast, thread-safe interface for lookups.

Features
  • High Performance: Uses binary search on a sorted range list for quick lookups (IPCountryDB).
  • Two Strategies:
    • IPCountryDB: Ideal for large, contiguous IP range datasets.
    • ExactIPCountryMap: Optimized for specific, non-contiguous IP-to-country mappings.
  • Thread-Safe: Designed for concurrent use in high-load services.
  • LRU Cache: Built-in cache to dramatically speed up repeated lookups for the same IPs.
  • On-Demand Reloading: The database can be reloaded at runtime without service interruption.
  • Zero Dependencies: Relies only on the Go standard library.
Installation
go get -u github.com/byteonabeach/ip2country
Example Usage

Here is a complete example of how to use IPCountryDB.

1. Prepare your data file (ip_to_country.csv)

Download the CSV from DB-IP or create a file with the following format:

1.0.0.0,1.0.0.255,AU
1.0.1.0,1.0.3.255,CN
1.0.4.0,1.0.7.255,AU
1.0.8.0,1.0.15.255,CN
8.8.8.0,8.8.8.255,US

2. Write your test Go script

// main.go
package main

import (
	"fmt"
	"log"

	"github.com/byteonabeach/ip2country"
)

func main() {
	// Initialize the database with the path to your CSV file.
	// The data is loaded on the first lookup.
	db := ip2country.NewIPCountryDB("ip_to_country.csv")

	// --- Test IPs ---
	ipsToTest := []string{
		"1.0.1.15",    // Should be CN
		"8.8.8.8",     // Should be US
		"1.0.5.100",   // Should be AU
		"127.0.0.1",   // Should be ZZ (special range)
	}

	fmt.Println("--- Looking up country codes ---")
	for _, ip := range ipsToTest {
		// GetCountryCode is the primary method for lookup.
		code, err := db.GetCountryCode(ip)
		if err != nil {
			log.Printf("Error looking up %s: %v", ip, err)
		} else {
			fmt.Printf("Country Code for %s is: %s\n", ip, code)
		}
	}

	// You can also get stats about the loaded data
	stats := db.Stats()
	fmt.Printf("\n--- DB Stats ---\n")
	fmt.Printf("Total Ranges: %d\n", stats.TotalRanges)
	fmt.Printf("Load Time: %s\n", stats.LoadTime)
	fmt.Printf("Cache Hits: %d, Cache Misses: %d\n", stats.CacheHits, stats.CacheMisses)
}

3. Run the code

go run main.go

Expected Output:

--- Looking up country codes ---
Country Code for 1.0.1.15 is: CN
Country Code for 8.8.8.8 is: US
Country Code for 1.0.5.100 is: AU
Country Code for 127.0.0.1 is: ZZ

--- DB Stats ---
Total Ranges: 342632
Load Time: 148.7ms
Cache Hits: 0, Cache Misses: 4
To-Do / Future Plans
  • IPv6 Support: Add the ability to parse and look up IPv6 ranges.
  • More Data Sources: Add parsers for other popular formats (e.g., MaxMind GeoLite2).
  • Benchmarks: Implement a comprehensive set of benchmarks to track performance.
  • CLI Tool: Create a simple command-line utility for quick lookups from the terminal.
  • More Config Options: Add more flexible configuration, for example, for the LRU cache behavior.

Documentation

Overview

Package ip2country provides fast and efficient IP to country lookup. It supports two lookup methods:

  1. IPCountryDB: A range-based lookup database, efficient for large datasets representing the entire IP address space. It loads a CSV file and uses a binary search for lookups.

  2. ExactIPCountryMap: An exact-match lookup map, suitable for smaller datasets where each IP address is mapped directly to a country code.

The recommended data source for IPCountryDB is the free IP-to-Country CSV database from DB-IP: https://db-ip.com/db/format/ip-to-country/csv.html This package is designed to parse its specific format: start_ip,end_ip,country_code

Both implementations feature thread-safe operations, an in-memory LRU cache to speed up repeated lookups, and on-demand reloading of the dataset.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ValidateIPRanges

func ValidateIPRanges(ranges []IPRange) error

ValidateIPRanges checks a slice of IPRange for validity and overlaps. It sorts the ranges by StartIP and then ensures that no two ranges overlap and that each individual range is valid.

Types

type Config

type Config struct {
	// Delimiter specifies the character used to separate fields in the CSV file.
	Delimiter string
	// MaxFileSize limits the size of the file to be loaded, preventing excessive memory usage.
	// The value is in bytes. A value of 0 or less means no limit.
	MaxFileSize int64
	// MaxRanges sets the maximum number of IP ranges or entries to load from the file.
	// A value of 0 or less means no limit.
	MaxRanges int
	// CacheSize defines the number of entries to keep in the LRU cache.
	// If set to 0 or less, a default value will be used.
	CacheSize int
	// SkipHeader indicates whether the first line of the CSV file should be skipped.
	SkipHeader bool
}

Config holds configuration parameters for the IP lookup databases. Fields are ordered for optimal memory alignment.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns a new Config with sensible default values.

type ExactIPCountryMap

type ExactIPCountryMap struct {
	// contains filtered or unexported fields
}

ExactIPCountryMap implements the IPCountryLookup interface using a map for exact IP matches. This is suitable for datasets where specific IPs are mapped to countries, rather than ranges. It expects a CSV format of: ip,country_code

func NewExactIPCountryMap

func NewExactIPCountryMap(filePath string, config ...Config) *ExactIPCountryMap

NewExactIPCountryMap creates a new instance of ExactIPCountryMap. The data is not loaded until the first lookup or an explicit call to Reload.

func (*ExactIPCountryMap) GetCountry

func (m *ExactIPCountryMap) GetCountry(ipStr string) (string, error)

GetCountry retrieves the country code for a given IP address string.

func (*ExactIPCountryMap) GetCountryCode

func (m *ExactIPCountryMap) GetCountryCode(ipStr string) (string, error)

GetCountryCode retrieves the country code for a given IP address string.

func (*ExactIPCountryMap) GetCountryCodeWithContext

func (m *ExactIPCountryMap) GetCountryCodeWithContext(ctx context.Context, ipStr string) (string, error)

GetCountryCodeWithContext retrieves the country code, respecting the context.

func (*ExactIPCountryMap) GetCountryWithContext

func (m *ExactIPCountryMap) GetCountryWithContext(ctx context.Context, ipStr string) (string, error)

GetCountryWithContext retrieves the country code, respecting the context.

func (*ExactIPCountryMap) GetParseErrors

func (m *ExactIPCountryMap) GetParseErrors() []ParseError

GetParseErrors returns any errors that occurred during the last load/reload.

func (*ExactIPCountryMap) Reload

func (m *ExactIPCountryMap) Reload() error

Reload clears the current dataset and loads it again from the source file.

func (*ExactIPCountryMap) ReloadWithContext

func (m *ExactIPCountryMap) ReloadWithContext(ctx context.Context) error

ReloadWithContext reloads the dataset, respecting the context for cancellation.

func (*ExactIPCountryMap) Stats

func (m *ExactIPCountryMap) Stats() Stats

Stats returns the current operational statistics of the map.

type IPCountryDB

type IPCountryDB struct {
	// contains filtered or unexported fields
}

IPCountryDB implements the IPCountryLookup interface using a sorted list of IP ranges. It is optimized for lookups using binary search and is protected by a mutex for concurrent access.

func NewIPCountryDB

func NewIPCountryDB(filePath string, config ...Config) *IPCountryDB

NewIPCountryDB creates a new instance of IPCountryDB. The database is not loaded until the first lookup or an explicit call to Reload. It accepts an optional Config; if not provided, DefaultConfig() is used.

func (*IPCountryDB) GetCountry

func (db *IPCountryDB) GetCountry(ipStr string) (string, error)

GetCountry retrieves the country code for a given IP address string.

func (*IPCountryDB) GetCountryCode

func (db *IPCountryDB) GetCountryCode(ipStr string) (string, error)

GetCountryCode retrieves the country code for a given IP address string.

func (*IPCountryDB) GetCountryCodeWithContext

func (db *IPCountryDB) GetCountryCodeWithContext(ctx context.Context, ipStr string) (string, error)

GetCountryCodeWithContext retrieves the country code, respecting the context.

func (*IPCountryDB) GetCountryWithContext

func (db *IPCountryDB) GetCountryWithContext(ctx context.Context, ipStr string) (string, error)

GetCountryWithContext retrieves the country code, respecting the context.

func (*IPCountryDB) Reload

func (db *IPCountryDB) Reload() error

Reload clears the current dataset and loads it again from the source file.

func (*IPCountryDB) ReloadWithContext

func (db *IPCountryDB) ReloadWithContext(ctx context.Context) error

ReloadWithContext reloads the dataset, respecting the context for cancellation.

func (*IPCountryDB) Stats

func (db *IPCountryDB) Stats() Stats

Stats returns the current operational statistics of the database.

type IPCountryLookup

type IPCountryLookup interface {
	// GetCountry retrieves the country code for a given IP address string.
	// In the current implementation, this returns the same value as GetCountryCode.
	GetCountry(ipStr string) (string, error)
	// GetCountryCode retrieves the country code (e.g., "US") for a given IP address string.
	GetCountryCode(ipStr string) (string, error)
	// GetCountryWithContext retrieves the country code, respecting the context.
	GetCountryWithContext(ctx context.Context, ipStr string) (string, error)
	// GetCountryCodeWithContext retrieves the country code, respecting the context.
	GetCountryCodeWithContext(ctx context.Context, ipStr string) (string, error)
	// Stats returns the current operational statistics of the database.
	Stats() Stats
	// Reload clears the current dataset and loads it again from the source file.
	Reload() error
	// ReloadWithContext reloads the dataset, respecting the context for cancellation.
	ReloadWithContext(ctx context.Context) error
}

IPCountryLookup defines the interface for IP to country lookup services. It provides methods to get country information from an IP address string.

type IPRange

type IPRange struct {
	// Country is the country code (e.g., US, DE).
	Country string `json:"country"`
	// Code is the two-letter country code.
	Code string `json:"code"`
	// StartIP is the starting IP address of the range, as a 32-bit unsigned integer.
	StartIP uint32 `json:"start_ip"`
	// EndIP is the ending IP address of the range, as a 32-bit unsigned integer.
	EndIP uint32 `json:"end_ip"`
}

IPRange represents a continuous range of IP addresses belonging to a single country. Fields are ordered for optimal memory alignment.

func (IPRange) Contains

func (r IPRange) Contains(ip uint32) bool

Contains checks if a given IP address (as a uint32) is within the range.

func (IPRange) Validate

func (r IPRange) Validate() error

Validate checks if the IPRange is valid. A range is valid if the start IP is not greater than the end IP and the code is not empty.

type ParseError

type ParseError struct {
	// Content is the actual content of the line that caused the error.
	Content string
	// Err is the underlying error.
	Err error
	// Line is the line number where the error occurred.
	Line int
}

ParseError represents an error that occurred while parsing a line from the data file. Fields are ordered for optimal memory alignment.

func (ParseError) Error

func (e ParseError) Error() string

Error returns a string representation of the ParseError.

type ParseResult

type ParseResult struct {
	// Ranges is the slice of successfully parsed IP ranges.
	Ranges []IPRange
	// Errors is a slice of errors encountered during parsing.
	Errors []ParseError
	// Stats contains statistics about the parsing process.
	Stats Stats
}

ParseResult holds the outcome of a file parsing operation.

func ParseCSVRanges

func ParseCSVRanges(filePath string, config ...Config) (*ParseResult, error)

ParseCSVRanges is a utility function that parses a CSV file containing IP ranges without creating a full DB instance. It's useful for pre-validating or inspecting data.

type Stats

type Stats struct {
	// LastUpdate is the timestamp of the last successful data load or reload.
	LastUpdate time.Time `json:"last_update"`
	// LoadTime is the duration it took to load the dataset.
	LoadTime time.Duration `json:"load_time"`
	// FileSize is the size of the source data file in bytes.
	FileSize int64 `json:"file_size"`
	// CacheHits is the number of times a lookup was served from the cache.
	CacheHits int64 `json:"cache_hits"`
	// CacheMisses is the number of times a lookup was not found in the cache.
	CacheMisses int64 `json:"cache_misses"`
	// TotalRanges is the number of IP ranges or entries currently loaded.
	TotalRanges int `json:"total_ranges"`
}

Stats provides operational statistics for an IP lookup database. Fields are ordered for optimal memory alignment.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL