# net.cidr A subnet calculator as five functions that only make sense together: describe an IPv4 block (`cidrInfo`), test membership for IPv4 or IPv6 (`cidrContains`), check a block without raising (`isCidr`), and convert between prefix lengths and dotted netmasks. ## Decisions - **Host bits are allowed and dropped.** `192.168.1.77/24` is how an interface address is written, and it describes `192.168.1.0/24`; `cidrInfo` returns the cleaned-up block in `cidr`. (Python's `ipaddress.ip_network` refuses it unless `strict=False`; this behaves like `strict=False`.) - **/31 and /32.** A /31 is a point-to-point link: RFC 3021 makes both addresses usable, so `hostCount` is 2, the hosts are the two addresses and `broadcast` is null. A /32 is one host, also with no broadcast. Everything from /0 to /30 has network and broadcast addresses reserved, so `hostCount` is `addressCount - 2`. - **Families do not mix.** `cidrContains("10.0.0.0/8", "::ffff:10.0.0.1")` is false: an IPv4-mapped IPv6 address is a different address as far as a socket is concerned. Convert it first if you mean the IPv4 address. - **Strict text.** Addresses follow `net.ipv4` and `net.ipv6` (no leading zeros, no zone ids); the prefix is ASCII decimal with no leading zero, 0-32 for IPv4 and 0-128 for IPv6. - `cidrInfo` is IPv4 only: an IPv6 /64 has 2^64 addresses, which no language here holds in an `int`, and "broadcast" has no IPv6 meaning. - Netmasks must be contiguous: `255.0.255.0` is refused, and so is a wildcard mask such as `0.0.0.255` (write the netmask, `255.255.255.0`). `cidrBlock` (`cidr_block`) is exported for the group's own functions; it is not part of the contract. Sources: RFC 4632 (CIDR) section 3.1; RFC 3021 (Using 31-Bit Prefixes on IPv4 Point-to-Point Links); RFC 4291 section 2.3 (IPv6 prefix notation).