btongeorge
btongeorge

Reputation: 453

Check if IP is in network on Python3

I am trying to run a routine on two lists, sourced from MySQL queries - one contains CIDR networks and the other contains IP addresses. I am trying to compare entries in the IP list to see whether they are in the networks described by the CIDR list, and act on those that are not.

I am trying to use the netaddr module but this doesn't appear to be implemented on Python3 yet?

I have also tried to use ipaddress but I can't seem to get them to compare correctly. Using ipaddress I have the following code:

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])
        if ip_address(ip[2]) in subnet:
            exclude = 1
    if exclude == 0:
        straglers.append([ip[3],ip[2],ip[1]]) # extension, customer_ip, company

As things stand the code gives a value error as follows: ValueError: b'82.148.47.64' does not appear to be an IPv4 or IPv6 address

I have tried converting ip[2] to an utf-8 string but this makes no difference.

Upvotes: 1

Views: 1932

Answers (1)

user7548672
user7548672

Reputation:

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)  

Upvotes: 4

Related Questions