Skip to content

roniemartinez/IPToCC

Repository files navigation

IPToCC

CI crates.io PyPI npm Python Rust License All Contributors

Fast, offline IPv4/IPv6 to ISO 3166-1 alpha-2 country code lookup. One Rust core with Python and WASM bindings, plus a CLI.

Important

iptocc 3.0 is a complete Rust rewrite. Versions 2.x and earlier were pure Python on top of pandas. 3.x is a standalone Rust crate with Python and WASM bindings. The Python public API stays compatible for most uses (see Migrating from 2.x).

Note

Country codes reflect the country assigned by a Regional Internet Registry (RIR) to each IP block, not where the block is being used. RIR data agrees with MaxMind for ~95% of IPv4 addresses and has minimal discrepancies for IPv6 (Zander, 2012).

Features

  • Offline lookup, no external API calls.
  • IPv4 and IPv6 in a single call.
  • Accepts a single address or a batch of addresses.
  • Lookup data embedded in the binary; no runtime file I/O.
  • ~1-13 ns on native Rust (typed input); ~44-141 ns through Python, ~200-300 ns through WASM.
  • iptocc CLI installed via pip, cargo, or npm.
  • Data refreshed nightly from the five Regional Internet Registries.

Install

Python (3.10 or newer)

pip install iptocc

Rust

cargo add iptocc         # library
cargo install iptocc     # CLI binary

Node, browser, Deno, bundlers

npm install @roniemartinez/iptocc

Usage

Python

from iptocc import country_code

# Single lookup
country_code("8.8.8.8")                # "US"
country_code("2001:4860:4860::8888")   # "US"
country_code("10.0.0.0")               # None

# Batch lookup (any iterable of strings)
country_code(["8.8.8.8", "1.0.16.1", "10.0.0.0"])
# ["US", "JP", None]

Rust

use iptocc::{country_code, country_codes};

let cc = country_code("8.8.8.8");
assert_eq!(cc, Some("US"));

let codes = country_codes(["8.8.8.8", "1.0.16.1", "10.0.0.0"]);
assert_eq!(codes, vec![Some("US"), Some("JP"), None]);

Node

const { country_code } = require("@roniemartinez/iptocc");

country_code("8.8.8.8");                     // "US"
country_code(["8.8.8.8", "1.0.16.1"]);       // ["US", "JP"]

CLI

$ iptocc 8.8.8.8
US

$ iptocc 8.8.8.8 1.0.16.1 10.0.0.0 193.0.6.139
8.8.8.8 US
1.0.16.1 JP
10.0.0.0 -
193.0.6.139 NL

Comparison with ip_to_country

Compared below against ip_to_country and the legacy iptocc 2.x line.

Features

Feature iptocc 2.x (legacy) ip_to_country iptocc 3.x
IPv4
IPv6
Offline lookup
Batch API
CLI
Python
Rust
WASM
Nightly data refresh

Performance

Apple M3 Pro, per-call latency on a single v4 hit. time.perf_counter() for Python, Criterion for the Rust core.

Library 1 lookup vs baseline
ip_to_country (Python bisect) ~1.2 us 1x
iptocc 2.1.2 (legacy, pandas filter) ~78 ms ~65,000x slower
iptocc 3.x Python ~100 ns ~12x faster
iptocc Rust ~1.3 ns ~900x faster

The 2.1.2 row is for historical context. The Python binding gets most of the way to the Rust core's speed; the remaining gap is per-call FFI overhead.

See BENCHMARK.md for the full per-RIR breakdown and the Rust-core / WASM numbers.

Migrating from 2.x

The legacy iptocc.get_country_code(ip) is now iptocc.country_code(ip). The return value is still str | None on a hit or miss.

# 2.x
from iptocc import get_country_code, CountryCodeNotFound
try:
    cc = get_country_code("8.8.8.8")
except CountryCodeNotFound:
    cc = None

# 3.x
from iptocc import country_code
cc = country_code("8.8.8.8")  # returns None on miss, no exception

Data sources

Lookups are based on the delegated extended statistics published by the five Regional Internet Registries:

RIR URL
AFRINIC https://ftp.afrinic.net/stats/afrinic/delegated-afrinic-extended-latest
ARIN https://ftp.arin.net/pub/stats/arin/delegated-arin-extended-latest
APNIC https://ftp.apnic.net/public/apnic/stats/apnic/delegated-apnic-extended-latest
LACNIC https://ftp.lacnic.net/pub/stats/lacnic/delegated-lacnic-extended-latest
RIPE NCC https://ftp.ripe.net/pub/stats/ripencc/delegated-ripencc-extended-latest

A nightly GitHub Action fetches fresh data, rebuilds the lookup tables, and publishes new releases automatically.

References

Contributors ✨

Thanks goes to these wonderful people (emoji key):

Ronie Martinez
Ronie Martinez

💻 📖 🚇 🚧 👀
Tate Barber
Tate Barber

💻 📖 🚇
mathgeek12
mathgeek12

🐛
James Dolan
James Dolan

🤔

This project follows the all-contributors specification. Contributions of any kind welcome!

About

Get country code of IPv4/IPv6 address. Address lookup is done offline.

Topics

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Packages

 
 
 

Contributors