Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

check if an IP is within a range of CIDR in Python

Tags:

python

ip

I know there are some similar questions up here, but they mostly either want to find the range itself (which uses some libraries, like the example that stackoverflow says is a dupe of my question) and is in another language.

I have a way to convert the subnet into the beginning and the end of the range of ip's in a subnet (okay, bad wording, it's simply like1.1.1.1/16 -> (1.1.0.0 , 1.1.255.255))

I now want to check if 1.1.2.2 is within this subnet. Can I simply do a > and < to compare?

ip_range = ('1.1.0.0', '1.1.255.255')
if '1.1.2.2' >= ip_range[0] and '1.1.2.2' <= ip_range[1]:
     return True

When I tested it, it works, but I don't know if it would always work for any ipv4 ip's. I'd assume I'm just comparing ASCII order , so this should always work, but is there any exception?

like image 990
JChao Avatar asked Sep 06 '16 22:09

JChao


People also ask

How do I know if an IP address belongs to CIDR?

To determine if an IP is within the range of IP's as defined by the IP and CIDR netmask bit specifier, it's unnecessary to calculate the beginning and end addresses if you apply the netmask as it's intended (as a mask).

How do you check if an IP address is within a particular subnet Python?

To just test against a single IP, you can just use the subnet mask /32 which means "only this IP address" as a subnet, or you can pass the IP address to IPv4Nework or IPv6Nework constructors and they will return a subnet value for you.

How do I find the CIDR range of addresses?

The formula to calculate the number of assignable IP address to CIDR networks is similar to classful networking. Subtract the number of network bits from 32. Raise 2 to that power and subtract 2 for the network and broadcast addresses. For example, a /24 network has 232-24 - 2 addresses available for host assignment.


2 Answers

In Python 3.3 and later, you should be using the ipaddress module.

from ipaddress import ip_network, ip_address

net = ip_network("1.1.0.0/16")
print(ip_address("1.1.2.2") in net)    # True
like image 76
kindall Avatar answered Nov 22 '22 13:11

kindall


You can't really do string comparisons on a dot separated list of numbers because your test will simply fail on input say 1.1.99.99 as '9' is simply greater than '2'

>>> '1.1.99.99' < '1.1.255.255'
False

So instead you can convert the input into tuples of integers through comprehension expression

def convert_ipv4(ip):
    return tuple(int(n) for n in ip.split('.'))

Note the lack of type checking, but if your input is a proper IP address it will be fine. Since you have a 2-tuple of IP addresses, you can create a function that takes both start and end as argument, pass that tuple in through argument list, and return that with just one statement (as Python allows chaining of comparisons). Perhaps like:

def check_ipv4_in(addr, start, end):
    return convert_ipv4(start) < convert_ipv4(addr) < convert_ipv4(end)

Test it out.

>>> ip_range = ('1.1.0.0', '1.1.255.255')
>>> check_ipv4_in('1.1.99.99', *ip_range)
True

With this method you can lazily expand it to IPv6, though the conversion to and from hex (instead of int) will be needed instead.

like image 21
metatoaster Avatar answered Nov 22 '22 12:11

metatoaster