CIDR Subnet Report
Problem Statement
Before a VPC exists you have to size its subnets, and a /24 that "looks big enough" is how a training cluster runs out of addresses mid-scale-up. Given a CIDR block, derive its network address, broadcast address, netmask and usable host count, and say which of a list of IPs fall inside it.
Background
An IPv4 address is 32 bits. A CIDR block A.B.C.D/p fixes the leading p bits (the network part) and leaves 32 - p host bits free. The netmask is p ones followed by 32 - p zeros.
- Network address: the address with all host bits 0 — ip & mask. Note the address you are given need not be the network address: 10.0.5.37/22 still describes the block 10.0.4.0/22.
- Broadcast address: all host bits 1.
- Membership: ip is inside the block exactly when ip & mask == network.
- Usable hosts: 2 ** (32 - p) - 2 for p <= 30, since the network and broadcast addresses are not assignable. Two special cases: a /31 has 2 usable addresses (RFC 3021 point-to-point links) and a /32 has 1. Blindly subtracting 2 gives 0 and -1 there.
Solve this with integer bit arithmetic — do not use the ipaddress module.
Your Task
Implement:
def subnet_report(cidr, ips):
Return a dict with keys, in this order: "network", "broadcast", "netmask" (all dotted-quad strings), "usable_hosts" (int), and "in_subnet" (list of bools, one per entry of ips, in order).
Input Format
- cidr: string like "10.0.5.37/22".
- ips: list of dotted-quad strings to test.
Output Format
- The dict described above.
Sample
print(subnet_report("10.0.5.37/22", ["10.0.4.9", "10.0.8.1", "10.0.7.255"]))
Output:
{'network': '10.0.4.0', 'broadcast': '10.0.7.255', 'netmask': '255.255.252.0', 'usable_hosts': 1022, 'in_subnet': [True, False, True]}
A /22 borrows 2 bits from the third octet, so the block spans 10.0.4.0-10.0.7.255: 1024 addresses, 1022 assignable.
Example
print(subnet_report("10.0.5.37/22", ["10.0.4.9", "10.0.8.1", "10.0.7.255"])){'network': '10.0.4.0', 'broadcast': '10.0.7.255', 'netmask': '255.255.252.0', 'usable_hosts': 1022, 'in_subnet': [True, False, True]}cidris"10.0.5.37/22": the prefix fixes the first 22 of the 32 bits as the network part, leaving host bits (2 in the third octet, 8 in the fourth).- The netmask is 22 ones then 10 zeros. The first two octets are 255, the third is , the fourth is 0, giving
255.255.252.0. - Zero the host bits of
10.0.5.37: the third octet keeps only its top 6 bits, becoming , and the fourth octet becomes 0. The network is10.0.4.0. - Set every host bit to 1 instead: the third octet becomes and the fourth , so the broadcast is
10.0.7.255. - The block holds addresses; removing network and broadcast leaves
1022. - Membership compares the network bits:
10.0.4.9and10.0.7.255both reduce to third octet 4 (inside), but10.0.8.1has , which stays 8, a different block. Notice the broadcast address itself still counts as inside, giving[True, False, True].
Constraints
cidris a valid IPv4 block, prefix length 0 to 32- The given address may have host bits set; normalise it to the network address
- Usable hosts:
2 ** (32 - p) - 2for p <= 30,2for a /31,1for a /32 - 0 <= len(ips) <= 100
- Use integer bit arithmetic, not the
ipaddressmodule