Alright, let’s talk about IPv4 addresses. You’ve seen them: those four numbers separated by dots, like 192.168.1.1. They’re the postal addresses of the internet, and at their core, they’re just 32-bit numbers. We humans are terrible at reading binary, so we split that 32-bit number into four 8-bit chunks (called “octets”) and convert each to decimal. That’s it. That’s the magic. It’s just a number.

The problem is, we have about 4.3 billion possible addresses, and that sounded like science fiction in the 1970s but turned out to be hilariously insufficient. This scarcity forced us to get really clever about how we use them, which is where subnets and CIDR come in. They’re not just academic concepts; they’re the fundamental tools for keeping the internet from collapsing under its own weight.

The Anatomy of an IP Address: It’s All About the Bits

Every IP address has two parts: the network portion (think: your zip code or city) and the host portion (your specific street address). The original, clunky way to define this split was with a subnet mask. This is another 32-bit number, written just like an IP, made of a contiguous block of 1 bits (defining the network) followed by 0 bits (defining the hosts).

Take 192.168.1.42 with a mask of 255.255.255.0.

  • 255.255.255.0 in binary is 11111111.11111111.11111111.00000000.
  • The first 24 bits are 1s, so that’s the network part.
  • The last 8 bits are 0s, so that’s for our hosts.

This means the network itself is 192.168.1.0 (the host bits set to zero), and the broadcast address is 192.168.1.255 (all host bits set to one). The usable host addresses are everything in between: 192.168.1.1 to 192.168.1.254. This is a “/24” network, which gives us 254 usable addresses. You’ll do this binary dance in your head until it becomes second nature.

CIDR Notation: Because Writing 255.255.255.0 is for Chumps

Classless Inter-Domain Routing (CIDR) notation is the sane person’s way to write a subnet mask. Instead of writing out the full dotted-decimal mask, you just slap a slash (/) after the IP address and write the number of bits that are 1s in the mask. It’s brilliantly concise.

So, 192.168.1.42 with a 255.255.255.0 mask becomes 192.168.1.42/24. A 255.255.0.0 mask is a /16. A 255.0.0.0 mask is a /8.

This notation is the key to variable-length subnet masking (VLSM), which is a fancy way of saying “we can break networks into smaller, differently-sized chunks instead of forcing everything into a few fixed sizes.” It’s the reason we can efficiently use our limited address space. Let’s say you need to figure out the network range for 10.0.34.147/21. Doing this by hand is error-prone. Let the computer do it.

import ipaddress

# Define a network using CIDR notation
net = ipaddress.ip_network('10.0.34.147/21', strict=False)
# 'strict=False' is a lifesaver. It lets you use a host IP to define the network.

print(f"Network Address: {net.network_address}")
print(f"Broadcast Address: {net.broadcast_address}")
print(f"Usable Host Range: {list(net.hosts())[0]} - {list(net.hosts())[-1]}")
print(f"Netmask: {net.netmask}")
print(f"CIDR: {net.prefixlen}")
print(f"Total Addresses: {net.num_addresses}")

Running this would show you that /21 gives you a netmask of 255.255.248.0, a network address of 10.0.32.0, and a whopping 2048 total addresses (with 2046 usable hosts). This is why we use libraries.

The Blessed Private Ranges (Your Digital Safe Space)

You can’t just pick any old IP address for your home network. Most of them are owned by someone else and routed on the public internet. Using them would cause chaos. To save us from ourselves, the wise elders of the IETF designated three ranges for “private” use. These addresses are not routable on the public internet; they’re for your internal networks only.

  1. 10.0.0.0/8 (10.0.0.0 - 10.255.255.255): The big one. One single /8 network with over 16 million addresses. This is for corporations, data centers, and anyone who never wants to worry about running out of IPs internally.
  2. 172.16.0.0/12 (172.16.0.0 - 172.31.255.255): The middle child. 16 contiguous /16 networks, offering a sweet spot between size and segmentation. It’s more than you’ll likely ever need at home but less overwhelming than the /8 behemoth.
  3. 192.168.0.0/16 (192.168.0.0 - 192.168.255.255): The people’s champion. 256 separate /24 networks. This is why your home router defaults to 192.168.1.1/24. It’s simple, easy to understand, and perfectly sized for most small networks.

Your router performs Network Address Translation (NAT), which is the magic trick that lets all your private devices share the router’s single public IP address when talking to the internet. It’s a kludge that technically breaks the end-to-end principle of the internet, but it’s also the main reason IPv4 is still functioning today. We’ll grumble about its downsides another time.

Common Pitfalls and “Oh Crap” Moments

  • The All-Zero and All-One Addresses: Never assign them to a host. The first address in a subnet (host bits all 0s) is the network identifier. The last address (host bits all 1s) is the broadcast address. Your OS will usually throw a fit if you even try.
  • The /31 Abomination (and Miracle): For a point-to-point link (like between two routers), you only need two addresses. A /30 (mask 255.255.255.252) gives you 4 addresses, wasting 2. A /31 is a special CIDR prefix designed for exactly two addresses, with no network or broadcast address. It breaks the old rules to avoid waste. Support is widespread now, but it still feels weird. Check your device docs before using it.
  • Mind the Gateway: Your default gateway (usually your router) needs an IP address within the subnet you define. If your network is 192.168.1.0/24, your gateway must be something like 192.168.1.1. I’ve lost hours of my life debugging connectivity issues only to find someone set the gateway to 192.168.2.1. Don’t be that person.