networking cidr subnetting aws

CIDR Notation and Subnetting for Developers (with AWS VPC Examples)

What /16 and /24 actually mean, how to count usable hosts (and why /31 is special), why AWS gives you five fewer addresses, how to split a VPC into subnets, and how to turn an IP range into CIDR blocks.

· Mohammed Aquib Ansari

I didn’t learn subnetting in a networking course. I learned it the first time a Terraform plan failed because two VPCs I wanted to peer overlapped, and again when a “/28 is plenty” subnet ran out of IPs at eleven instances. This is the guide I wish I’d had: the parts of CIDR that matter when you write infrastructure code.

I check everything below with the CIDR calculator, which runs in the browser.

What the slash means

An IPv4 address is a 32-bit number. 192.168.1.0/24 says: the first 24 bits are the network, the remaining 8 bits are hosts. Eight host bits give 2^8 = 256 addresses:

Network         192.168.1.0/24
Broadcast       192.168.1.255
Usable range    192.168.1.1 – 192.168.1.254
Total addresses 256
Usable hosts    254
Netmask         255.255.255.0
Wildcard mask   0.0.0.255

The first address is the network itself and the last is the broadcast address, so a normal subnet has total − 2 usable hosts. A smaller number after the slash means a bigger network: 10.0.0.0/8 is 16,777,216 addresses; /28 is 16.

The netmask is the same information written as an address (24 ones followed by 8 zeros). The wildcard mask is its inverse, which is what Cisco ACLs and some firewall configs want. The calculator accepts all three forms.

/31 and /32 are not broken

A lot of calculators report “0 usable hosts” for a /31. That was true once, but RFC 3021 made /31 valid for point-to-point links: two addresses, no network or broadcast, both usable. A /32 is a single host — you see it for loopbacks, Elastic IPs and host routes in security groups (203.0.113.7/32 means “exactly this IP”).

Host bits set

10.0.1.37/24 is a valid host address with a prefix, but it’s not a network. The network is 10.0.1.0/24. AWS, Azure and most firewall APIs reject the first form in a CIDR field, which is a confusing error if you don’t know to look for it. The calculator shows the normalized network and says so.

Why AWS says 251

Create a /24 subnet in AWS and the console says 251 available addresses. AWS reserves five in every subnet:

  • .0 — network address
  • .1 — VPC router
  • .2 — DNS (Route 53 Resolver)
  • .3 — reserved for future use
  • .255 — the last address (broadcast is unsupported in a VPC, but it’s reserved anyway)

Azure also reserves five (network, gateway, two for DNS, and the last); Google Cloud reserves four. With the calculator’s “Reserved addresses” set to AWS, a 10.0.1.0/24 shows 251 usable, from 10.0.1.4 to 10.0.1.254.

This matters for small subnets. An AWS /28 has 16 addresses and 11 usable. If each instance, load balancer node, Lambda ENI and interface endpoint needs an IP, eleven goes fast. AWS subnets can be between /16 and /28; I rarely go smaller than /24 for anything that autoscales.

Planning a VPC

A common layout: a /16 VPC split into /20 subnets, which gives sixteen subnets of 4,096 addresses each. In “Split network”, enter 10.0.0.0/16 and /20:

10.0.0.0/20
10.0.16.0/20
10.0.32.0/20
10.0.48.0/20

…and so on up to 10.0.240.0/20. Assign them per availability zone and tier (public, private, data) and leave some unused for later. You can also enter a count (“split into 6”) and the calculator rounds up to the next power of two, because subnets of equal size must come in powers of two.

Check for overlaps before peering

VPC peering and Transit Gateway routes require non-overlapping CIDRs. So do VPNs back to an office network, and Docker’s default bridge (172.17.0.0/16) has collided with more corporate networks than I can count. Paste all your ranges into “Overlap check”, one per line, before you create anything:

10.0.0.0/16
10.1.0.0/16
10.0.128.0/20

The calculator flags that 10.0.0.0/16 contains 10.0.128.0/20 — those two can’t be peered.

IP ranges to CIDR

Sometimes you get a range instead of a prefix: a partner’s allow-list, a GeoIP table, “our office uses .0 to .130”. Security groups and firewall rules want CIDRs. The trick is that a range usually isn’t one block. 192.168.1.0 to 192.168.1.130 is exactly:

192.168.1.0/25
192.168.1.128/31
192.168.1.130/32

Doing that by hand is where mistakes creep in; “Range → CIDR” gives the minimal list.

Private ranges and leading zeros

For private networks you have 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16 (RFC 1918). 100.64.0.0/10 is carrier-grade NAT space — some teams use it for Kubernetes pods when RFC 1918 space runs out, but it can clash with ISPs that actually do CGNAT. The calculator labels each of these.

One more trap: never write octets with leading zeros. 10.010.0.1 means 10.10.0.1 to some software and 10.8.0.1 to others, because inet_aton reads a leading zero as octal. That ambiguity has caused real allow-list bypasses, so the calculator rejects it rather than guessing.

IPv6

IPv6 works the same way with 128 bits. The standard subnet is a /64 (SLAAC requires it), so you’ll mostly hand out /64s from a /48 or /56 allocation. There’s no broadcast address, and the numbers get absurd — a single /64 is 18,446,744,073,709,551,616 addresses — which is why IPv6 planning is about prefix boundaries, not host counts. The calculator handles IPv6 prefixes, compression (2001:db8::) and expansion.

If you’re converting between the binary and hex forms by hand, the number base converter helps. Most of the time, though, the CIDR calculator answers the question before I’ve finished doing the arithmetic.