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 /31 and a /32 the 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.

Network, mask, broadcast Checkpoint
import ipaddress
net = ipaddress.ip_network("192.168.1.42/24", )
print(net)
print(net.)
print(net.)

Tap a piece to place it

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.

Block size and usable hosts Checkpoint
import ipaddress
net = ipaddress.ip_network("192.168.1.42/24", strict=False)
print("block", )
print("usable", )

Tap a piece to place it

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.

Four /26 blocks Checkpoint
import ipaddress
net = ipaddress.ip_network("192.168.1.0/24")
blocks = list(net.(new_prefix=26))
print(len(blocks))
print()
print()

Tap a piece to place it

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.

A /31 and a /32 Checkpoint
import ipaddress
link = ipaddress.ip_network("10.0.0.4/31")
single = ipaddress.ip_network("192.0.2.9/32")
print("link hosts", )
print("single hosts", )
print("single is", )

Tap a piece to place it

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.

Describe a network Checkpoint
import ipaddress
def describe(cidr):
net = ipaddress.ip_network(cidr, strict=False)
return f"{net} has {len(list(net.hosts()))} hosts"
for cidr in ["192.168.1.0/24", "192.168.1.0/26"]:
print()

Tap a piece to place it

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.

A dotted mask Checkpoint
import ipaddress
net = ipaddress.ip_network("192.168.1.42/255.255.255.0", strict=False)
print(net)
print()

Tap a piece to place it

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.

A /8 network Checkpoint

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.

Find the mistake Find the mistake

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

PieceWhat it does
ip_network("10.0.0.0/8")a network, strict by default
strict=Falseaccept an address with host bits set
net.netmaskthe mask in full, 255.255.255.0
net.prefixlenthe prefix as a number, 24
net.network_addressthe lowest address
net.broadcast_addressthe highest address
net.num_addressesthe 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 - 2the host count without building a list
a /31two usable addresses, per RFC 3021

Next steps

Test yourself on this

4 questions and 1 task where you run a real command, with the reasoning explained either way.

Start