netip
Zero-dependency Rust library for IPv4/IPv6 networks and MAC addresses — with first-class support for non-contiguous subnet masks.
Why netip?
Most networking libraries assume subnet masks are contiguous (a run of 1-bits followed by 0-bits, like 255.255.255.0). Real-world network hardware — routers, firewalls, packet classifiers — often uses non-contiguous masks like 255.0.255.0 or even 170.85.170.85 to match on arbitrary bit patterns.
netip treats every network as a (address, mask) pair where the mask can be any bit pattern. All operations — containment, intersection, difference, iteration — work correctly with non-contiguous masks.
If your masks happen to be contiguous, the Contiguous<T> wrapper gives you a compile-time guarantee and CIDR prefix access.
Key features
- Non-contiguous mask support — the only open-source Rust library that handles arbitrary subnet masks
- Full set algebra —
contains,intersection,difference,merge,is_adjacenton networks as sets of addresses - Correct iteration — iterate over addresses in a non-contiguous network in host-index order
- Zero dependencies — only
core, nothing else - Performance-first —
const fnwhere possible,#[inline]on hot paths, minimal instruction count - Type-safe —
Contiguous<T>enforces contiguous masks at parse time; mismatched IPv4/IPv6 operations are compile errors
Quick start
Add to your Cargo.toml:
[]
= "0.3"
Parsing and basic operations
use ;
// Standard CIDR notation.
let net: Ipv4Network = parse.unwrap;
assert_eq!;
// Dotted-mask notation — including non-contiguous masks.
let net = parse.unwrap;
assert!;
// IpNetwork parses both IPv4 and IPv6.
let net: IpNetwork = parse.unwrap;
Set operations on networks
Networks are sets of addresses. netip gives you the algebra:
use Ipv4Network;
let a = parse.unwrap;
let b = parse.unwrap;
// Containment: is every address in b also in a?
assert!;
// Intersection: the set of addresses in both networks.
let ab = a.intersection.unwrap;
assert_eq!;
// Difference: addresses in a but not in b — returns an iterator of networks.
for net in a.difference
Non-contiguous masks in action
This is where netip shines. Non-contiguous masks let you express bit-pattern matching that CIDR cannot:
use Ipv4Network;
// Match all addresses where the first and third octets are 10 and 0.
// Second and fourth octets can be anything.
let pattern = parse.unwrap;
let specific = parse.unwrap;
assert!; // 10.42.0.99 matches 10.*.0.*
// Intersection of two non-contiguous networks — always a single network.
let a = parse.unwrap;
let b = parse.unwrap;
let ab = a.intersection.unwrap;
assert_eq!;
// Iterate over all addresses in a non-contiguous network.
let small = parse.unwrap;
let addrs: = small.addrs.collect;
assert_eq!;
Contiguous wrapper
When you need the CIDR guarantee, Contiguous<T> enforces it at parse time:
use Contiguous;
use Ipv4Network;
let net: = parse.unwrap;
assert_eq!; // guaranteed to succeed — no Option
// Non-contiguous mask is rejected at parse time.
assert!;
// Contiguous<T> derefs to T — all network methods are available.
assert!;
MAC addresses
use MacAddr;
let mac = parse.unwrap;
assert_eq!;
Types
| Type | Description |
|---|---|
Ipv4Network |
IPv4 network — (address, mask) pair, arbitrary masks |
Ipv6Network |
IPv6 network — (address, mask) pair, arbitrary masks |
IpNetwork |
Enum over Ipv4Network / Ipv6Network |
Contiguous<T> |
Newtype that enforces contiguous masks at parse time |
MacAddr |
MAC address (EUI-48), stored as lower 48 bits of u64 |
Roadmap
netip is on the path to a stable 1.0. Current version: 0.3.0.
v0.3 — API cleanup:✓#[must_use],#[deny(missing_docs)]- v0.4 — Complete set algebra:
complement,Contiguous<T>merge/adjacent - v0.5 — Testing hardening: fuzz targets, exhaustive non-contiguous edge cases
- v0.6+ — Documentation polish, API review, CHANGELOG
- v1.0 — Stable release
License
Apache-2.0