Course outline

3.1

IP Addresses, CIDR and Subnet Maths

Read and write any CIDR block, count its addresses, split it into subnets, and tell private ranges from public ones.

30 min Reading + animations

Tip: tap or hover any dotted-underlined term to see what it means.

By the end of this lesson you will be able to

  • Read an IPv4 address as 32 bits and convert any octet between binary and decimal.
  • Read any CIDR block (like 10.0.0.0/16), say how many addresses it holds, and write its first and last address.
  • Convert between a prefix length and a subnet mask (/28 = 255.255.255.240).
  • Split a range into equal subnets and check that each one starts on the right boundary.
  • Tell private (RFC 1918) addresses from public ones, and explain why the VPC range must never overlap a network it will talk to.
  • Use 0.0.0.0/0 and /32 correctly in AWS route tables and firewall rules.

#Why you have to plan addresses first

When you create a VPC (Virtual Private Cloud, your own private network inside AWS), the first thing AWS asks for is an address range in CIDR notation, for example 10.0.0.0/16. Every server, database and load balancer you later put inside the VPC gets an address from that range.

That one choice is hard to undo:

  • The VPC’s first (primary) range can never be changed after creation. You can add extra ranges later, but you cannot resize or renumber the first one.
  • If the range overlaps your office network or another VPC, those networks can never talk to each other properly (you will see exactly why below).
  • If the range is too small, you run out of addresses as the system grows.

So before you build anything on AWS, you need to be fluent in IPv4 addresses and CIDR. The System Design course covers IP addressing in general; this lesson focuses on what you need for AWS.

#IPv4 in one minute: 32 bits, 4 octets

An IPv4 address is a 32-bit number. To make it readable we split it into four groups of 8 bits (called octets) and write each group in decimal, separated by dots:

   10   .    0     .    1     .   10
00001010 . 00000000 . 00000001 . 00001010

Each octet is 8 bits, so it ranges from 00000000 (0) to 11111111 (255). The bit positions in an octet are worth, from left to right:

Bit1st2nd3rd4th5th6th7th8th
Value1286432168421

To turn binary into decimal, add the values of the bits that are 1: 11110000 = 128 + 64 + 32 + 16 = 240. To go the other way, take the largest value that fits and subtract: 192 = 128 + 64, so 11000000.

32 bits give 2³² = 4,294,967,296 possible addresses. After large blocks are set aside for private networks, multicast, documentation and other special uses, about 3.7 billion are usable on the public internet, which is far too few for every device on Earth. That shortage is why private ranges and NAT exist, and why AWS now charges for public IPv4 addresses (lesson 3.6).

#CIDR notation: a base address and a prefix

Originally the internet handed out addresses in fixed classes: a Class A network had 16.7 million addresses, Class B 65,536 and Class C 256. An organisation that needed 2,000 addresses had to take a whole Class B and waste over 63,000 of them. In 1993 classes were replaced by CIDR (Classless Inter-Domain Routing), which lets a block be any power-of-two size.

A CIDR block is written as base address / prefix length:

10.0.0.0/16
└──┬───┘ └┬┘
 base   prefix: the first 16 bits are fixed
  • The prefix length (/16) says how many bits, from the left, are fixed. These bits name the network.
  • The remaining 32 − prefix bits are free. Every combination of them is one address in the block.

So the number of addresses in a block is:

addresses = 2^(32 − prefix)

CIDRFree bitsAddressesWhich octets change
/3201none (exactly one address)
/28416part of the last octet
/27532part of the last octet
/26664part of the last octet
/248256the whole last octet
/20124,096part of the 3rd + all of the 4th
/161665,536the last two octets
/82416,777,216the last three octets
/0324,294,967,296all of them: every IPv4 address

A few quick reads:

  • 10.20.0.0/16 → 10.20.0.0 to 10.20.255.255 (65,536 addresses).
  • 10.20.5.0/24 → 10.20.5.0 to 10.20.5.255 (256).
  • 198.51.100.7/32 → just 198.51.100.7.
  • 0.0.0.0/0 → every IPv4 address there is.

Play with the planner: type a block, drag the prefix and watch the blue (fixed) and grey (free) bits change. Ignore the subnet part for now; we use it in a moment.

VPC CIDR planner

Pick a block for a VPC, then cut it into subnets. Blue bits are fixed (the network), grey bits are free (the hosts).

10.0.0.0/16

00001010000000000000000000000000

First address

10.0.0.0

Last address

10.0.255.255

Addresses in the block

2^16 = 65,536

Subnet mask

255.255.0.0

Kind of range: Private (RFC 1918, 10/8): the usual choice for VPCs

Valid size for a VPC (AWS allows /16 to /28).

  • 10.0.0.0/24 → 10.0.0.0 – 10.0.0.255
  • 10.0.1.0/24 → 10.0.1.0 – 10.0.1.255
  • 10.0.2.0/24 → 10.0.2.0 – 10.0.2.255
  • 10.0.3.0/24 → 10.0.3.0 – 10.0.3.255
  • 10.0.4.0/24 → 10.0.4.0 – 10.0.4.255
  • 10.0.5.0/24 → 10.0.5.0 – 10.0.5.255
  • … +250 more

Reserved in the first subnet

  • 10.0.0.0 network address
  • 10.0.0.1 VPC router
  • 10.0.0.2 Amazon-provided DNS
  • 10.0.0.3 reserved for future use
  • 10.0.0.255 broadcast (not supported, so reserved)
Smallest subnet that fits: /24 (256 − 5 = 251)
i

Subnets must also be between /16 and /28.

#Subnet masks: the same thing written differently

Older tools and many operating systems express the prefix as a subnet mask: a 32-bit number whose network bits are all 1 and whose host bits are all 0.

PrefixMaskLast-octet bits
/8255.0.0.0
/16255.255.0.0
/20255.255.240.03rd octet = 11110000
/24255.255.255.000000000
/26255.255.255.19211000000
/27255.255.255.22411100000
/28255.255.255.24011110000
/32255.255.255.25511111111

To convert, count the 1s: 255.255.255.240 is 8 + 8 + 8 + 4 = 28 ones, so /28. Going the other way, /28 leaves 4 ones in the last octet: 11110000 = 240.

#Finding the range when the prefix is not a multiple of 8

For /8, /16 and /24 the answer is easy: whole octets are fixed or free. For anything in between, use the block size trick on the one octet that is split:

  1. Find the octet where the prefix ends. For /20 that is the 3rd octet (bits 17–24).
  2. Block size in that octet = 256 − mask value. For /20 the 3rd-octet mask is 240, so the block size is 16.
  3. Blocks start at multiples of 16 in that octet: 0, 16, 32, 48…

Example: which /20 contains 10.0.37.9? 37 lies between 32 and 47, so the block is 10.0.32.0/20, covering 10.0.32.0 to 10.0.47.255 (16 × 256 = 4,096 addresses).

#Splitting a range into subnets

A VPC range is always cut into smaller blocks called subnets (lesson 3.2 shows how AWS uses them). Splitting is just fixing more bits:

  • Going from /16 to /24 fixes 8 more bits, so you get 2⁸ = 256 subnets of 256 addresses each.
  • Going from /16 to /18 fixes 2 more bits: 4 subnets of 16,384.
  • In general, splitting a /a into /b blocks gives 2^(b − a) subnets.

A typical plan for a VPC 10.0.0.0/16 used across two Availability Zones (separate data centres, explained in lesson 3.2):

SubnetCIDRRange
public, zone A10.0.0.0/2410.0.0.0 – 10.0.0.255
public, zone B10.0.1.0/2410.0.1.0 – 10.0.1.255
private app, zone A10.0.10.0/2410.0.10.0 – 10.0.10.255
private app, zone B10.0.11.0/2410.0.11.0 – 10.0.11.255
database, zone A10.0.20.0/2410.0.20.0 – 10.0.20.255
database, zone B10.0.21.0/2410.0.21.0 – 10.0.21.255

Most of the /16 is left free on purpose, for subnets you will need later.

In the planner, drag the green split slider. AWS keeps 5 addresses in every subnet for itself (the network address, the VPC router, DNS, one for future use and the last one), so a /24 subnet gives you 256 − 5 = 251 usable addresses. Lesson 3.2 explains each of the five. Try the “servers I need” box with 200: a /25 holds only 128 − 5 = 123, so the answer is a /24.

Self-checkQuestion

How many addresses are in 10.0.0.0/20, and what is the last one?

#Private and public addresses

Not every IPv4 address may be used on the internet. RFC 1918 sets aside three ranges for private networks:

RangeCIDRSizeTypical use
10.0.0.0 – 10.255.255.25510.0.0.0/816.7 millionLarge networks; the most common choice for VPCs
172.16.0.0 – 172.31.255.255172.16.0.0/121 millionAWS’s default VPC uses 172.31.0.0/16 from here
192.168.0.0 – 192.168.255.255192.168.0.0/1665,536Home Wi-Fi routers and small offices

Everything outside the special-purpose ranges is public.

Public addressPrivate address
Reachable from the internetYes, routers everywhere forward itNo, internet routers drop it
UniqueGlobally: two machines can never share oneOnly within one network: two companies can both use 10.0.1.5
Who assigns itRegional registries, through ISPs and cloud providers like AWSYou choose it freely
Can be locatedRoughly geo-locatableMeans nothing outside its network
How it reaches the internetDirectlyThrough NAT, which swaps it for a public address (lesson 3.4)

A few other ranges are worth recognising on AWS:

  • 169.254.0.0/16 (link-local): AWS uses 169.254.169.254 for the instance metadata service and 169.254.169.123 for its time service. It can never be a VPC range.
  • 100.64.0.0/10 (shared address space, also used for carrier-grade NAT): allowed in a VPC with some restrictions, sometimes used when RFC 1918 space runs out.
  • 127.0.0.0/8 (loopback) and 224.0.0.0/4 (multicast): never usable for a VPC.
  • 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24: reserved for documentation. This course uses them for made-up public addresses.

#The overlap trap

Two networks that need to talk (a VPC and your office, two VPCs, or a VPC and a partner’s network) must use ranges that do not overlap. The reason is routing: when a packet’s destination matches the VPC’s own range, the VPC delivers it inside the VPC, full stop.

Why two networks that talk must not share addresses

A VPC is connected to the office over a VPN. Watch where the VPC router sends a packet for 10.0.5.20.

Scenario

VPC 10.0.0.0/16 and the office also uses 10.0.0.0/16.

AWS Cloud
VPC
Private subnet10.0.1.0/24
Office network
App server10.0.1.10
VPC router
VPN gatewayAWS side
Office routercustomer gateway
Office database10.0.5.20
→ 10.0.5.20

VPC route table

DestinationTarget
10.0.0.0/16local
10.0.0.0/16 (office)vgw ✕ (cannot be added)
Step 1 of 4
1

The app server wants the office database at 10.0.5.20. The packet first goes to the VPC router, which checks its route table.

What to take from the three scenarios:

  • Same range on both sides: the office is unreachable. A route to it cannot even be added.
  • Different ranges: routing works in both directions.
  • Partial overlap: the most specific route wins (longest prefix match: a /16 beats a /8). Some office addresses work and some silently fail.

How teams avoid this in practice:

  1. Keep an address plan. Give each environment and Region its own block, for example 10.0.0.0/16 for production in one Region, 10.1.0.0/16 for staging, and leave the office its existing range.
  2. Avoid the common defaults. 192.168.0.0/24 and 192.168.1.0/24 are on half the home routers in the world, which matters as soon as staff connect through a VPN. 172.31.0.0/16 is the default VPC everywhere.
  3. Use a tool at scale. AWS VPC IPAM (IP Address Manager) hands out non-overlapping ranges to teams and accounts automatically.

#0.0.0.0/0 and /32 in AWS rules

Two CIDR blocks appear everywhere in AWS:

  • 0.0.0.0/0 means “any IPv4 address”. In a route table it is the default route: “for anything not matched by a more specific route, go here” (usually the internet gateway or a NAT gateway). In a firewall rule it means “from anywhere” or “to anywhere”.
  • /32 means “exactly this one address”. You use it to allow just your own IP to SSH into a server, for example 203.0.113.25/32, or to block one attacker’s address.

#Try it yourself

You do not need an AWS account to practise. Python’s standard library does all of this:

python3 - <<'EOF'
import ipaddress as ip

vpc = ip.ip_network("10.0.0.0/16")
print(vpc.num_addresses, vpc[0], vpc[-1])          # 65536 10.0.0.0 10.0.255.255
print(vpc.netmask)                                  # 255.255.0.0
print(vpc.is_private)                               # True

# split into /24 subnets and show the first three
for s in list(vpc.subnets(new_prefix=24))[:3]:
    print(s, "usable on AWS:", s.num_addresses - 5)

# which /20 holds 10.0.37.9?
print(ip.ip_network("10.0.37.9/20", strict=False))  # 10.0.32.0/20

# do two ranges overlap?
print(ip.ip_network("10.0.0.0/16").overlaps(ip.ip_network("10.0.0.0/8")))  # True
EOF

With an AWS account and the CLI configured, list the ranges your VPCs already use:

aws ec2 describe-vpcs --query "Vpcs[].{id:VpcId,cidr:CidrBlock,default:IsDefault}" --output table

#Summary

Key takeaways

  • An IPv4 address is 32 bits, written as four octets of 0–255. Bit values in an octet are 128, 64, 32, 16, 8, 4, 2, 1.
  • CIDR = base address / prefix length. The prefix bits are fixed; the rest are free. Addresses = 2^(32 − prefix). Bigger prefix, smaller block.
  • A subnet mask is the same information: /24 = 255.255.255.0, /28 = 255.255.255.240. For split octets, block size = 256 − mask value.
  • Splitting a /a into /b gives 2^(b − a) subnets, each starting on a multiple of its own size. AWS keeps 5 addresses per subnet, so usable = total − 5.
  • RFC 1918 private ranges: 10.0.0.0/8, 172.16.0.0/12 (default VPC 172.31.0.0/16), 192.168.0.0/16. Public addresses are globally unique; private ones reach the internet through NAT.
  • A VPC range must be /16 to /28, and its primary range can never be changed. Plan it so it never overlaps a network it will connect to; the longest prefix match makes overlaps fail silently.
  • 0.0.0.0/0 = anywhere (the default route); /32 = one address. Never open admin ports to 0.0.0.0/0.