Skip to content

Subnet / CIDR Calculator — Swift source

Compute IPv4 subnet details from a CIDR block - network, broadcast, host range, netmask, wildcard, host count, IP class, and private-range detection. Split a block into smaller subnets, all in your browser.

This is the Swift implementation — the same logic the interactive tool runs, in a shareable, citable form.

// subnet-cidr — Swift port: IPv4 subnet/CIDR math (dotted-quad ⇄ UInt32, subnet details, CIDR splitting). Language: Swift (5.9+). Port of src/lib/subnet-cidr.ts — same logic as this dir's python.py / go.go; invalid input yields nil rather than throwing.

struct SubnetInfo {
    let network: String, broadcast: String, firstHost: String, lastHost: String
    let hostCount: UInt64, prefix: Int, ipClass: Character, isPrivate: Bool
}

enum SubnetCidr {
    // The TS /^\d+$/ check — rejects signs, hex, whitespace, and the empty string.
    private static func allDigits(_ s: Substring) -> Bool {
        !s.isEmpty && s.allSatisfy { $0.isASCII && $0.isNumber }
    }

    // "a.b.c.d" → UInt32. nil for a wrong octet count, junk octets, or an octet > 255.
    static func ipToInt(_ ip: String) -> UInt32? {
        let parts = ip.split(separator: ".", omittingEmptySubsequences: false)
        guard parts.count == 4 else { return nil }
        var result: UInt32 = 0
        for part in parts {
            guard allDigits(part), part.count <= 3 else { return nil }
            var octet: UInt32 = 0
            for c in part { octet = octet * 10 + UInt32(c.wholeNumberValue!) }
            guard octet <= 255 else { return nil }
            result = result * 256 + octet
        }
        return result
    }

    static func intToIp(_ v: UInt32) -> String {
        "\(v >> 24).\((v >> 16) & 255).\((v >> 8) & 255).\(v & 255)"
    }

    private static func mask(fromPrefix p: Int) -> UInt32 {
        p == 0 ? 0 : UInt32.max << (32 - p)
    }

    // "ip/prefix" → full block details; nil for an invalid CIDR.
    static func subnetDetails(_ cidr: String) -> SubnetInfo? {
        guard let slash = cidr.firstIndex(of: "/") else { return nil }
        let prefixPart = cidr[cidr.index(after: slash)...]
        guard !prefixPart.contains("/"), allDigits(prefixPart), prefixPart.count <= 2 else { return nil }
        let prefix = prefixPart.reduce(0) { $0 * 10 + $1.wholeNumberValue! }
        guard prefix <= 32, let ipInt = ipToInt(String(cidr[..<slash])) else { return nil }

        let maskValue = mask(fromPrefix: prefix)
        let wildcard = ~maskValue
        let network = ipInt & maskValue
        let broadcast = network | wildcard
        // /31 (point-to-point) and /32 (single host) have no host/broadcast split.
        let first = prefix >= 31 ? network : network + 1
        let last = prefix >= 31 ? broadcast : broadcast - 1
        let hostCount: UInt64 = prefix >= 32 ? 1 : prefix == 31 ? 2 : (1 << (32 - prefix)) - 2

        let o1 = network >> 24, o2 = (network >> 16) & 255
        let ipClass: Character = o1 < 128 ? "A" : o1 < 192 ? "B" : o1 < 224 ? "C" : "-" // D/E → '-'
        let isPrivate = o1 == 10 || (o1 == 172 && (16...31).contains(o2)) || (o1 == 192 && o2 == 168)
        return SubnetInfo(network: intToIp(network), broadcast: intToIp(broadcast),
                          firstHost: intToIp(first), lastHost: intToIp(last),
                          hostCount: hostCount, prefix: prefix, ipClass: ipClass, isPrivate: isPrivate)
    }

    // Split into 2^(newPrefix-prefix) children; [] for invalid input or range.
    static func splitSubnet(_ cidr: String, newPrefix: Int) -> [String] {
        guard let base = subnetDetails(cidr) else { return [] }
        guard newPrefix >= base.prefix, newPrefix <= 32 else { return [] }
        let network = ipToInt(base.network)! & mask(fromPrefix: base.prefix)
        let block = UInt32(1) << (32 - newPrefix)
        return (0..<(1 << (newPrefix - base.prefix))).map {
            intToIp(network + UInt32($0) * block) + "/\(newPrefix)"
        }
    }
}

let d = SubnetCidr.subnetDetails("192.168.1.100/24")!
print("192.168.1.100/24 net=\(d.network) bcast=\(d.broadcast) first=\(d.firstHost) " +
      "last=\(d.lastHost) hosts=\(d.hostCount) class=\(d.ipClass) private=\(d.isPrivate)")
for kid in SubnetCidr.splitSubnet("192.168.1.0/24", newPrefix: 26) { print("  split /26 → \(kid)") }

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →