Documentation
¶
Overview ¶
Package cidr provides fast, immutable IPv4/IPv6 lookups over a set of CIDR prefixes, built once and queried concurrently with zero per-query allocation.
Two structures cover the two questions callers ask:
Set answers membership — "is this address in any added prefix?" (yes/no). Overlapping prefixes are merged, so it is the smallest, fastest form.
Table[V] answers value lookup — "what value is attached to the most specific prefix covering this address?" (yes + data). It resolves nested prefixes into disjoint segments at build time (longest-prefix match), so a query is a single binary search that returns the value directly.
Both are backed by sorted, contiguous arrays of net/netip addresses: no pointer-chasing, no interface dispatch, and a flat memory layout that serialises trivially. For the static, build-once-query-many workloads this package targets — blocklists, allowlists, IP-to-ASN and geo tables — a sorted range array is both faster and an order of magnitude smaller than a prefix trie; see docs/architecture.md for the measurements and the trade-off.
The package has no dependency beyond the Go standard library.
Build with a Builder / TableBuilder, then Freeze to an immutable value:
b := cidr.NewBuilder()
b.AddPrefix("192.0.2.0/24")
set := b.Freeze()
set.Contains(netip.MustParseAddr("192.0.2.10")) // true
Index ¶
- func AppendRangePrefixes(dst []netip.Prefix, lo, hi netip.Addr) []netip.Prefix
- func BuildASN(entries []SpecEntry) (*Set, *Table[Info])
- func DecodeASN(v uint64) (asn uint32, orgID uint32, flags uint8)
- func EncodeASN(asn uint32, orgID uint32, flags uint8) uint64
- func LoadASN(r io.Reader) (*Set, *Table[Info], error)
- func LoadRefsASN(r io.Reader) (*Set, *Table[Info], error)
- func ParsePrefix(s string) (netip.Prefix, error)
- func RangePrefixes(lo, hi netip.Addr) []netip.Prefix
- type Builder
- type Info
- type MMDB
- type Refs
- type Set
- type SpecEntry
- type Table
- type TableBuilder
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AppendRangePrefixes ¶
AppendRangePrefixes appends the minimal CIDR cover of [lo, hi] to dst and returns the extended slice, reusing dst's capacity. Use it in hot loops (folding millions of ranges) to avoid a fresh allocation per call; RangePrefixes is the dst==nil convenience wrapper.
func BuildASN ¶ added in v0.1.3
BuildASN compiles already-parsed entries into a membership Set plus an LPM value Table[Info] in one pass — the "entries → Set + Table" step LoadASN wraps, exported so a caller that parsed the entries itself (to count or filter them first) can build both without re-parsing.
func EncodeASN ¶
EncodeASN packs an autonomous-system answer into a uint64:
bits [31:0] ASN full 4-byte ASN space bits [55:32] org id (24) index into a caller-side []string (16.7M orgs) bits [63:56] flags (8) caller-defined (e.g. bogon / anycast / rir)
It is the compact "encoded uint64" value for a Table[uint64]; DecodeASN recovers the fields, and the org id can index a side table for the full name.
func LoadASN ¶
LoadASN reads a spec from r and compiles both a membership Set (yes/no) and an LPM value Table[Info] (yes+data). One pass builds both, so a caller can answer "is this address listed?" and "which AS/org owns it?" from the same input.
func LoadRefsASN ¶
LoadRefsASN reads a refs JSON envelope and compiles a membership Set plus an LPM value Table[Info] — the JSON analogue of LoadASN.
func ParsePrefix ¶
ParsePrefix parses "10.0.0.0/8" or "2001:db8::/32", or a bare address ("1.2.3.4", "::1") promoted to a host route (/32 or /128). The returned prefix is masked to its network address.
func RangePrefixes ¶
RangePrefixes decomposes the inclusive interval [lo, hi] into the minimal, ordered set of CIDR prefixes that exactly cover it (the standard range-to-CIDR split). It returns nil for an invalid range: mismatched families or hi < lo.
Types ¶
type Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
Builder accumulates prefixes for a Set. Not safe for concurrent use.
func (*Builder) AddPrefix ¶
AddPrefix parses s (a CIDR or bare address, see ParsePrefix) and adds it, returning any parse error.
func (*Builder) AddRange ¶
AddRange adds the inclusive address interval [lo, hi] to the membership set. Both ends must be the same family and lo <= hi; an invalid range is ignored. This is the natural entry point for range-based feeds (start/end columns) such as iptoasn.com or the RIR delegated files.
type Info ¶
type Info struct {
Prefix string `json:"prefix"`
ASN uint32 `json:"asn,omitempty"`
Org string `json:"org,omitempty"`
}
Info is the value attached to a prefix loaded from a spec: the origin AS number and organisation name, alongside the matched prefix in CIDR form. It is the value type of the Table that LoadASN builds, and encodes to compact JSON for the service examples.
type MMDB ¶ added in v0.1.3
type MMDB struct {
// contains filtered or unexported fields
}
MMDB is an opened MaxMind DB held in memory, safe for concurrent lookups.
func OpenMMDBBytes ¶ added in v0.1.3
OpenMMDBBytes parses an in-memory MaxMind DB. The slice is retained (not copied) and must not be mutated while the MMDB is in use.
func (*MMDB) Close ¶ added in v0.1.3
Close is a no-op: the database is a plain in-memory buffer, reclaimed by GC once the MMDB is unreferenced. It exists for API symmetry (and a future mmap backend) and does NOT release the buffer, so it is safe to call concurrently with in-flight Lookups.
type Refs ¶
type Refs struct {
Name string `json:"name"`
Version int `json:"version"` // yyyymmdd
List []string `json:"list"`
}
Refs is the common refs resource envelope — a named, versioned list of spec lines — as published at refs.netstar.dev and similar feeds:
{"name": "parked", "version": 20260705, "list": ["1.2.3.0/24", ...]}
Each list entry uses the same grammar as a ParseSpec line ("<cidr> [ASN] [org...]"), so a bare CIDR list and an IP-to-ASN list are both valid bodies.
type Set ¶
type Set struct {
// contains filtered or unexported fields
}
Set is an immutable IPv4/IPv6 membership set. The zero Set is a valid empty set. Safe for concurrent use once built.
func LoadRefsSet ¶
LoadRefsSet reads a refs JSON envelope and compiles a membership Set — the JSON analogue of LoadSet.
func LoadSet ¶
LoadSet reads a spec (or a plain CIDR list) from r and compiles a membership Set, ignoring any ASN/org fields.
type SpecEntry ¶
SpecEntry is one parsed spec line.
type Table ¶
type Table[V any] struct { // contains filtered or unexported fields }
Table is an immutable IPv4/IPv6 longest-prefix-match table returning a value V (e.g. an ASN, an org name, or an encoded uint64). Nesting is resolved at build time into disjoint segments, so Lookup is one binary search with no allocation. The zero Table is a valid empty table. Safe for concurrent use once built.
func LoadFunc ¶
func LoadFunc[V any](r io.Reader, parse func(fields []string) (netip.Prefix, V, bool)) (*Table[V], error)
LoadFunc reads a line-oriented stream and builds a Table[V], delegating the format to the caller: parse maps a line's whitespace-separated fields to a prefix and value, returning ok=false to skip the line. Blank lines and '#'-comments are dropped before parse is called. This is the generic loader for any "<cidr-or-prefix> <data...>" feed whose value is not an ASN — see the user guide for a worked example.
type TableBuilder ¶
type TableBuilder[V any] struct { // contains filtered or unexported fields }
TableBuilder accumulates (prefix, value) pairs for a Table. Not safe for concurrent use.
func NewTableBuilder ¶
func NewTableBuilder[V any]() *TableBuilder[V]
NewTableBuilder returns an empty value-table builder.
func (*TableBuilder[V]) Add ¶
func (b *TableBuilder[V]) Add(p netip.Prefix, v V)
Add attaches value v to prefix p (masked to its network). When prefixes nest, the longest (most specific) one wins at lookup time. Adding the same prefix more than once keeps the most recently added value.
func (*TableBuilder[V]) AddPrefix ¶
func (b *TableBuilder[V]) AddPrefix(s string, v V) error
AddPrefix parses s (a CIDR or bare address, see ParsePrefix) and adds it with value v, returning any parse error.
func (*TableBuilder[V]) AddRange ¶
func (b *TableBuilder[V]) AddRange(lo, hi netip.Addr, v V)
AddRange attaches value v to the inclusive interval [lo, hi]. The range is decomposed into its minimal set of CIDR prefixes, each carrying v, so longest-prefix match stays well defined: a more-specific range's pieces have longer masks and win over a covering one. An invalid range is ignored.
func (*TableBuilder[V]) Freeze ¶
func (b *TableBuilder[V]) Freeze() *Table[V]
Freeze compiles the accumulated prefixes into an immutable Table.
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
cidr
command
Command cidr looks up IP addresses against a CIDR/ASN spec: membership (yes/no) and the owning AS/org via longest-prefix match.
|
Command cidr looks up IP addresses against a CIDR/ASN spec: membership (yes/no) and the owning AS/org via longest-prefix match. |
|
ipfold
command
Command ipfold reads an unorganized list of IP addresses (mixed IPv4/IPv6, one per line), sorts and de-duplicates them, and folds runs of consecutive addresses into the minimal set of CIDR prefixes — e.g.
|
Command ipfold reads an unorganized list of IP addresses (mixed IPv4/IPv6, one per line), sorts and de-duplicates them, and folds runs of consecutive addresses into the minimal set of CIDR prefixes — e.g. |
|
iptoasn
command
Command iptoasn fetches the iptoasn.com IP-to-ASN table, converts each start/end address range to its minimal set of CIDR prefixes, and writes cidr spec lines.
|
Command iptoasn fetches the iptoasn.com IP-to-ASN table, converts each start/end address range to its minimal set of CIDR prefixes, and writes cidr spec lines. |
|
mm-dbip
command
Command mm-dbip converts a DB-IP Lite database (db-ip.com, CC BY 4.0) to the cidr spec format.
|
Command mm-dbip converts a DB-IP Lite database (db-ip.com, CC BY 4.0) to the cidr spec format. |
|
mm-geolite2-asn
command
Command mm-geolite2-asn converts the MaxMind GeoLite2 ASN database to the cidr spec format — "<cidr> <ASN> <org>" per line — that LoadASN reads back.
|
Command mm-geolite2-asn converts the MaxMind GeoLite2 ASN database to the cidr spec format — "<cidr> <ASN> <org>" per line — that LoadASN reads back. |
|
mmdb-build-countries
command
Command mmdb-build-countries builds the cmd/mmdb-write/data/countries.json nomenclature file from Wikidata.
|
Command mmdb-build-countries builds the cmd/mmdb-write/data/countries.json nomenclature file from Wikidata. |
|
example
|
|
|
http
command
Command http exposes a cidr set over a small HTTP REST API: membership (yes/no) and value lookup (yes+data, the owning AS/org), for single addresses and newline-batched streams.
|
Command http exposes a cidr set over a small HTTP REST API: membership (yes/no) and value lookup (yes+data, the owning AS/org), for single addresses and newline-batched streams. |
|
library
command
Command library is a runnable tour of the cidr package used directly: a membership Set (yes/no), a value Table returning a struct (yes+data), the same lookup returning a compact encoded uint64, longest-prefix match over a nested block, and IPv6 — all from one in-memory spec.
|
Command library is a runnable tour of the cidr package used directly: a membership Set (yes/no), a value Table returning a struct (yes+data), the same lookup returning a compact encoded uint64, longest-prefix match over a nested block, and IPv6 — all from one in-memory spec. |
|
mcp
command
Command mcp is a Model Context Protocol server that exposes a cidr set as tools an LLM agent can call.
|
Command mcp is a Model Context Protocol server that exposes a cidr set as tools an LLM agent can call. |
|
unix
command
Command unix serves a cidr set over a Unix domain socket as a line protocol: send one address per line, read back one NDJSON result per line (membership plus the owning AS/org when present).
|
Command unix serves a cidr set over a Unix domain socket as a line protocol: send one address per line, read back one NDJSON result per line (membership plus the owning AS/org when present). |