Firewall rules, Fail2ban settings and VPN configs all ask for addresses like 198.51.100.0/24 or 2001:db8::/64. The number after the slash decides how many addresses the rule covers, so getting it wrong can open your server to far more of the internet than you meant, or block your own office. This guide explains CIDR notation in plain terms and shows how to check a range before you put it in a rule.
Before you start
- You only need a basic idea of what an IP address is. If IPv6 is new to you, read IPv4 vs IPv6 first.
- For the calculation examples, any Linux machine with
python3works. That includes a Linux VPS. - Examples use the documentation ranges
203.0.113.0/24,198.51.100.0/24and2001:db8::/32. Replace them with your real addresses.
What CIDR notation means
An IPv4 address is 32 bits long, written as four numbers from 0 to 255. CIDR (Classless Inter-Domain Routing) adds a slash and a number, called the prefix length. It says how many bits, counted from the left, are fixed. The remaining bits can be anything, and every combination is part of the range.
/32fixes all 32 bits. It means exactly one address./24fixes the first 24 bits (the first three numbers). The last number can be 0 to 255, so it covers 256 addresses./16fixes the first two numbers. It covers 65,536 addresses./0fixes nothing. It means every IPv4 address on the internet.
The rule of thumb: a smaller number after the slash means a bigger range. Each step down doubles the size. A /23 is two /24s, and a /25 is half of one.
The number of addresses is 2 to the power of (32 minus the prefix):
/32 -> 2^0 = 1 address
/30 -> 2^2 = 4 addresses
/28 -> 2^4 = 16 addresses
/24 -> 2^8 = 256 addresses
/16 -> 2^16 = 65,536 addressesYou will also see the older netmask form. 255.255.255.0 is the same as /24, and 255.255.255.255 is the same as /32. Linux tools such as ip addr show the CIDR form.
The network address must line up
A range always starts on a boundary that matches its size. 198.51.100.0/24 is valid because the last 8 bits are zero. 198.51.100.77/24 is not a clean network address. Some tools quietly round it down to 198.51.100.0/24, others reject it. Write the network address itself to avoid surprises.
The same applies to smaller blocks. A /28 holds 16 addresses, so valid starts are .0, .16, .32, .48 and so on. 198.51.100.20/28 is not a clean start; the block it belongs to is 198.51.100.16/28, which covers .16 to .31.
IPv6 prefixes: /128, /64 and /48
IPv6 addresses are 128 bits long, so the numbers are bigger, but the idea is the same.
/128is one single IPv6 address, like/32in IPv4./64is the standard size of one IPv6 subnet. A single server is often given a whole/64. That is more addresses than the entire IPv4 internet./56and/48are common sizes handed to a home connection or a site. They contain many/64subnets.
This matters for security. An attacker who controls a /64 can rotate through billions of addresses, so blocking one IPv6 address (/128) often does nothing. When you block an IPv6 source, block its /64. When you allow your own IPv6 connection, allow the prefix your provider gives you, because your device address inside it can change.
Note: Your home or office IPv6 prefix may change when the router restarts, depending on your ISP. If you allowlist it, keep a second way in, such as the browser console in your VPS provider's control panel.
Calculate a range before you use it
Python's ipaddress module is on every modern Linux system and gives an exact answer. This prints the size, first and last address of a range:
python3 -c "import ipaddress as i; n=i.ip_network('198.51.100.16/28'); print(n.num_addresses, n[0], n[-1])"16 198.51.100.16 198.51.100.31If you pass an address that is not on a boundary, Python refuses with has host bits set. That is a useful check: it tells you the range is not what you typed.
To check whether one address falls inside a range:
python3 -c "import ipaddress as i; print(i.ip_address('198.51.100.25') in i.ip_network('198.51.100.16/28'))"On Debian and Ubuntu you can also install ipcalc with sudo apt install ipcalc for a friendlier summary of any IPv4 range.
Using CIDR in firewall rules
Most Linux firewalls take CIDR directly. With UFW, allow SSH only from one office range:
sudo ufw allow from 203.0.113.0/24 to any port 22 proto tcpWith firewalld, trust an admin subnet:
sudo firewall-cmd --permanent --zone=trusted --add-source=203.0.113.0/24In Fail2ban's jail.local, keep your own range from ever being banned:
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 203.0.113.0/24On Windows, New-NetFirewallRule -RemoteAddress 203.0.113.0/24 works the same way.
Warning: Before you restrict SSH (or RDP on port 3389 on Windows) to a range, make sure your current IP is inside it. Check it with the Python test above. A typo such as /42 or the wrong start address can lock you out the moment the rule applies.
Good habits:
- Allow narrowly. Use
/32for a single static IP. Only widen to/24if you really connect from several addresses in that block. - Block broadly with care. Blocking a
/16can cut off a whole ISP or country region, including real customers. - Never allow
0.0.0.0/0or::/0by accident. Those mean "everyone". - Comment your rules. Write down who owns each range so you can remove it later.
Check it works
After adding a CIDR rule, confirm the firewall stored the range you meant. For UFW, sudo ufw status numbered lists each source. For firewalld, sudo firewall-cmd --zone=trusted --list-sources. Then test from an address inside the range and, if you can, from one outside it.
Troubleshooting
- Rule shows a different range than you typed: the tool rounded your address down to the network boundary. Recalculate and use the true network address.
has host bits setin Python or an "invalid" error in a tool: the address is not the start of a block of that size. Fix the start address or the prefix.- Your IPv6 allow rule stopped working: your ISP changed your prefix. Log in through your VPS provider's browser console and update the rule.
- Blocking one IPv6 address had no effect: the attacker moved to another address in the same
/64. Block the/64instead.
Next steps
- Put this to use in your firewall: Open ports with UFW: single ports, ranges and trusted IPs.
- Learn which ports to expose at all: Common server ports and what uses them.
- Get a deeper IPv6 picture: IPv6 basics explained.
