152

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.

1
  • Note: if you're doing this because you intend to compare the IP against the Multicast subnets, you should just check is_multicast directly; not only is it easier, but you also get IPv6 thrown in for free! Commented Aug 20, 2024 at 19:30

30 Answers 30

219

Using ipaddress (in the stdlib since 3.3, at PyPi for 2.6/2.7):

>>> import ipaddress >>> ipaddress.ip_address('192.168.0.1') in ipaddress.ip_network('192.168.0.0/24') True 

If you want to evaluate a lot of IP addresses this way, you'll probably want to calculate the netmask upfront, like

n = ipaddress.ip_network('192.0.0.0/16') netw = int(n.network_address) mask = int(n.netmask) 

Then, for each address, calculate the binary representation with one of

a = int(ipaddress.ip_address('192.0.43.10')) a = struct.unpack('!I', socket.inet_pton(socket.AF_INET, '192.0.43.10'))[0] a = struct.unpack('!I', socket.inet_aton('192.0.43.10'))[0] # IPv4 only 

Finally, you can simply check:

in_network = (a & mask) == netw 
Sign up to request clarification or add additional context in comments.

4 Comments

Beware, python-ipaddr behaved quite slow for us, so it may be unsuitable for some cases where a lot of comparsions are required frequently. YMMV, so benchmark yourself.
In some versions, you may need to supply a unicode string instead of a Python str type, like ipaddress.ip_address(u'192.168.0.1') in ipaddress.ip_network(u'192.168.0.0/24') .
I was concerned that this method was iterating over the list of addresses in the network, but the ipaddress module overrides __contains__ method to do it in an efficient way by comparing the integer representations of the network and broadcast addresses, so rest assured if that was your worry.
To check if a network contains a network, you can use overlaps from ipaddress, e.g. ipaddress.ip_network('192.168.0.16/28').overlaps(ipaddress.ip_network('192.168.0.0/24'))
178

I like to use netaddr for that:

from netaddr import CIDR, IP if IP("192.168.0.1") in CIDR("192.168.0.0/24"): print "Yay!" 

As arno_v pointed out in the comments, new version of netaddr does it like this:

from netaddr import IPNetwork, IPAddress if IPAddress("192.168.0.1") in IPNetwork("192.168.0.0/24"): print "Yay!" 

3 Comments

>>> netaddr.all_matching_cidrs("192.168.0.1", ["192.168.0.0/24","212.11.64.0/19"] ) [IPNetwork('192.168.0.0/24')]
Or in the new version: from netaddr import IPNetwork, IPAddress IPAddress("192.168.0.1") in IPNetwork("192.168.0.0/24")
Note that this approach, although nice API, requires installation of third-party module. Whereas the other answer, which discusses builtin ipaddress module, does not.
68

For python3

import ipaddress ipaddress.IPv4Address('192.168.1.1') in ipaddress.IPv4Network('192.168.0.0/24') ipaddress.IPv4Address('192.168.1.1') in ipaddress.IPv4Network('192.168.0.0/16') 

Output :

False True 

1 Comment

The standard lib uses clever bitwise checking so this is the most optimal solution here. github.com/python/cpython/blob/3.8/Lib/ipaddress.py#L690
35

Using Python >= 3.7 ipaddress:

import ipaddress address = ipaddress.ip_address("192.168.0.1") network = ipaddress.ip_network("192.168.0.0/16") print(network.supernet_of(ipaddress.ip_network(f"{address}/{address.max_prefixlen}"))) 

Explanation

You can think of an IP Address as a Network with the largest possible netmask (/32 for IPv4, /128 for IPv6)

Checking whether 192.168.0.1 is in 192.168.0.0/16 is essentially the same as checking whether 192.168.0.1/32 is a subnet of 192.168.0.0/16

5 Comments

...not sure why this answer is not at the top (yet).
Thanks for this helpful answer of the constraint Python >= 3.7? I've seen in the doc that it has been introduced in version 3.3.
even easier, all built in: if IPv4Address('192.0.2.6') in IPv4Network('192.0.2.0/28')
@benzkji Yeah I've commented that under petertc's answer stackoverflow.com/a/51472420/4318281
@benzkji - Although right, checking ip_address in ip_network will be more time consuming
28

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 

10 Comments

Additionally, struct.unpack('L',socket.inet_aton(ip))[0] will fail on architectures where 'L' unpacks to something different than 4 bytes, regardless of endianness.
Continuing on Rafal's comment, to get this to work on a 64-bit Python interpreter, replace the line in question with: return struct.unpack('<L',socket.inet_aton(ip))[0]
I think your solution has a serious bug: addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True (I converted 'L' to '<L' in my 64bit os)
CAUTION: This solution has a serious bug: addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True
This answer has a bug. See answer: stackoverflow.com/questions/819355/…
|
15

This code is working for me on Linux x86. I haven't really given any thought to endianess issues, but I have tested it against the "ipaddr" module using over 200K IP addresses tested against 8 different network strings, and the results of ipaddr are the same as this code.

def addressInNetwork(ip, net): import socket,struct ipaddr = int(''.join([ '%02x' % int(x) for x in ip.split('.') ]), 16) netstr, bits = net.split('/') netaddr = int(''.join([ '%02x' % int(x) for x in netstr.split('.') ]), 16) mask = (0xffffffff << (32 - int(bits))) & 0xffffffff return (ipaddr & mask) == (netaddr & mask) 

Example:

>>> print addressInNetwork('10.9.8.7', '10.9.1.0/16') True >>> print addressInNetwork('10.9.8.7', '10.9.1.0/24') False 

1 Comment

Nice and fast. No need for a library for a few simple logic operations.
11

Wherever possible I'd recommend the built in ipaddress module. It's only available in Python 3 though, but it is super easy to use, and supports IPv6. And why aren't you using Python 3 yet anyway, right?


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

Comments

8

I'm not a fan of using modules when they are not needed. This job only requires simple math, so here is my simple function to do the job:

def ipToInt(ip): o = map(int, ip.split('.')) res = (16777216 * o[0]) + (65536 * o[1]) + (256 * o[2]) + o[3] return res def isIpInSubnet(ip, ipNetwork, maskLength): ipInt = ipToInt(ip)#my test ip, in int form maskLengthFromRight = 32 - maskLength ipNetworkInt = ipToInt(ipNetwork) #convert the ip network into integer form binString = "{0:b}".format(ipNetworkInt) #convert that into into binary (string format) chopAmount = 0 #find out how much of that int I need to cut off for i in range(maskLengthFromRight): if i < len(binString): chopAmount += int(binString[len(binString)-1-i]) * 2**i minVal = ipNetworkInt-chopAmount maxVal = minVal+2**maskLengthFromRight -1 return minVal <= ipInt and ipInt <= maxVal 

Then to use it:

>>> print isIpInSubnet('66.151.97.0', '66.151.97.192',24) True >>> print isIpInSubnet('66.151.97.193', '66.151.97.192',29) True >>> print isIpInSubnet('66.151.96.0', '66.151.97.192',24) False >>> print isIpInSubnet('66.151.97.0', '66.151.97.192',29) 

That's it, this is much faster than the solutions above with the included modules.

1 Comment

{TypeError}'map' object is not subscriptable. You need a o = list(o) after o = map(int, ip.split('.'))
7

Not in the Standard library for 2.5, but ipaddr makes this very easy. I believe it is in 3.3 under the name ipaddress.

import ipaddr a = ipaddr.IPAddress('192.168.0.1') n = ipaddr.IPNetwork('192.168.0.0/24') #This will return True n.Contains(a) 

Comments

6

I tried Dave Webb's solution but hit some problems:

Most fundamentally - a match should be checked by ANDing the IP address with the mask, then checking the result matched the Network address exactly. Not ANDing the IP address with the Network address as was done.

I also noticed that just ignoring the Endian behaviour assuming that consistency will save you will only work for masks on octet boundaries (/24, /16). In order to get other masks (/23, /21) working correctly I added a "greater than" to the struct commands and changed the code for creating the binary mask to start with all "1" and shift left by (32-mask).

Finally, I added a simple check that the network address is valid for the mask and just print a warning if it is not.

Here's the result:

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] ipaddr_masked = ipaddr & (4294967295<<(32-int(bits))) # Logical AND of IP address and mask will equal the network address if it matches if netmask == netmask & (4294967295<<(32-int(bits))): # Validate network address is valid for mask return ipaddr_masked == netmask else: print "***WARNING*** Network",netaddr,"not valid with mask /"+bits return ipaddr_masked == netmask 

2 Comments

This appears to work reliably on 64-bit ('L' fails as the value is 32-bit) and returns the values in a sensible order (ipaddr will be 0xC0A80001 for 192.168.0.1). It also copes with "192.168.0.1/24" as a netmask for "192.168.0.1" (not standard, but possible and easily correctable)
Works perfectly on Python 2.4
6

As of Python 3.7, you can use subnet_of and supernet_of helper methods, which are part of the standard library:

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.

So for your example:

from ipaddress import IPv4Network, IPv4Address # Store IP Address as variable >>> myip = IPv4Address('192.168.0.1') >>> myip IPv4Address('192.168.0.1') # This treats the IP as a subnet >>> myip_subnet = IPv4Network(myip) >>> myip_subnet IPv4Network('192.168.0.1/32') # The other subnet to test membership against >>> other_subnet = IPv4Network('192.168.0.0/24') >>> other_subnet IPv4Network('192.168.0.0/24') # Now we can test >>> myip_subnet.subnet_of(other_subnet) True 

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.

In Python 3, there's the ipaddress module which has tools for IPv4 and IPv6 manipulation. You can convert them to an int, by casting, i.e. int(IPv4Address('192.168.0.1')). Lots of other useful functions in the ipaddress module for hosts, etc.

1 Comment

This is the best answer for Python 3 and checking if one subnet is fully covered by (contained in) another subniet.
4

The choosen answer has a bug.

Following is the correct code:

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 = ((1L << int(bits)) - 1) return ipaddr & netmask == netaddr & netmask 

Note: ipaddr & netmask == netaddr & netmask instead of ipaddr & netmask == netmask.

I also replace ((2L<<int(bits)-1) - 1) with ((1L << int(bits)) - 1), as the latter seems more understandable.

4 Comments

I think the mask conversion ((2L<<int(bits)-1) - 1) is correct. e.g. if the mask is 16, it should be "255.255.0.0" or 65535L, but ((1L << int(bits)) - 1) will get 32767L, which is not right.
@Chris.Q, ((1L << int(bits)) - 1) gives 65535L on my system, with bits set to 16!!
Also, for bits set to 0, ((2L<<int(bits)-1) - 1) is raising error.
Yes, actually no value other than /0, /8, /16, /32 is working properly.
4

Relying on the "struct" module can cause problems with endian-ness and type sizes, and just isn't needed. Nor is socket.inet_aton(). Python works very well with dotted-quad IP addresses:

def ip_to_u32(ip): return int(''.join('%02x' % int(d) for d in ip.split('.')), 16) 

I need to do IP matching on each socket accept() call, against a whole set of allowable source networks, so I precompute masks and networks, as integers:

SNS_SOURCES = [ # US-EAST-1 '207.171.167.101', '207.171.167.25', '207.171.167.26', '207.171.172.6', '54.239.98.0/24', '54.240.217.16/29', '54.240.217.8/29', '54.240.217.64/28', '54.240.217.80/29', '72.21.196.64/29', '72.21.198.64/29', '72.21.198.72', '72.21.217.0/24', ] def build_masks(): masks = [ ] for cidr in SNS_SOURCES: if '/' in cidr: netstr, bits = cidr.split('/') mask = (0xffffffff << (32 - int(bits))) & 0xffffffff net = ip_to_u32(netstr) & mask else: mask = 0xffffffff net = ip_to_u32(cidr) masks.append((mask, net)) return masks 

Then I can quickly see if a given IP is within one of those networks:

ip = ip_to_u32(ipstr) for mask, net in cached_masks: if ip & mask == net: # matched! break else: raise BadClientIP(ipstr) 

No module imports needed, and the code is very fast at matching.

1 Comment

What's this cached_masks referred to??
3

Marc's code is nearly correct. A complete version of the code is -

def addressInNetwork3(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(int(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-mask,32): bits |= (1 << i) return "%d.%d.%d.%d" % ((bits & 0xff000000) >> 24, (bits & 0xff0000) >> 16, (bits & 0xff00) >> 8 , (bits & 0xff)) 

Obviously from the same sources as above...

A very Important note is that the first code has a small glitch - The IP address 255.255.255.255 also shows up as a Valid IP for any subnet. I had a heck of time getting this code to work and thanks to Marc for the correct answer.

1 Comment

Tried and tested. From all the socket/struct examples on this page this is the only correct one
2

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.

Comments

2
 #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 

1 Comment

The code did not work correctly on 64-bit OS, because of incorrect netmask values. I've taken a liberty to fix that.
2

previous solution have a bug in ip & net == net. Correct ip lookup is ip & netmask = net

bugfixed code:

import socket import 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 addressInNetwork(ip,net,netmask): "Is an address in a network" print "IP "+str(ip) + " NET "+str(net) + " MASK "+str(netmask)+" AND "+str(ip & netmask) return ip & netmask == net def humannetcheck(ip,net): address=dottedQuadToNum(ip) netaddr=dottedQuadToNum(net.split("/")[0]) netmask=makeMask(long(net.split("/")[1])) return addressInNetwork(address,netaddr,netmask) print humannetcheck("192.168.0.1","192.168.0.0/24"); print humannetcheck("192.169.0.1","192.168.0.0/24"); 

Comments

1

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!

1 Comment

the current version of the above code gives a traceback in the last line, that you can "|=" an int and a tuple.
1

Relating to all of the above, I think socket.inet_aton() returns bytes in network order, so the correct way to unpack them is probably

struct.unpack('!L', ... ) 

Comments

1
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('/') netaddr = struct.unpack('!L',socket.inet_aton(netaddr))[0] netmask = ((1<<(32-int(bits))) - 1)^0xffffffff return ipaddr & netmask == netaddr & netmask print addressInNetwork('10.10.10.110','10.10.10.128/25') print addressInNetwork('10.10.10.110','10.10.10.0/25') print addressInNetwork('10.10.10.110','10.20.10.128/25') 

$ python check-subnet.py
False
True
False

1 Comment

Can you explain what are you adding to the already given answers?
1

Here is a class I wrote for longest prefix matching:

#!/usr/bin/env python class Node: def __init__(self): self.left_child = None self.right_child = None self.data = "-" def setData(self, data): self.data = data def setLeft(self, pointer): self.left_child = pointer def setRight(self, pointer): self.right_child = pointer def getData(self): return self.data def getLeft(self): return self.left_child def getRight(self): return self.right_child def __str__(self): return "LC: %s RC: %s data: %s" % (self.left_child, self.right_child, self.data) class LPMTrie: def __init__(self): self.nodes = [Node()] self.curr_node_ind = 0 def addPrefix(self, prefix): self.curr_node_ind = 0 prefix_bits = ''.join([bin(int(x)+256)[3:] for x in prefix.split('/')[0].split('.')]) prefix_length = int(prefix.split('/')[1]) for i in xrange(0, prefix_length): if (prefix_bits[i] == '1'): if (self.nodes[self.curr_node_ind].getRight()): self.curr_node_ind = self.nodes[self.curr_node_ind].getRight() else: tmp = Node() self.nodes[self.curr_node_ind].setRight(len(self.nodes)) tmp.setData(self.nodes[self.curr_node_ind].getData()); self.curr_node_ind = len(self.nodes) self.nodes.append(tmp) else: if (self.nodes[self.curr_node_ind].getLeft()): self.curr_node_ind = self.nodes[self.curr_node_ind].getLeft() else: tmp = Node() self.nodes[self.curr_node_ind].setLeft(len(self.nodes)) tmp.setData(self.nodes[self.curr_node_ind].getData()); self.curr_node_ind = len(self.nodes) self.nodes.append(tmp) if i == prefix_length - 1 : self.nodes[self.curr_node_ind].setData(prefix) def searchPrefix(self, ip): self.curr_node_ind = 0 ip_bits = ''.join([bin(int(x)+256)[3:] for x in ip.split('.')]) for i in xrange(0, 32): if (ip_bits[i] == '1'): if (self.nodes[self.curr_node_ind].getRight()): self.curr_node_ind = self.nodes[self.curr_node_ind].getRight() else: return self.nodes[self.curr_node_ind].getData() else: if (self.nodes[self.curr_node_ind].getLeft()): self.curr_node_ind = self.nodes[self.curr_node_ind].getLeft() else: return self.nodes[self.curr_node_ind].getData() return None def triePrint(self): n = 1 for i in self.nodes: print n, ':' print i n += 1 

And here is a test program:

n=LPMTrie() n.addPrefix('10.25.63.0/24') n.addPrefix('10.25.63.0/16') n.addPrefix('100.25.63.2/8') n.addPrefix('100.25.0.3/16') print n.searchPrefix('10.25.63.152') print n.searchPrefix('100.25.63.200') #10.25.63.0/24 #100.25.0.3/16 

Comments

0

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) 

Comments

0

I tried one subset of proposed solutions in these answers.. with no success, I finally adapted and fixed the proposed code and wrote my fixed function.

I tested it and works at least on little endian architectures--e.g.x86-- if anyone likes to try on a big endian architecture, please give me feedback.

IP2Int code comes from this post, the other method is a fully (for my test cases) working fix of previous proposals in this question.

The code:

def IP2Int(ip): o = map(int, ip.split('.')) res = (16777216 * o[0]) + (65536 * o[1]) + (256 * o[2]) + o[3] return res def addressInNetwork(ip, net_n_bits): ipaddr = IP2Int(ip) net, bits = net_n_bits.split('/') netaddr = IP2Int(net) bits_num = int(bits) netmask = ((1L << bits_num) - 1) << (32 - bits_num) return ipaddr & netmask == netaddr & netmask 

Hope useful,

Comments

-1

There is an API that's called SubnetTree available in python that do this job very well. This is a simple example :

import SubnetTree t = SubnetTree.SubnetTree() t.insert("10.0.1.3/32") print("10.0.1.3" in t) 

This is the link

Comments

-1

Here is my code

# -*- coding: utf-8 -*- import socket class SubnetTest(object): def __init__(self, network): self.network, self.netmask = network.split('/') self._network_int = int(socket.inet_aton(self.network).encode('hex'), 16) self._mask = ((1L << int(self.netmask)) - 1) << (32 - int(self.netmask)) self._net_prefix = self._network_int & self._mask def match(self, ip): ''' 判断传入的 IP 是不是本 Network 内的 IP ''' ip_int = int(socket.inet_aton(ip).encode('hex'), 16) return (ip_int & self._mask) == self._net_prefix st = SubnetTest('100.98.21.0/24') print st.match('100.98.23.32') 

Comments

-1

If you do not want to import other modules you could go with:

def ip_matches_network(self, network, ip): """ '{:08b}'.format(254): Converts 254 in a string of its binary representation ip_bits[:net_mask] == net_ip_bits[:net_mask]: compare the ip bit streams :param network: string like '192.168.33.0/24' :param ip: string like '192.168.33.1' :return: if ip matches network """ net_ip, net_mask = network.split('/') net_mask = int(net_mask) ip_bits = ''.join('{:08b}'.format(int(x)) for x in ip.split('.')) net_ip_bits = ''.join('{:08b}'.format(int(x)) for x in net_ip.split('.')) # example: net_mask=24 -> compare strings at position 0 to 23 return ip_bits[:net_mask] == net_ip_bits[:net_mask] 

Comments

-1

Here is the solution using netaddr package

from netaddr import IPNetwork, IPAddress def network_has_ip(network, ip): if not isinstance(network, IPNetwork): raise Exception("network parameter must be {0} instance".format(IPNetwork.__name__)) if not isinstance(ip, IPAddress): raise Exception("ip parameter must be {0} instance".format(IPAddress.__name__)) return (network.cidr.ip.value & network.netmask.value) == (ip.value & network.netmask.value) 

Comments

-1

To avoid having builtin or third party modules change their syntax over time, I created my own that does this. I'm using this as an importable module. I hope this helps someone:

 def subnet_lookup(subnet: str, netmask: str, ip_address: str): """ :param subnet: subnet to test against (as string) :param netmask: mask of subnet :param ip_address: ip to test against subnet and mask :return True if a match; False if not a match Steps: 1) convert entire subnet into one binary word 2) convert entire mask into one binary word 3) determine bcast from comparing subnet and mask 4) convert entire ip_address into one binary word 5) convert entire subnet into decimal 6) convert entire bcast into decimal 7) convert entire ip_address into decimal 8) determine if ip_address falls between subnet and bcast using range(); returns True if yes, False if no """ def convert_whole_to_bin(whole): ip_dec_list = whole.split(".") ip_bin_str = "" for ip in ip_dec_list: binary = dec_to_bin(int(ip)) ip_bin_str += binary return ip_bin_str def dec_to_bin(decimal_octet: int): binary = bin(decimal_octet).replace("0b", "") return binary.rjust(8, '0') def split_binary_into_list(binary_octet: str): bin_list = [] for s in binary_octet: bin_list.append(s) return bin_list def determine_bcast(subnet, netmask): subnet_split = split_binary_into_list(subnet) netmask_split = split_binary_into_list(netmask) bcast_list = [] for subnet, mask in zip(subnet_split, netmask_split): if mask != '0': bcast_list.append(subnet) else: bcast_list.append('1') bcast_bin = "".join(bcast_list) return bcast_bin def bin_to_dec(binary_single_word: str): decimal = int(binary_single_word, 2) return decimal def subnet_lookup(ip_address, subnet, bcast): return ip_address in range(subnet, bcast + 1) # 1) convert entire subnet into one binary word subnet_single_bin = convert_whole_to_bin(whole=subnet) # 2) convert entire mask into one binary word mask_single_bin = convert_whole_to_bin(whole=netmask) # 3) determine bcast from comparing subnet and mask bcast_single_bin = determine_bcast(subnet=subnet_single_bin, netmask=mask_single_bin) # 4) convert entire ip_address into one binary word ip_address_single_bin = convert_whole_to_bin(whole=ip_address) # 5) convert entire subnet into decimal subnet_single_dec = bin_to_dec(binary_single_word=subnet_single_bin) # 6) convert entire bcast into decimal bcast_single_dec = bin_to_dec(binary_single_word=bcast_single_bin) # 7) convert entire ip_address into decimal ip_address_single_dec = bin_to_dec(binary_single_word=ip_address_single_bin) # 8) determine if ip_address falls between subnet and bcast; returns True if yes, False if no lookup_result = subnet_lookup(ip_address=ip_address_single_dec, subnet=subnet_single_dec, bcast=bcast_single_dec) return lookup_result # Testing: subnet = "172.16.0.0" netmask = "255.255.0.0" ip_address = "172.16.255.255" result = subnet_lookup(subnet=subnet, netmask=netmask, ip_address=ip_address) print(result) 

Comments

-1

This function checks if IP Address falls in Private IP Subnet or Public Subnet Domain.

def is_private_ip(ip_address_as_str): '''Takes String IP Address without Cider as input Returns True if the IP Address falls in Private subnet Returns False if IP Address is public ''' class_a=ipaddress.ip_address(ip_address_as_str) in ipaddress.ip_network('10.0.0.0/8') class_b=ipaddress.ip_address(ip_address_as_str) in ipaddress.ip_network('172.16.0.0/12') class_c=ipaddress.ip_address(ip_address_as_str) in ipaddress.ip_network('192.168.0.0/16') class_local_loop=ipaddress.ip_address(ip_address_as_str) in ipaddress.ip_network('127.0.0.0/8') class_apipa=ipaddress.ip_address(ip_address_as_str) in ipaddress.ip_network('169.254.0.0/16') return class_a|class_b|class_c|class_local_loop|class_apipa 

Comments

-1

The other solution is to use IPy library

def is_ip_in_prefix(ip, *prefixes): prefixes_ipset = IPy.IPSet([IPy.IP(item) for item in prefixes]) try: ip_ipset = IPy.IP(ip) return ( ip_ipset in prefixes_ipset or # If the IP is IPv4/IPv6 and prefix is IPv6/IPv4 addresses, we need to convert it to a compatible # format. # >>> IP('192.168.1.1').v46map() # IP('::ffff:192.168.1.1') # >>> IP('::ffff:192.168.1.1').v46map() # IP('192.168.1.1') ip_ipset.v46map() in prefixes_ipset ) except ValueError: return False 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.