swift-cidr

0.7.1

Value-semantic Swift types for IP addresses, networks, prefixes, endpoints, and CIDR math.
RouteObjects/swift-cidr

What's New

swift-cidr 0.7.1

2026-09-16T15:54:54Z

IPv6 literal validation

swift-cidr 0.7.1 corrects three IPv6 text-validation defects in the shared parser. Malformed input that previously parsed successfully is now rejected; valid addresses retain their existing values, formatting, and prefix context.

The parser now rejects:

  • Hextets longer than four hexadecimal digits, including zero-padded values whose numeric value fits in 16 bits, such as 00000::1.
  • A terminal single colon, such as 1:2:3:4:5:6:7:8: or ::1:.
  • A double colon that compresses no words, such as 1:2:3:4:5:6:7:8::. An embedded IPv4 tail contributes two words to this validation.

These checks follow RFC 4291 section 2.2 and apply through the existing shared parser to concrete and mixed-family addresses and networks, CIDR-qualified text, range endpoints, Codable decoding, and CIDRArgumentParser conversions, including bracketed IPv6 endpoints.

Valid compression, including exactly one omitted word, remains supported. IPv4-mapped IPv6 remains IPv6. Existing decimal leading-zero IPv4-octet acceptance is unchanged, including mixed IPv6 notation.

Compatibility

No public declarations, dependencies, signatures, stored layout, or availability have changed. Swift 6.2 remains the minimum toolchain; deployment floors remain macOS 15 and iOS 18.

Integer-backed identity, CIDR math, formatting, and valid-input Codable behavior are unchanged. Previously accepted malformed IPv6 strings now return nil from failable parsers, throw decoding errors through Codable, or fail argument parsing.

Consumers requiring this correction should declare 0.7.1 as their minimum version, rather than relying only on a resolved-file pin.

Validation

  • 225 tests across 23 suites passed on macOS Swift 6.3.3 and Linux Swift 6.2.4/6.3.3.
  • All four targets built at the macOS 15 and iOS 18 simulator deployment floors; the public API comparison against 0.7.0 reports no breaking changes.
  • All six focused parser benchmark thresholds pass unchanged; sampled allocation and ARC metrics remained zero before and after. No threshold recalibration or cross-machine speed claim.
  • The correction was integrated through PR #14, preserving the reviewed SSH-signed commit.
  • All five manual CI jobs passed on the merged release commit, including the benchmark-target build.
  • A clean consumer resolved the public 0.7.1 tag and passed malformed-input rejection and valid-address preservation checks; repeated resolution kept its lockfile stable.

These are parser correctness fixes; no exploit or downstream security impact has been established.

Full changelog: 0.7.0...0.7.1

swift-cidr icon  CIDR

CIDR provides value-semantic Swift types for classless Internet Protocol addressing and related routing identifiers: addresses, prefix lengths, networks, exact address ranges and coverage sets, endpoints, and Autonomous System numbers that need stable modeling across routing, addressing, policy, validation, configuration, server, and POSIX boundaries.

Although an Autonomous System number is not a CIDR prefix, it is a foundational Internet routing identifier. Inter-domain routing operates between autonomous systems, and AS numbers are used alongside IP prefixes throughout BGP, RPKI ROAs, RPSL, IRR queries, route-origin validation, and routing policy—not BGP alone. swift-cidr therefore owns the protocol-neutral numeric AutonomousSystemNumber value, while higher-level packages own contextual syntax and behavior. For example, swift-rpsl owns AS-prefixed forms, AS expressions, sets, references, and policy semantics.

Progressive disclosure. Many apps only need IPv4Address / IPv6Address. Infrastructure work adds PrefixLength, IPNetwork, blocks, selectors, ASN, and mixed-family types. You do not need the full surface on day one—see DESIGN.md.

The core models are currency types: public value types intended to be stored, passed, and composed throughout network infrastructure software.

Swift for Network Infrastructure. swift-cidr is a foundation for Swift applications that model, validate, configure, and operate on IP networks. Built from the network model outward, it provides type-safe foundations for IP infrastructure software: routing, addressing, policy, validation, configuration, and control-plane data.

swift-cidr brings native CIDR currency types to Swift on Server, apps, services, tooling, and network control-plane systems. It is not "Swift networking" in the URLSession or socket-adapter sense, and it is not just another IP address parser: it is a typed, pure Swift foundation for carrying addresses, prefixes, networks, and endpoint values through network infrastructure software without falling back to loosely typed strings or POSIX-shaped state.

That scope includes routing protocols, RPKI validation, access-list builders, IPAM systems, NETCONF/SSH configuration tooling, ping and diagnostic utilities, and other systems that process high-volume IP data or control-plane state.

Why CIDR

  • Family-safe APIs expose familiar IPv4 and IPv6 names like IPv4Address, IPv6Address, IPv4Network, and IPv6Network, while keeping address-family boundaries explicit in the type system.
  • AddressFamily models selected IANA address-family values as compile-time traits instead of runtime tags, carrying storage width, parser, formatter, and IANA family metadata in the type system.
  • AutonomousSystemNumber, also available as ASN, is the canonical numeric AS-number value, while AF.ASN remains its IANA address-family marker.
  • IPNetwork is first-class, so CIDR prefixes can participate directly in containment checks, subnet traversal, summarization, and mixed-family API boundaries. In this package, CIDR is a protocol shared by several forms— not a single hybrid struct CIDR wrapper around a host address (see DESIGN.md).
  • IPAddressRange represents one exact inclusive address interval independently of CIDR prefix structure, while IPAddressCoverage normalizes an exact union of ranges for deterministic containment and summarization.
  • RPSL-style prefix-range operators model route-policy prefix selection with ^+, ^-, ^n, and ^n-m forms.
  • Multicast group addresses and group-address ranges are modeled explicitly, so multicast CIDR notation does not inherit unicast subnet, host, or broadcast semantics.
  • The core CIDR module stays pure Swift and dependency-free. POSIX and SwiftNIO support live at adapter boundaries instead of shaping the core type system.
  • IPv4Address and IPv6Address expose fixed-size, network-byte-order InlineArray projections on supported toolchains and platforms while keeping integer storage as the canonical representation for CIDR math.
  • The API is designed for network infrastructure software: routing, addressing, policy, validation, configuration, and control-plane data pipelines that need small value types, explicit family metadata, predictable formatting/parsing, and optional CIDRNIO interoperability for SwiftNIO users.
  • Performance work is measured with benchmark coverage against Swift public APIs and system baselines, including IPv4/IPv6 inet_pton parser baselines and IPv4/IPv6 inet_ntop formatter baselines.

The package is organized around a family-bound core:

  • AddressFamily is the compile-time trait that binds storage width, parsing, formatting, and IANA family metadata to selected registry families. IPAddressFamily narrows that surface to IP address families, with AF.V4 and AF.V6 as the concrete IPv4 and IPv6 marker types.
  • IPAddress<Family> stores an IP address together with its prefix context.
  • IPNetwork<Family> stores a canonical network boundary.
  • IPAddressRange<Family> stores one inclusive address interval using strict lower...upper text, and IPAddressCoverage<Family> stores a normalized exact union of those intervals.
  • PrefixLength<Family> validates CIDR prefix lengths per family.
  • IPMulticastGroup<Family> and IPMulticastGroupRange<Family> model multicast destination identifiers and group-address ranges, with aliases such as IPv4MulticastGroup and IPv6MulticastGroup.
  • AnyIPAddress, AnyIPNetwork, AnyIPAddressRange, and AnyPrefixLength provide mixed-family wrappers for boundary APIs.
  • AutonomousSystemNumber stores a four-octet AS number and parses its canonical bare asplain decimal representation.
  • Port stores numeric transport-layer port values and round-trips their canonical decimal text, while IPEndpoint combines an IP address with a port. Design intent treats endpoint, port, and future scoped IPv6 (addr%zone) as a host/context layer above pure prefix math (see DESIGN.md and issue #10).

Standards Grounding

swift-cidr is built around established Internet standards and registry terminology rather than package-specific interpretations.

Type ↔ standards map, form comparison, and layering: Documentation/DESIGN.md.

Dogfooding / usage examples: Documentation/Examples.md.

Internals for contributors and prior-art explorers: Documentation/INTERNALS.md.

Flagship references (full map in DESIGN.md):

  • The IANA Address Family Numbers registry grounds AddressFamily.ianaValue and the selected registry families modeled by AF, including IPv4, IPv6, AS Number, 48-bit MAC, and 64-bit MAC.
  • RFC 791 grounds IPv4 as a 32-bit Internet address family.
  • RFC 4291 grounds IPv6 as a 128-bit address family and defines conventional IPv6 text forms.
  • RFC 4632 is Classless Inter-domain Routing: The Internet Address Assignment and Aggregation Plan—not merely slash-text parsing. The package’s abbreviated Classless / Inter-domain / Routing reading is in DESIGN.md §2.
  • RFC 7020 describes the Internet Numbers Registry System for globally unique IP address space and AS numbers; that registry and delegation context is why CIDRBlock exists as a neutral address-space block separate from host addresses and configured network prefixes.
  • RFC 5952 guides compressed IPv6 text formatting.
  • RFC 2622 defines the RPSL address-prefix-range operators modeled by NetworkPrefixRange.
  • RFC 6308 informs the multicast address allocation and assignment model used by multicast types.
  • RFC 1930 defines the Autonomous System concept modeled by AutonomousSystemNumber and identified by the AF.ASN family marker. ASNs appear with BGP, RPKI ROAs, IRR, and policy—not only BGP.
  • RFC 5396 defines bare decimal asplain as the canonical textual representation of an AS number.
  • RFC 6793 defines four-octet AS numbers, matching AutonomousSystemNumber's AF.ASN.Storage backing.

Learning Guides

The package includes short learning guides for developers who know Swift but may not have deep network-architecture background:

These guides explain why swift-cidr separates host addresses, network prefixes, Regional Internet Registry-style delegated CIDR blocks, and multicast group ranges into distinct types while leaving operational context to higher layers. For a single map of types to standards and the math vs host/context split, start with DESIGN.md.

Modules

  • CIDR: Core address, network, prefix, mixed-family, and endpoint types.
  • CIDRArgumentParser: Opt-in Swift Argument Parser conformances for Port, AutonomousSystemNumber, family-bound address, endpoint, network, and prefix-length values, plus the AnyIPAddress and AnyIPNetwork mixed-family boundary types. See CIDRArgumentParser.md.
  • CIDRPOSIX: POSIX interoperability helpers for address families and sockaddr conversion.
  • CIDRNIO: SwiftNIO adapters for ByteBuffer and SocketAddress. Importing CIDRNIO is explicit, and the core CIDR target does not import NIOCore.

IANA registry datasets are intentionally outside the core CIDR package, keeping this package focused on value types, parsing, formatting, and CIDR math.

Swift Argument Parser Integration

Beginning with swift-cidr 0.7.0, CLI targets can opt into direct @Option / @Argument parsing by depending on CIDR, CIDRArgumentParser, and Swift Argument Parser, then importing all three modules explicitly:

import ArgumentParser
import CIDR
import CIDRArgumentParser

struct PeerOptions: ParsableArguments {
    @Option var peer: IPv4Address
    @Option var port: Port = Port(179)
    @Option(name: .customLong("local-as"))
    var localAS: AutonomousSystemNumber = AutonomousSystemNumber(65001)
    @Option(name: .customLong("local-address"))
    var localAddress: IPv4Address?
    @Option(name: .customLong("allowed-prefix"))
    var allowedPrefix: IPv4Network?
    @Option(name: .customLong("listen-endpoint"))
    var listenEndpoint: IPEndpoint<V6>?
    @Option(name: .customLong("maximum-prefix-length"))
    var maximumPrefixLength: IPv4PrefixLength?
    @Option(name: .customLong("next-hop"))
    var nextHop: AnyIPAddress?
    @Option(name: .customLong("route"))
    var route: AnyIPNetwork?
}

The adapter accepts numeric ports, bare asplain ASNs, and literal IPv4 or IPv6 addresses. Bare addresses receive /32 or /128 context, and an explicit valid prefix is preserved. It also parses family-bound endpoints, networks, and standalone prefix lengths: endpoints require a numeric port (and brackets around IPv6), networks require an explicit prefix and clear host bits to the canonical network boundary, and prefix lengths must fit their address family. AnyIPAddress and AnyIPNetwork provide the same address and network behavior when the family is selected from each literal at runtime, which is useful for dual-stack CLI boundaries. DNS names, service-name ports, AS-prefixed/asdot ASNs, and an explicit empty option value are rejected. Omit an optional option to get nil.

The CIDR, CIDRPOSIX, and CIDRNIO targets do not depend on or link Swift Argument Parser. SwiftPM does resolve swift-argument-parser as part of the overall swift-cidr package graph because it is declared in the package manifest; only targets that opt into CIDRArgumentParser link the adapter and Argument Parser. No modules are underscored re-exports.

Toolchains and Platforms

  • Swift 6.2 or later
  • Swift 6.2 or later Command Line Tools for command-line and editor-based workflows
  • Minimum Apple deployment targets:
    • macOS 15
    • iOS 18

The Apple platform minimums come from this toolchain's built-in UInt128 availability. The InlineArray octet adapters require macOS 26, iOS 26, tvOS 26, watchOS 26, or visionOS 26; existing APIs retain the package's lower deployment targets. Linux validation is handled in CI, including the Swift 6.2 minimum toolchain.

On macOS with standalone Command Line Tools, use the repository test wrapper:

./scripts/test.sh

The wrapper still runs SwiftPM tests. It only adds the Swift Testing framework and runtime paths needed by standalone Command Line Tools installations where plain swift test cannot locate Testing.framework.

For local Linux validation with Docker Desktop, use the Linux wrapper:

./scripts/linux-test.sh

The wrapper uses the official swift:6.3 image and defaults to linux/amd64 to match GitHub Actions. On Apple Silicon, a faster architecture-native smoke test is available with:

CIDR_LINUX_PLATFORM=linux/arm64 ./scripts/linux-test.sh

Use the interactive Linux shell when diagnosing platform-specific failures:

./scripts/linux-test.sh shell

Examples

Parse and Format

import CIDR

if let host = IPv4Address("192.0.2.1/24"),
   let port = Port("53") {
    let endpoint = IPEndpoint(address: host, port: port)

    print(host.description)
    // 192.0.2.1/24

    print(port.description)
    // 53

    print(host.network.description)
    // 192.0.2.0/24

    print(endpoint.description)
    // 192.0.2.1/24:53
}

Network-Order Octets

On Swift 6.2 or later, IPv4Address and IPv6Address can exchange address bits with packet, protocol, and FFI boundaries through fixed-size InlineArray values. On Apple platforms these APIs require macOS 26, iOS 26, tvOS 26, watchOS 26, or visionOS 26.

import CIDR

let wireOctets: InlineArray<4, UInt8> = [192, 0, 2, 129]

let address = IPv4Address(octets: wireOctets)

print(address.description)
// 192.0.2.129/32

let projected = address.octets
print(projected[0], projected[1], projected[2], projected[3])
// 192 0 2 129

Octets use network byte order, with the most-significant octet first. They are an owned projection of address bits only: they do not carry prefix length, network canonicalization, or IPv6 scope. The integer-backed address remains the math representation. This adapter is an exact, allocation-free, text-free interoperability boundary; it does not replace integer storage or model a borrowed View.

Four locked currency benchmarks cover IPv4 and IPv6 octet projection and reconstruction. Their configured p50, p75, and p90 gates require zero mallocs, object allocations, retains, and releases; see the benchmark methodology.

This standard-library octet boundary coexists with the richer CIDRPOSIX and CIDRNIO adapters. On Linux and Apple OS 26 or later, the CIDRNIO SocketAddress bridge consumes this same octet projection when copying address bytes to and from POSIX socket fields. Supported pre-26 Apple deployments retain a private, behavior-equivalent integer network-byte-order fallback because InlineArray is not back-deployed. The ByteBuffer bridge remains integer network-byte-order I/O.

The InlineArray used by CIDRNIO is a transient, owned transfer value. It is not the literal storage of SocketAddress, a zero-copy representation, or a borrowed View. The allocation-free evidence above applies to the octet projection itself; it is not a claim that constructing a SwiftNIO SocketAddress performs no allocations. Integer-backed address identity and CIDR math remain canonical in every case.

Subnet Math

import CIDR

if let network = IPv4Network("192.0.2.0/24"),
   let start = IPv4Address("192.0.2.0"),
   let end = IPv4Address("192.0.2.255") {
    let subnets = Array(network.subnets(prefixLength: 26)).map(\.description)
    let summary = IPv4Network.summarize(from: start, to: end).map(\.description)

    print(subnets)
    // ["192.0.2.0/26", "192.0.2.64/26", "192.0.2.128/26", "192.0.2.192/26"]

    print(summary)
    // ["192.0.2.0/24"]
}

Mixed-Family Boundary APIs

import CIDR

if let v4 = AnyIPAddress("192.0.2.1/24"),
   let v6 = AnyIPAddress("2001:db8::1/64") {
    let addresses = [v4, v6]

    for address in addresses {
        print(address.familyName, address.network.description)
    }
}

Exact Address Coverage

IPAddressRange text is a strict, library-defined lower...upper form. It models inclusive address coverage rather than preserving the CIDR prefixes that may have produced that coverage. Adjacent and overlapping ranges can be normalized into an IPAddressCoverage, whose containment lookup uses its sorted range index.

import CIDR

if let lower = IPv4AddressRange("192.0.2.0...192.0.2.63"),
   let upper = IPv4AddressRange("192.0.2.64...192.0.2.127") {
    let coverage = IPAddressCoverage([upper, lower])

    print(coverage.ranges.map(\.description))
    // ["192.0.2.0...192.0.2.127"]

    print(coverage.summarizedNetworks().map(\.description))
    // ["192.0.2.0/25"]
}

summarizedNetworks() preserves the exact address union, but it does not retain the original prefix lengths used to construct a range or coverage set.

Autonomous System Numbers

import CIDR

if let asn = AutonomousSystemNumber("64496") {
    print(asn.rawValue)
    // 64496

    print(asn.description)
    // 64496
}

The numeric value intentionally does not accept the RPSL form AS64496 or legacy asdot text. Those lexical and policy concerns belong in higher-level packages.

Development

Common local commands:

swift build --target CIDR
swift build --target CIDRArgumentParser
swift build --target CIDRPOSIX
swift build --target CIDRNIO
./scripts/test.sh
./scripts/linux-test.sh
./scripts/benchmarks.sh build
./scripts/benchmarks.sh check

Benchmarking

TL;DR

Build, test, and run the primary public/API-facing benchmarks from the repository root:

./scripts/test.sh
./scripts/benchmarks.sh run --no-progress --scale --time-units nanoseconds
./scripts/benchmarks.sh check

./scripts/benchmarks.sh run defaults to CIDRBenchmarkTarget, which exercises the normal public APIs such as IPv4Address, IPv6Address, IPNetwork, and formatting paths. Deeper benchmark targets for parser experiments, fixed-loop CPU research, and SwiftNIO adapters are documented below.

Benchmark Details

Benchmark tooling lives in the separate Benchmarks/ package rather than the root library package, so contributors may not see it when opening only the root Package.swift in Xcode.

From the repository root:

./scripts/benchmarks.sh build
./scripts/benchmarks.sh run
./scripts/benchmarks.sh check
./scripts/benchmarks.sh update
./scripts/benchmarks.sh graph

The wrapper defaults to CIDRBenchmarkTarget, the public/API-facing benchmark target.

For fixed-loop research benchmarks that report only user CPU time, select CIDRCPUBenchmarkTarget:

CIDR_BENCHMARK_TARGET=CIDRCPUBenchmarkTarget ./scripts/benchmarks.sh run

For opt-in SwiftNIO adapter benchmarks, select CIDRNIOBenchmarkTarget:

CIDR_BENCHMARK_TARGET=CIDRNIOBenchmarkTarget ./scripts/benchmarks.sh run

Open Benchmarks/Package.swift separately in Xcode if you want the benchmark package to appear in Xcode's package navigator.

Benchmark details live in Benchmarks/README.md, and the root wrapper script lives at scripts/benchmarks.sh. Benchmark tooling is intentionally isolated in the nested Benchmarks package so normal library builds, tests, and non-macOS Apple destinations do not pull in Benchmark. Linux remains part of normal build/test CI, and the opt-in Linux benchmark job checks benchmark target compilation. Benchmark-threshold validation remains a local/macOS workflow unless it is explicitly run on Linux.

License

CIDR is licensed under Apache-2.0. See LICENSE.

Description

  • Swift Tools 6.2.0
View More Packages from this Author

Dependencies

Last updated: Tue Oct 13 2026 13:39:04 GMT-0900 (Hawaii-Aleutian Daylight Time)