How can I check if an ip is in a network in python

2019-01-03 08:37发布

Given an ip address (say 192.168.0.1), how do I check if it's in a network (say 192.168.0.0/24) in Python?

Are there general tools in Python for ip address manipulation? Stuff like host lookups, ip adddress to int, network address with netmask to int and so on? Hopefully in the standard Python library for 2.5.

25条回答
神经病院院长
2楼-- · 2019-01-03 08:55
#This works properly without the weird byte by byte handling
def addressInNetwork(ip,net):
    '''Is an address in a network'''
    # Convert addresses to host order, so shifts actually make sense
    ip = struct.unpack('>L',socket.inet_aton(ip))[0]
    netaddr,bits = net.split('/')
    netaddr = struct.unpack('>L',socket.inet_aton(netaddr))[0]
    # Must shift left an all ones value, /32 = zero shift, /0 = 32 shift left
    netmask = (0xffffffff << (32-int(bits))) & 0xffffffff
    # There's no need to mask the network address, as long as its a proper network address
    return (ip & netmask) == netaddr 
查看更多
三岁会撩人
3楼-- · 2019-01-03 08:57

The accepted answer doesn't work ... which is making me angry. Mask is backwards and doesn't work with any bits that are not a simple 8 bit block (eg /24). I adapted the answer, and it works nicely.

    import socket,struct

    def addressInNetwork(ip, net_n_bits):  
      ipaddr = struct.unpack('!L', socket.inet_aton(ip))[0]
      net, bits = net_n_bits.split('/')
      netaddr = struct.unpack('!L', socket.inet_aton(net))[0]
      netmask = (0xFFFFFFFF >> int(bits)) ^ 0xFFFFFFFF
      return ipaddr & netmask == netaddr

here is a function that returns a dotted binary string to help visualize the masking.. kind of like ipcalc output.

    def bb(i):
     def s = '{:032b}'.format(i)
     def return s[0:8]+"."+s[8:16]+"."+s[16:24]+"."+s[24:32]

eg:

screen shot of python

查看更多
Lonely孤独者°
4楼-- · 2019-01-03 08:57

from netaddr import all_matching_cidrs

>>> from netaddr import all_matching_cidrs
>>> all_matching_cidrs("212.11.70.34", ["192.168.0.0/24","212.11.64.0/19"] )
[IPNetwork('212.11.64.0/19')]

Here is the usage for this method:

>>> help(all_matching_cidrs)

Help on function all_matching_cidrs in module netaddr.ip:

all_matching_cidrs(ip, cidrs)
    Matches an IP address or subnet against a given sequence of IP addresses and subnets.

    @param ip: a single IP address or subnet.

    @param cidrs: a sequence of IP addresses and/or subnets.

    @return: all matching IPAddress and/or IPNetwork objects from the provided
    sequence, an empty list if there was no match.

Basically you provide an ip address as the first argument and a list of cidrs as the second argument. A list of hits are returned.

查看更多
家丑人穷心不美
5楼-- · 2019-01-03 08:57

From various sources above, and from my own research, this is how I got subnet and address calculation working. These pieces are enough to solve the question and other related questions.

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

    @staticmethod
    def numToDottedQuad(n):
        "convert long int to dotted quad string"
        return socket.inet_ntoa(struct.pack('>L', n))

    @staticmethod
    def makeNetmask(mask):
        bits = 0
        for i in xrange(32-int(mask), 32):
            bits |= (1 << i)
        return bits

    @staticmethod
    def ipToNetAndHost(ip, maskbits):
        "returns tuple (network, host) dotted-quad addresses given"
        " IP and mask size"
        # (by Greg Jorgensen)
        n = iptools.dottedQuadToNum(ip)
        m = iptools.makeMask(maskbits)
        net = n & m
        host = n - mask
        return iptools.numToDottedQuad(net), iptools.numToDottedQuad(host)
查看更多
叛逆
6楼-- · 2019-01-03 08:58

Thank you for your script!
I have work quite a long on it to make everything working... So I'm sharing it here

  • Using netaddr Class is 10 times slower than using binary conversion, so if you'd like to use it on a big list of IP, you should consider not using netaddr class
  • makeMask function is not working! Only working for /8,/16,/24
    Ex:

    bits = "21" ; socket.inet_ntoa(struct.pack('=L',(2L << int(bits)-1) - 1))
    '255.255.31.0' whereas it should be 255.255.248.0

    So I have used another function calcDottedNetmask(mask) from http://code.activestate.com/recipes/576483-convert-subnetmask-from-cidr-notation-to-dotdecima/
    Ex:


#!/usr/bin/python
>>> calcDottedNetmask(21)
>>> '255.255.248.0'
  • Another problem is the process of matching if an IP belongs to a network! Basic Operation should be to compare (ipaddr & netmask) and (network & netmask).
    Ex: for the time being, the function is wrong

#!/usr/bin/python
>>> addressInNetwork('188.104.8.64','172.16.0.0/12')
>>>True which is completely WRONG!!

So my new addressInNetwork function looks-like:


#!/usr/bin/python
import socket,struct
def addressInNetwork(ip,net):
    '''This function allows you to check if on IP belogs to a Network'''
    ipaddr = struct.unpack('=L',socket.inet_aton(ip))[0]
    netaddr,bits = net.split('/')
    netmask = struct.unpack('=L',socket.inet_aton(calcDottedNetmask(bits)))[0]
    network = struct.unpack('=L',socket.inet_aton(netaddr))[0] & netmask
    return (ipaddr & netmask) == (network & netmask)

def calcDottedNetmask(mask):
    bits = 0
    for i in xrange(32-int(mask),32):
        bits |= (1 > 24, (bits & 0xff0000) >> 16, (bits & 0xff00) >> 8 , (bits & 0xff))


And now, answer is right!!


#!/usr/bin/python
>>> addressInNetwork('188.104.8.64','172.16.0.0/12')
False

I hope that it will help other people, saving time for them!

查看更多
三岁会撩人
7楼-- · 2019-01-03 08:58

I don't know of anything in the standard library, but PySubnetTree is a Python library that will do subnet matching.

查看更多
登录 后发表回答