Track 3 · Lesson 3 of 5
Addresses in Python
Work out networks, masks, host counts and subnets in whole programs built from blanks, with the ipaddress module.
Subnetting is bit arithmetic, and bit arithmetic done by hand on a phone is a way to make mistakes. Python ships a module that does all of it, including the two cases people get wrong: a /31 and a /32.
Each program below is six to nine lines with a few gaps. Fill them, press Run, and read the figures.
What you'll be able to do
- Build a network from an address and a prefix, and read three figures off it.
- Tell the block size apart from the usable host count.
- Split a network into smaller ones and read the first and last.
- Handle a
/31and a/32the way the RFCs actually say. - Recognise the one call that will exhaust memory on a large block.
Step 1: Three figures off one network
An address on its own is not a network. You need the prefix, and you need to tell the module what to do when the address has host bits set.
Tap a piece to place it
One gap lets the module accept an address with host bits set. The other two read the mask and the top address.
Turn the switch off when you want to place the pieces yourself, and the mistakes become yours to find.
Seven lines, three figures. 192.168.1.42/24 is an address, not a network, because .42 is a host bit. With strict=True, which is the default, the module raises ValueError: 192.168.1.42/24 has host bits set. With strict=False it works out which network you meant.
Note that print(net) shows the prefix as well: 192.168.1.0/24, not 192.168.1.0. The prefix is part of what a network is.
Step 2: Block size and host count are different numbers
Two figures that people quote interchangeably and should not.
Tap a piece to place it
One gap is the size of the block. The other is the addresses a machine can be given.
Turn the switch off when you want to place the pieces yourself, and the mistakes become yours to find.
256 addresses in the block, 254 of them usable, because the network address and the broadcast address cannot be given to a machine. net.prefixlen would print 24, which is the prefix rather than a count.
Step 3: Split it up and read the ends
subnets cuts a network into smaller ones. This program asks for four /26 blocks and shows you the first and the last.
Tap a piece to place it
One gap makes the smaller blocks. The other two read the first and the last out of the list.
Turn the switch off when you want to place the pieces yourself, and the mistakes become yours to find.
Nine lines. A /24 holds four /26 blocks, each with 64 addresses. blocks[0] is the first and blocks[-1] is the last, because a negative index counts back from the end.
Borrowing bits doubles the count for every bit you take: one bit gives two blocks, two bits give four. That is the one piece of arithmetic worth holding in your head.
Step 4: The two cases most calculators get wrong
A /31 has two addresses and both are usable, because there is no room to reserve a network or a broadcast address. RFC 3021 defines this for point-to-point links.
Tap a piece to place it
Ask each network for its hosts, then print the one address the /32 has.
Turn the switch off when you want to place the pieces yourself, and the mistakes become yours to find.
Eight lines, and the first figure is 2, not 0. Plenty of subnet calculators subtract two from a /31 and report that no host can be given an address, which is wrong. The module follows the RFC rather than the folk rule.
The /32 is a single address, and it is both the network and the host, which is why the last line prints the same address twice over.
Step 5: A function that describes any network
Now put it together: a function that takes a CIDR and returns a sentence, called in a loop.
Tap a piece to place it
Call the function with the loop variable.
Turn the switch off when you want to place the pieces yourself, and the mistakes become yours to find.
Nine lines, one gap, and two different answers from the same function. That is what a function is for: write the logic once, call it for each value.
A warning worth knowing. That len(list(net.hosts())) is fine for a /24, which builds 254 addresses, and it will exhaust memory on a 10.0.0.0/8, which tries to build sixteen million of them at once. For a big block use arithmetic instead: net.num_addresses - 2. The lesson here is that a call which works on your test network can fail on a real one.
Step 6: A mask instead of a prefix
People write 255.255.255.0 as often as they write /24. The module takes either.
Tap a piece to place it
The second line should show the prefix length that mask is worth.
Turn the switch off when you want to place the pieces yourself, and the mistakes become yours to find.
Six lines, and net.prefixlen gives you 24 back from a dotted mask. The module also rejects a mask that is not a run of ones followed by zeros, which is a check worth having.
Step 7: Type one yourself
Print the network that 10.1.2.3/8 belongs to, then its broadcast address, one per line.
Use ip_network with strict=False, then print the network and its broadcast_address on two lines.
import ipaddress net = ipaddress.ip_network("10.1.2.3/8", strict=False) print(net) print(net.broadcast_address)Runs in your browser, and nothing is sent anywhere. Python starts loading in the background as you reach this cell, about six megabytes once. After that every cell on the site runs instantly until you close the tab.
Do not add len(list(net.hosts())) to this one. A /8 holds sixteen million addresses, and building the list will fail.
Step 8: A mistake to find
This one raises. Press Run and read the last line.
An address with host bits set is not a network. The module is strict by default.
import ipaddress print(ipaddress.ip_network("192.168.1.42/24", strict=False))Runs in your browser, and nothing is sent anywhere. Python starts loading in the background as you reach this cell, about six megabytes once. After that every cell on the site runs instantly until you close the tab.
ValueError: 192.168.1.42/24 has host bits set. The module is telling you that you handed it an address and asked for a network. Either give it a real network address, or say strict=False and let it work out which network you meant.
Quick reference
| Piece | What it does |
|---|---|
ip_network("10.0.0.0/8") | a network, strict by default |
strict=False | accept an address with host bits set |
net.netmask | the mask in full, 255.255.255.0 |
net.prefixlen | the prefix as a number, 24 |
net.network_address | the lowest address |
net.broadcast_address | the highest address |
net.num_addresses | the block size, 256 |
net.hosts() | the addresses a machine can be given |
net.subnets(new_prefix=26) | smaller blocks inside it |
blocks[-1] | the last item of a list |
net.num_addresses - 2 | the host count without building a list |
a /31 | two usable addresses, per RFC 3021 |
Next steps
- Build a subnet calculator does the same arithmetic in shell, so you can see what the module is doing underneath.
- Networking basics covers the addresses and ports this lesson assumes.
- DNS and addresses is where a name becomes one of these addresses.
Test yourself on this
4 questions and 1 task where you run a real command, with the reasoning explained either way.