How to check if ip is online in python

Given the ip address (say 192.168.0.1), how to check if it is on the network (say 192.168.0.0/24) in Python?

Does Python have common tools for handling IP addresses? Things like host lookup, ip adddress for int, network address with netmask for int, etc.? Hopefully in the Python standard library for 2.5.

+72
python networking ip-address
May 4 '09 at 8:59
source share
23 answers

This article shows that you can do this with socket and struct without much 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) 

It is output:

 False True 

If you need only one function that accepts strings, it will 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 
+31
May 04 '09 at 9:21 a.m.
source share

I like to use netaddr for this:

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

As noted in the comments of arno_v, the 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!" 
+111
May 04 '09 at 1:35 pm
source share

Using ipaddress ( in stdlib since 3.3 , in 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 probably want to calculate netmask advances, for example

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

Then, for each address, compute a 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 
+78
Jun 17 '09 at 0:15
source share

This code works for me on Linux x86. I really didn’t think about problems with endianess, but I tested it against the ipaddr module using over 200K IP addresses tested against 8 different network strings, and the ipaddr results 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 
+7
Dec 16 '10 at 20:16
source share

I tried the Dave Webb solution, but ran into some problems:

Basically - compliance should be checked using ANDing an IP address using a mask, and then checking the result exactly matches the network address. DO NOT USE the IP address with the network address as it was done.

I also noticed that by simply ignoring Endian behavior, assuming consistency is maintained, you will only work for masks at octet boundaries (/ 24, / 16). To work with other masks (/ 23, / 21), I added "more" to the structure commands and changed the code to create a binary mask to start with all "1" and shift left to (32-mask).

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

Here is 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 
+6
May 10 '12 at 12:57
source share

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

 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) 

What it is, it is much faster than the solutions above with the modules turned on.

+6
Apr 29 '15 at 17:41
source share

The accepted answer does not work ... which makes me angry. The mask is inverse and does not work with any bits that are not a simple 8-bit block (for example, / 24). I adapted the answer and it works well.

  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 binary string with a dotted line to visualize masking .. sort 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

+5
Jun 05 '15 at 21:38
source share

Marc's code is almost correct. The full 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 ...

It is very important to note that the first code has a slight glitch. The IP address 255.255.255.255 is also displayed as a valid IP address for any subnet. I had a hell of a time for this code to work, and thanks to Mark for the correct answer.

+4
Mar 29 '11 at 3:13
source share

Not in the standard library for version 2.5, but ipaddr makes this very easy. I believe this 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) 
+3
Sep 25 '13 at 21:42 on
source share

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 use of 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 specify the ip address as the first argument and the cidrs list as the second argument. The hit list is being returned.

+2
Sep 06 '11 at 17:33
source share
 #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 & lt & lt (32-int (bits))) & 0xffffffff
     # There no need to mask the network address, as long as its a proper network address
     return (ip & netmask) == netaddr 
+2
Apr 7 2018-12-12T00:
source share

Here is the class I wrote for the longest prefix match:

 #!/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 the 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 
+2
Aug 01 '13 at 23:34
source share

I don’t know anything in the standard library, but PySubnetTree is a Python library that will execute subnet subnets.

+1
May 04 '09 at 9:03
source share

Thanks for your script!
I have been working for quite some time so that everything works ... Therefore, I am sharing this here.

  • Using the netaddr class is 10 times slower than using a binary conversion, so if you want to use it in a large IP list, you should not consider the netaddr class
  • The makeMask function does not work! Only works 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 used another function calcDottedNetmask (mask) from http://code.activestate.com/recipes/576483-convert-subnetmask-from-cidr-notation-to-dotdecima/
    Example:

 #!/usr/bin/python >>> calcDottedNetmask(21) >>> '255.255.248.0' 
  • Another problem is the mapping process if the IP belongs to the network! The main operation should be a comparison of (ipaddr and netmask) and (network and network mask).
    Ex: while the function is incorrect.
 #!/usr/bin/python >>> addressInNetwork('188.104.8.64','172.16.0.0/12') >>>True which is completely WRONG!! 

So my new addressInNetwork function is as follows:

 #!/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 the answer is correct!

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

I hope this helps other people, saving time for them!

+1
Jul 06 '10 at 17:10
source share

Regarding 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', ... ) 
+1
Jan 11 '13 at
source share

the previous solution has an error in ip and net == net. The correct ip lookup is ip and netmask = net

error 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"); 
+1
Feb 03 '14 at 12:43
source share

There is an error in the selected answer.

The 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.

+1
Apr 22 '14 at 21:11
source share

There is an API called SubnetTree, available in python, which does 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 a link

+1
Oct 21 '15 at 16:14
source share
 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
truth
False

+1
Feb 17 '16 at 14:50
source share

From various sources above, and from my own research, this is how I got the subnet and address calculation. These parts are enough to resolve the issue and other related issues.

 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) 
0
Aug 20 '15 at 20:35
source share

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') 
0
Apr 17 '17 at 7:44
source share

If you do not want to import other modules, you can 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] 
0
Oct 10 '17 at 8:45
source share

Relying on the "struct" module, you can create problems with type sizes and sizes and are simply not needed. Also there is no socket.inet_aton (). Python works great with dotted IPs:

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

I need to match the IP addresses for each accept () socket call for the entire set of valid source networks, so I prefix the 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 find out if this IP is in one of these networks:

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

Importing modules is not required, and the code is very fast when matching.

0
Nov 06 '17 at 6:32
source share



All Articles