I need to block some IPs from some countries but I'm only given the starting IP and the ending IP like this:
11.22.33.44 - 11.22.35.200
I'd like to calculate the subnet to have it like this:
(not accurate)
11.22.33.44/14
How can I determine the subnet given an IP address range in Python?
I haven't spent much time networking recently, but here's how I think you can do this most efficiently.
First of all, it's important to recognize that not all IP ranges can be represented as a single subnet. Let's take a look at a common subnet like
192.168.0.0/24
The /24
indicates that the first 24 bits of 192.168.0.0
give the network prefix, in this case 192.168.0
and the remaining bits are used for host addressing. You get a range from 192.168.0.0
to 192.168.0.255
.
ipcalc
can help us out here. Let's see if it agrees:
$ ipcalc 192.168.0.0 - 192.168.0.255
deaggregate 192.168.0.0 - 192.168.0.255
192.168.0.0/24
So far so good. But what if you want to exclude the .0
or the .255
, which is used for broadcast? There isn't a single subnet that represents that range:
$ ipcalc 192.168.0.0 - 192.168.0.254
deaggregate 192.168.0.0 - 192.168.0.254
192.168.0.0/25
192.168.0.128/26
192.168.0.192/27
192.168.0.224/28
192.168.0.240/29
192.168.0.248/30
192.168.0.252/31
192.168.0.254/32
Subnets grow by powers of two and when our range doesn't slot into that framework cleanly we end up with things like this.
The example you gave, incidentally, doesn't give a single subnet:
$ ipcalc 11.22.33.44 - 11.22.35.200
deaggregate 11.22.33.44 - 11.22.35.200
11.22.33.44/30
11.22.33.48/28
11.22.33.64/26
11.22.33.128/25
11.22.34.0/24
11.22.35.0/25
11.22.35.128/26
11.22.35.192/29
11.22.35.200/32
Python has an ipaddress
module. Let's see if its summarize_address_range()
function agrees with ipcalc
(formatted for readability):
>>> import ipaddress
>>> list(ipaddress.summarize_address_range(
ipaddress.IPv4Address('192.168.0.0'),
ipaddress.IPv4Address('192.168.0.255')))
[IPv4Network('192.168.0.0/24')]
So far so good. How about the second example?
>>> list(ipaddress.summarize_address_range(
ipaddress.IPv4Address('11.22.33.44'),
ipaddress.IPv4Address('11.22.35.200')))
[IPv4Network('11.22.33.44/30'),
IPv4Network('11.22.33.48/28'),
IPv4Network('11.22.33.64/26'),
IPv4Network('11.22.33.128/25'),
IPv4Network('11.22.34.0/24'),
IPv4Network('11.22.35.0/25'),
IPv4Network('11.22.35.128/26'),
IPv4Network('11.22.35.192/29'),
IPv4Network('11.22.35.200/32')]
Looks like a match to me.