IP Addressing & Subnetting
Why this matters
Every routing decision, firewall rule, and cloud network you will ever configure is expressed in terms of IP addresses and subnets. If you cannot look at 10.0.4.7/22 and immediately say what range it belongs to and whether another address is in the same network, you will misread routes, open firewall holes by accident, and be unable to debug "why can't these two machines talk?" Subnetting is the one piece of arithmetic in this whole track worth doing by hand until it is automatic.
Concepts
What an IP address is
An IPv4 address is a 32-bit number, written as four octets (bytes) in dotted-decimal: 192.168.1.10. Each octet is 0–255. That's it — 192.168.1.10 is just a friendlier way to write one 32-bit number. An address identifies an interface on a host, not the host itself; a machine with two network cards has two addresses.
An address alone is not enough to communicate. A host also needs a subnet mask, which splits the 32 bits into a network part (shared by every host on the same local network) and a host part (unique to each host within it). Think of it like a postal address: the network part is the street, the host part is the house number. Everyone on the same street can hand mail to each other directly; anything for another street goes to the post office (the gateway).
CIDR notation and the subnet mask
The mask is written two equivalent ways. The old way is a dotted-decimal mask like 255.255.255.0. The modern way is CIDR: a slash and the number of network bits, like /24. /24 means "the first 24 bits are network, the remaining 8 are host" — which is exactly 255.255.255.0 (24 one-bits followed by 8 zero-bits). So 192.168.1.10/24 says: network bits are the first 24, host bits are the last 8.
The number of host bits determines how many addresses the network holds: 2^(host bits). A /24 has 8 host bits = 256 addresses. But two of those are reserved: the network address (all host bits 0, e.g. 192.168.1.0) names the network itself, and the broadcast address (all host bits 1, e.g. 192.168.1.255) reaches everyone on it. So a /24 gives 256 - 2 = 254 usable host addresses. General rule: usable hosts = 2^(host bits) - 2.
Reading a subnet: network, broadcast, and range
To find the network address, keep the network bits and set all host bits to zero. For 10.0.4.7/22: /22 means 22 network bits, 10 host bits. The third octet is where the boundary falls (bits 17–24 are the third octet, so the /22 boundary is 6 bits into the third octet). The block size in the third octet is 256 - 252 = 4 (since a /22 mask third octet is 252). So networks step by 4 in the third octet: 10.0.0.0, 10.0.4.0, 10.0.8.0... 10.0.4.7 falls in the 10.0.4.0/22 block, which spans 10.0.4.0 through 10.0.7.255, with broadcast 10.0.7.255 and usable hosts 10.0.4.1–10.0.7.254.
The mechanical trick: for the octet where the mask isn't 0 or 255, the block size is 256 - mask_octet. Network boundaries are multiples of that block size. Find the largest multiple ≤ your address's octet, and you've found the network. Do this by hand a dozen times and it becomes instant; ipcalc (below) checks your work.
Public vs private addresses
Some address ranges are reserved as private — usable freely inside any organization but never routed on the public internet. Memorize them:
10.0.0.0/8(10.x.x.x) — 16 million addresses172.16.0.0/12(172.16.x.x – 172.31.x.x) — note it's only 16–31, not all of 172192.168.0.0/16(192.168.x.x)
Your home router, WSL2, and Docker all hand out private addresses. Because private ranges repeat in every network on earth, a packet from a private address can't be delivered across the internet — it must be translated to a public address first (NAT, module 05). Public addresses are globally unique and assigned by registries. Also note 127.0.0.0/8 (loopback, stays on the local machine) and 169.254.0.0/16 (link-local, a fallback when no address was configured — seeing one usually means DHCP failed).
The "local or gateway?" decision
Here is why the mask matters operationally. When a host wants to send a packet, it applies its own mask to both its address and the destination address. If the network parts match, the destination is on the same local network and the host delivers directly over the link layer (resolving the destination's MAC via ARP). If they differ, the destination is remote, and the host sends the packet to its default gateway instead. This single comparison, made for every packet, is the whole reason a wrong subnet mask breaks connectivity: get the mask wrong and the host either tries to deliver locally something that's remote, or ships to the gateway something that was a neighbor all along.
VLSM: subnets don't have to be equal size
Everything so far assumed carving a block into equal-size pieces. Real
networks rarely need that — a point-to-point link between two routers
needs 2 addresses, an office LAN needs 100. VLSM (Variable Length
Subnet Masking) is simply the practice of giving each subnet exactly the
prefix length its own host count needs, instead of forcing every subnet
in a network to share one mask. Given 10.0.0.0/24 and three needs (100
hosts, 50 hosts, 2 hosts), you'd carve a /25 (126 usable, covers the
100-host need) for the first, a /26 (62 usable) for the second carved
out of what's left, and a /30 (2 usable) for the point-to-point link out
of what's left after that — each boundary computed with the same
block-size trick from above, just applied repeatedly with a shrinking
mask instead of once with a fixed one. The only rule: once a block is
handed out, the next one starts immediately after it ends, and it can't
overlap. VLSM is why real address plans look like an irregular patchwork
of different prefix lengths rather than one uniform size everywhere.
Supernetting: the reverse operation
Supernetting goes the other direction: combining several
contiguous, equal-size smaller blocks into one larger block described
by a shorter (less specific) prefix, so a router can advertise or match
them with a single route instead of several. Four adjacent /24s —
192.168.0.0/24 through 192.168.3.0/24 — combine into one 192.168.0.0/22
only if the first address is itself a valid /22 boundary (a multiple of
the /22 block size, 4, in the second-to-last-varying octet here) and all
four blocks are present with no gaps. This is also called CIDR route
aggregation or route summarization: an ISP holding
203.0.113.0/24 through 203.0.116.0/24-ish ranges advertises one
summarized prefix upstream instead of dozens of individual /24 routes,
keeping the internet's global routing table from growing without bound —
the same "one route instead of many, if the blocks line up" idea reused
at internet scale (module 08 picks this back up as route
aggregation/CIDR in the context of routing protocols).
The check for "can these combine?" is the same longest-prefix-match arithmetic in reverse: take the proposed shorter prefix, compute its network address and block size, and confirm every one of the smaller blocks falls inside it contiguously, starting exactly at that boundary. If the smaller blocks don't start at a valid boundary for the wider mask, or there's a gap, they cannot be summarized into one clean prefix — you'd need two summary routes instead of one, or to leave them unaggregated.
IPv6 in one breath
IPv4's 32 bits (~4 billion addresses) ran out, so IPv6 uses 128 bits, written as eight groups of four hex digits: 2001:0db8:0000:0000:0000:ff00:0042:8329. Long runs of zeros compress: leading zeros in a group drop, and one run of all-zero groups becomes ::, giving 2001:db8::ff00:42:8329. The concepts transfer directly — there's still a prefix length (/64 is the standard subnet size), still network and host portions, still public and special ranges (fe80::/10 is link-local, ::1 is loopback). You will meet IPv6 more in the Azure track; for now, know it exists, know ::1 is "localhost," and know the CIDR idea is identical.
Command reference
| Command | What it does | Example |
|---|---|---|
ip addr |
Shows interfaces, their IP addresses, and prefix lengths | ip -brief addr |
ip route |
Shows which subnets are reachable directly vs via the gateway | ip route get 8.8.8.8 |
ipcalc |
Calculates network, broadcast, and host range from a CIDR | ipcalc 10.0.4.7/22 |
ping |
Tests reachability of a specific address | ping -c 3 192.168.1.1 |
ip addr add |
Assigns an address+mask to an interface (needs sudo) | sudo ip addr add 10.0.0.5/24 dev eth0 |
ip addr del |
Removes an address from an interface (needs sudo) | sudo ip addr del 10.0.0.5/24 dev eth0 |
Flag breakdowns:
ip -brief addr—-brief(or-br) prints one compact line per interface (name, state, addresses) instead of the verbose multi-line default; far easier to scan.ip route get 8.8.8.8—getasks the kernel to show exactly which route and gateway this specific destination would use, resolving the "local or gateway?" decision for you.ipcalc 10.0.4.7/22— takes an address in CIDR form and prints the network address, broadcast, netmask, and usable host range; add-bon some versions to suppress the binary display.sudo ip addr add 10.0.0.5/24 dev eth0—addassigns a new address;10.0.0.5/24is the address plus prefix length (mask);dev eth0names the interface it's bound to.
Hands-on exercises
Read your own subnet. Run
ip -brief addr. Take youreth0address with its/prefixand runipcalc <that-address>. Confirm the network address, broadcast, and host range. Expected: for172.28.20.5/20, network172.28.16.0, broadcast172.28.31.255, 4094 usable hosts.Subnet by hand, then check. Without tools, compute the network and broadcast for
192.168.10.130/26. (Hint: /26 → mask octet 192 → block size 64 → boundaries 0,64,128,192.) Then verify withipcalc 192.168.10.130/26. Expected: network192.168.10.128, broadcast192.168.10.191, hosts.129–.190.Same network or not? Given
10.1.2.3/23and10.1.3.200/23, decide by hand whether they're in the same subnet, then verify withipcalcon each. Expected: /23 block size 2 in the third octet → both fall in10.1.2.0/23(spanning10.1.2.0–10.1.3.255), so yes, same network.Let the kernel decide local vs remote. Run
ip route get <an-IP-on-your-subnet>andip route get 8.8.8.8. Compare: the on-subnet one shows a directdevwith novia; the remote one showsvia <gateway>. You've watched the "local or gateway?" decision happen.Count the hosts. For each of /30, /29, /28, /24, /16, state the number of usable hosts from memory (
2^(32-prefix) - 2), then confirm a couple withipcalc. Expected: /30 → 2, /29 → 6, /28 → 14, /24 → 254, /16 → 65534.Spot the private ranges. For
172.15.0.1,172.20.0.1,192.168.5.5,10.255.255.254, and169.254.10.10, label each as private, public, or special. Expected:172.15is public (private is only 16–31);172.20private;192.168.5.5private;10.255.255.254private;169.254.xlink-local (DHCP-failure fallback).Create and remove an address. On a throwaway interface (or
eth0, carefully), runsudo ip addr add 10.99.99.2/24 dev eth0, confirm withip -br addr, thensudo ip addr del 10.99.99.2/24 dev eth0. Expected: the address appears then disappears. (Don't remove your primary address.)Diagnose and fix: wrong subnet mask. Set up the failure:
sudo ip addr add 10.50.0.10/28 dev eth0. Nowip route get 10.50.0.200— with a /28,10.50.0.200is outside your10.50.0.0/28block (which ends at.15), so the kernel routes it via the gateway even though you intended them to be neighbors on a /24. The symptom "host on the same LAN is unreachable" is classically a mask that's too narrow. Fix: remove and re-add with the correct mask —sudo ip addr del 10.50.0.10/28 dev eth0thensudo ip addr add 10.50.0.10/24 dev eth0— and re-runip route get 10.50.0.200to confirm it's now treated as local (directdev, novia). Clean up withip addr delafterward.VLSM by hand. Given
192.168.20.0/24, carve out a subnet for 100 hosts, then a subnet for 50 hosts from what's left, then a subnet for 2 hosts (a point-to-point link) from what's left after that. Work out each prefix length and boundary before checking: /25 (192.168.20.0/25, 126 usable) for the first; /26 (192.168.20.128/26, 62 usable) for the second; /30 (192.168.20.192/30, 2 usable) for the third. Confirm each withipcalc.Supernet four /24s and check the boundary rule. Given
10.4.0.0/24,10.4.1.0/24,10.4.2.0/24,10.4.3.0/24, verify by hand that these summarize cleanly into10.4.0.0/22(compute the /22's block size in the third octet — 4 — and confirm10.4.0.0is a multiple of it and all four /24s are contiguous with no gap). Then try summarizing10.4.1.0/24through10.4.4.0/24instead — explain why this set does not summarize into one clean CIDR block.
Independent challenge
You are handed the block 172.16.0.0/22 for a small lab and told to carve it into four equal subnets, one per team, each needing at least 100 usable hosts. Determine the correct prefix length for the four subnets, list the network address, usable range, and broadcast for each, and state which subnet the address 172.16.2.150 lands in. This builds directly on the "local or gateway?" and block-size ideas here; it also leans on the layering model from module 00 — specifically why a host on team 2's subnet reaching a host on team 3's subnet must go through a gateway rather than delivering directly.
Stuck? One hint
Four equal subnets means borrowing 2 host bits from the /22 (because 2^2 = 4), giving you four /24s. Check the host count survives the requirement: a /24 has 254 usable hosts, comfortably above 100. Now just step through the third octet in blocks of 1 (since these are /24s within the /22): the four networks are 172.16.0.0, 172.16.1.0, 172.16.2.0, 172.16.3.0. Place 172.16.2.150 by its third octet.
Common mistakes & troubleshooting
- Off-by-one on the block size. The block size is
256 - mask_octet, and networks start at multiples of it including zero. Forgetting the zero boundary (x.x.0.0) is the most common subnetting error. - Assuming 172 is all private. Only
172.16.0.0through172.31.255.255(a /12) is private.172.15.x.xand172.32.x.xare public. This trips people constantly. - Forgetting the two reserved addresses. The network and broadcast addresses are not assignable to hosts. A /30 (common for point-to-point links) has 4 addresses but only 2 usable.
- Confusing prefix length with host count directly.
/24is not "24 hosts." It's 24 network bits, leaving 8 host bits = 254 usable. Always convert to host bits first. - A
169.254.x.xaddress means something failed. If a host self-assigned a link-local address, it means it never got a real one (DHCP failure). Don't try to route through it — fix the address assignment. - Trying to supernet blocks that don't start on a valid boundary, or that have a gap.
10.4.1.0/24through10.4.4.0/24looks like four contiguous /24s but does not summarize into one clean CIDR block, because10.4.1.0is not a multiple of the /22 block size (4) in the third octet — the valid /22 boundaries are10.4.0.0,10.4.4.0,10.4.8.0... A summary route must start exactly on its own boundary, not wherever your blocks happen to begin. - Changing your primary address over SSH/WSL. Deleting the address you're connected through will drop your session. Practice
ip addr add/delon a spare address, not your lifeline.
Checkpoint quiz
Write down your answer to each question before expanding it — checking without attempting first is the single easiest way to fool yourself into thinking you've learned this.
- Convert
/26to a dotted-decimal mask and state how many usable hosts it provides. - What is the network address and broadcast for
10.20.30.200/27? - Are
192.168.1.100/24and192.168.2.100/24in the same subnet? What happens when the first tries to reach the second? - Which of these are private:
10.0.0.1,172.31.255.1,172.32.0.1,192.168.0.1? - Why does a host need the subnet mask, not just its own address, to send a packet?
- What does a
169.254.x.xaddress usually indicate? - How many usable hosts in a
/30, and what is it commonly used for? - What is VLSM, and why do real address plans end up with subnets of different prefix lengths instead of one uniform size?
- What two conditions must hold for a set of contiguous /24 blocks to be summarized into a single, shorter-prefix supernet route?
Show answers
/26=255.255.255.192(26 one-bits). Host bits = 6, so2^6 - 2 = 62usable hosts./27→ mask octet 224, block size 32.200falls in the block starting at192. Network10.20.30.192, broadcast10.20.30.223, hosts.193–.222.- No — different network parts (
192.168.1vs192.168.2). The first host sees the destination as remote and sends it to its default gateway rather than delivering directly. - Private:
10.0.0.1,172.31.255.1,192.168.0.1. Public:172.32.0.1(private range stops at 172.31). - The mask tells the host which bits are network vs host, which is how it decides whether a destination is local (deliver directly) or remote (send to the gateway). Without it, that decision is impossible.
- Link-local self-assignment — the host failed to obtain an address (e.g., DHCP didn't answer).
2^2 - 2 = 2usable hosts. Commonly used for point-to-point links between two routers, where exactly two addresses are needed.- VLSM means giving each subnet the prefix length its own host count actually needs (a /25 for 100 hosts, a /30 for a 2-host link), instead of forcing every subnet in a network to share one uniform mask — the result is an irregular patchwork of different-length blocks carved sequentially out of the original allocation.
- Supernetting (route aggregation/summarization) combines several contiguous, equal-size blocks into one wider, less-specific prefix, but only if the first block starts exactly on a valid boundary for the wider mask and there's no gap between the blocks — otherwise they can't be expressed as one clean CIDR route and must stay separate (or be summarized as more than one route).
Free PDF notes
Download these notes as a printable PDF, with every diagram and interview questions: SD-B-006: IP Addresses, Subnets & CIDR. Each section in one file: Phase 2, Networking (PDF).
Next
02 — DNS fundamentals: you can now reason about addresses, but humans use names. Learn how example.com becomes an IP before any packet is ever sent.