How to Check If an Ip Is in a Network in Python

How can I check if an ip is in a network in Python?

This article shows you can do it with socket and struct modules without too much extra effort. I added a little to the article as follows:

import socket,struct

def makeMask(n):
"return a mask of n bits as a long integer"
return (2L<<n-1) - 1

def dottedQuadToNum(ip):
"convert decimal dotted quad string to long integer"
return struct.unpack('L',socket.inet_aton(ip))[0]

def networkMask(ip,bits):
"Convert a network address to a long integer"
return dottedQuadToNum(ip) & makeMask(bits)

def addressInNetwork(ip,net):
"Is an address in a network"
return ip & net == net

address = dottedQuadToNum("192.168.1.1")
networka = networkMask("10.0.0.0",24)
networkb = networkMask("192.168.0.0",24)
print (address,networka,networkb)
print addressInNetwork(address,networka)
print addressInNetwork(address,networkb)

This outputs:

False
True

If you just want a single function that takes strings it would look like this:

import socket,struct

def addressInNetwork(ip,net):
"Is an address in a network"
ipaddr = struct.unpack('L',socket.inet_aton(ip))[0]
netaddr,bits = net.split('/')
netmask = struct.unpack('L',socket.inet_aton(netaddr))[0] & ((2L<<int(bits)-1) - 1)
return ipaddr & netmask == netmask

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

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.

How to check an IP address is within a range of two IPs in Python?

For changing the ip format so that we can compare

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

This function will return True or False if the ip is within range or not

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

ip_range = ('1.1.0.0', '1.1.255.255')

print(check_ipv4_in('1.1.99.99', *ip_range))

It will print 'true' in this case as the function returns True in this case

How do you determine if an IP address is private, in Python?

Check out the IPy module. If has a function iptype() that seems to do what you want:

>>> from IPy import IP
>>> ip = IP('127.0.0.0/30')
>>> ip.iptype()
'PRIVATE'

How to check if an IP is contained in a network with python?

Using Python 3.3+ ipaddress

>>> import ipaddress
>>> ipaddress.ip_address('10.40.0.1') in ipaddress.ip_network('10.40.0.0/24')
True
>>> ipaddress.ip_address('10.40.2.1') in ipaddress.ip_network('10.40.0.0/24')
False

There's also backport of ipaddress.

Using ipaddr

>>> import ipaddr
>>> ipaddr.IPAddress('10.40.0.1') in ipaddr.IPNetwork('10.40.0.0/24')
True
>>> ipaddr.IPAddress('10.40.2.1') in ipaddr.IPNetwork('10.40.0.0/24')
False

Find if IP in set of ip addresses and ip networks

One way would be to use the ipaddress module to build a set of IPv4Address instances:

>>> from ipaddress import *
>>> from itertools import *
>>>
>>> p = {'127.0.0.1', '138.56.76.02', '192.4.2.0/24', '29.24.48.80', ...}
>>>
>>> all_hosts = set(chain.from_iterable(IPv4Network(n) for n in p))
>>>
>>> IPv4Address('192.4.2.4') in all_hosts
True
>>> IPv4Address('29.24.48.80') in all_hosts
True
>>> IPv4Address('29.24.48.81') in all_hosts
False

This takes advantage of the fact that constructing an IPv4Network from just an address (with no mask) creates a network with just that address in it. It also uses the feature that iterating an IPv4Network gives you each host in turn.

The all_hosts set will be slow to build and large in memory if p is large or the netmasks contain many hosts. However, after that, checking if an IP address is in the set is fast (O(1) on average).

All this still works if p already contains IPv4Network and IPv4Address instances.

Check if IP is in network on Python3

What you are describing as a list is actually a tuple.

First, when I ran your code I did not receive the error you are getting

ValueError: b'82.148.47.64' does not appear to be an IPv4 or IPv6 address

Instead I received the following

raise ValueError('%s has host bits set' % self)
ValueError: 1.1.6.0/20 has host bits set

Is this the error your are actually receiving? If so, this is how to properly correct it.

Referenced from ipaddress module Defining Networks:

By default, attempting to create a network object with host bits set will result in ValueError being raised. To request that the additional bits instead be coerced to zero, the flag strict=False can be passed to the constructor:

This is because the host bits are set and will need to be coerced to zero, as the documentation states above. Pass the following flag strict=False to the constructor.

For example.

subnet = ip_network(network[0], strict=False) 

Also, in your ips contained in your tuple need only to be formatted to a string.

For example.

ips = ((8888, 'customer', '2.8.4.64', '8888*200')

OR the following will be presented to you.

'ValueError: b'2.8.4.64' does not appear to be an IPv4 or IPv6 address'

The full working code.

from ipaddress import ip_network, ip_address
networks = (('1.1.6.0/20',), ('2.8.2.0/19',), ('7.2.2.0/19',), ('2.2.0.0/19',))

ips = ((8888, 'customer', b'2.8.4.64', '8888*200'),(8888, 'customer', b'1.1.6.3', '8888*201'), (8888, 'customer', b'122.223.159.3', '8888*202'))

straglers = list()

for ip in ips:
exclude = 0
for network in networks:
subnet = ip_network(network[0], strict=False)
print(ip_address(ip[2].decode('utf-8')))
print(subnet)
if ip_address(ip[2].decode('utf-8')) in subnet:
exclude = 1
if exclude == 0:
straglers.append([ip[3],ip[2],ip[1]]) # extension, customer_ip, company
print(straglers)


Related Topics



Leave a reply



Submit