Convert IP address to ulong in Python [duplicate] - python

How would I use python to convert an IP address that comes as a str to a decimal number and vice versa?
For example, for the IP 186.99.109.000 <type'str'>, I would like to have a decimal or binary form that is easy to store in a database, and then retrieve it.

converting an IP string to long integer:
import socket, struct
def ip2long(ip):
"""
Convert an IP string to long
"""
packedIP = socket.inet_aton(ip)
return struct.unpack("!L", packedIP)[0]
the other way around:
>>> socket.inet_ntoa(struct.pack('!L', 2130706433))
'127.0.0.1'

Here's a summary of all options as of 2017-06. All modules are either part of the standard library or can be installed via pip install.
ipaddress module
Module ipaddress (doc) is part of the standard library since v3.3 but it's also available as an external module for python v2.6,v2.7.
>>> import ipaddress
>>> int(ipaddress.ip_address('1.2.3.4'))
16909060
>>> str(ipaddress.ip_address(16909060))
'1.2.3.4'
>>> int(ipaddress.ip_address(u'1000:2000:3000:4000:5000:6000:7000:8000'))
21268296984521553528558659310639415296L
>>> str(ipaddress.ip_address(21268296984521553528558659310639415296L))
u'1000:2000:3000:4000:5000:6000:7000:8000'
No module import (IPv4 only)
Nothing to import but works only for IPv4 and the code is longer than any other option.
>>> ipstr = '1.2.3.4'
>>> parts = ipstr.split('.')
>>> (int(parts[0]) << 24) + (int(parts[1]) << 16) + \
(int(parts[2]) << 8) + int(parts[3])
16909060
>>> ipint = 16909060
>>> '.'.join([str(ipint >> (i << 3) & 0xFF)
for i in range(4)[::-1]])
'1.2.3.4'
Module netaddr
netaddr is an external module but is very stable and available since Python 2.5 (doc)
>>> import netaddr
>>> int(netaddr.IPAddress('1.2.3.4'))
16909060
>>> str(netaddr.IPAddress(16909060))
'1.2.3.4'
>>> int(netaddr.IPAddress(u'1000:2000:3000:4000:5000:6000:7000:8000'))
21268296984521553528558659310639415296L
>>> str(netaddr.IPAddress(21268296984521553528558659310639415296L))
'1000:2000:3000:4000:5000:6000:7000:8000'
Modules socket and struct (ipv4 only)
Both modules are part of the standard library, the code is short, a bit cryptic and IPv4 only.
>>> import socket, struct
>>> ipstr = '1.2.3.4'
>>> struct.unpack("!L", socket.inet_aton(ipstr))[0]
16909060
>>> ipint=16909060
>>> socket.inet_ntoa(struct.pack('!L', ipint))
'1.2.3.4'

Use class IPAddress in module netaddr.
ipv4 str -> int:
print int(netaddr.IPAddress('192.168.4.54'))
# OUTPUT: 3232236598
ipv4 int -> str:
print str(netaddr.IPAddress(3232236598))
# OUTPUT: 192.168.4.54
ipv6 str -> int:
print int(netaddr.IPAddress('2001:0db8:0000:0000:0000:ff00:0042:8329'))
# OUTPUT: 42540766411282592856904265327123268393
ipv6 int -> str:
print str(netaddr.IPAddress(42540766411282592856904265327123268393))
# OUTPUT: 2001:db8::ff00:42:8329

Since Python 3.3 there is the ipaddress module that does exactly this job among others: https://docs.python.org/3/library/ipaddress.html. Backports for Python 2.x are also available on PyPI.
Example usage:
import ipaddress
ip_in_int = int(ipaddress.ip_address('192.168.1.1'))
ip_in_hex = hex(ipaddress.ip_address('192.168.1.1'))

Here's One Line Answers:
import socket, struct
def ip2long_1(ip):
return struct.unpack("!L", socket.inet_aton(ip))[0]
def ip2long_2(ip):
return long("".join(["{0:08b}".format(int(num)) for num in ip.split('.')]), 2)
def ip2long_3(ip):
return long("".join(["{0:08b}".format(num) for num in map(int, ip.split('.'))]), 2)
Execution Times:
ip2long_1 => 0.0527065660363234 ( The Best )
ip2long_2 => 0.577211893924598
ip2long_3 => 0.5552745958088666

One line solution without any module import:
ip2int = lambda ip: reduce(lambda a, b: (a << 8) + b, map(int, ip.split('.')), 0)
int2ip = lambda n: '.'.join([str(n >> (i << 3) & 0xFF) for i in range(0, 4)[::-1]])
Example:
In [3]: ip2int('121.248.220.85')
Out[3]: 2046352469
In [4]: int2ip(2046352469)
Out[4]: '121.248.220.85'

Convert IP to integer :
python -c "print sum( [int(i)*2**(8*j) for i,j in zip( '10.20.30.40'.split('.'), [3,2,1,0]) ] )"
Convert Interger to IP :
python -c "print '.'.join( [ str((169090600 >> 8*i) % 256) for i in [3,2,1,0] ])"

def ip2Hex(ip = None):
'''Returns IP in Int format from Octet form'''
#verifyFormat(ip)
digits=ip.split('.')
numericIp=0
count=0
for num in reversed(digits):
print "%d " % int(num)
numericIp += int(num) * 256 **(count)
count +=1
print "Numeric IP:",numericIp
print "Numeric IP Hex:",hex(numericIp)
ip2Hex('192.168.192.14')
ip2Hex('1.1.1.1')
ip2Hex('1.0.0.0')

Here's one
def ipv4_to_int(ip):
octets = ip.split('.')
count = 0
for i, octet in enumerate(octets):
count += int(octet) << 8*(len(octets)-(i+1))
return count

You can use the function clean_ip from the library DataPrep if your IP addresses are in a DataFrame. Install DataPrep with pip install dataprep.
from dataprep.clean import clean_ip
df = pd.DataFrame({"ip": ["186.99.109.000", "127.0.0.1", "1.2.3.4"]})
To convert to a decimal format, set the parameter output_format to "integer":
df2 = clean_ip(df, "ip", output_format="integer")
# print(df2)
ip ip_clean
0 186.99.109.000 3127078144
1 127.0.0.1 2130706433
2 1.2.3.4 16909060
To convert to a binary format, set the parameter output_format to "binary":
df2 = clean_ip(df, "ip", output_format="binary")
# print(df2)
ip ip_clean
0 186.99.109.000 10111010011000110110110100000000
1 127.0.0.1 01111111000000000000000000000001
2 1.2.3.4 00000001000000100000001100000100
To convert back to IPv4, set the parameter output_format to "compressed":
df = pd.DataFrame({"ip": [3127078144, 2130706433, 16909060]})
df2 = clean_ip(df, "ip", output_format="compressed")
# print(df2)
ip ip_clean
0 3127078144 186.99.109.0
1 2130706433 127.0.0.1
2 16909060 1.2.3.4

You must first convert the string that contains the IP address into a byte or a string of bytes and then start communicating.
According to the code below, your error will be resolved.
Make sure your code is working correctly overall.
string = '192.168.1.102'
new_string = bytearray(string,"ascii")
ip_receiver = new_string
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto(text.encode(), (ip_receiver, 5252))

Related

convert cidr to subnet mask in python

I have a python dictionary that I've created, this dictionary contains a list of subnets in the following format:
x.x.x.x/24
y.y.y,y/25
z.z.z.z/26
a.a.a.a/27
etc...
I would like to take the items in this dictionary, parse it, then spit out the results in the following format:
x.x.x.x 255.255.255.0
y.y.y.y 255.255.255.128
x.x.x.x 255.255.255.192
a.a.a.a 255.255.255.224
I don't have much on this as of right now because I can't find a lot on this topic on the web, not anything that can be in a quick and concise way that is. Thoughts?
Code:
import socket
import struct
def cidr_to_netmask(cidr):
network, net_bits = cidr.split('/')
host_bits = 32 - int(net_bits)
netmask = socket.inet_ntoa(struct.pack('!I', (1 << 32) - (1 << host_bits)))
return network, netmask
Usage:
>>> cidr_to_netmask('10.10.1.32/27')
('10.10.1.32', '255.255.255.224')
>>> cidr_to_netmask('208.128.0.0/11')
('208.128.0.0', '255.224.0.0')
>>> cidr_to_netmask('208.130.28.0/22')
('208.130.28.0', '255.255.252.0')
I thought I'd throw in my own solution, since I was going for a little bit more readability in it than the other answers shown.
def cidr_to_netmask(cidr):
cidr = int(cidr)
mask = (0xffffffff >> (32 - cidr)) << (32 - cidr)
return (str( (0xff000000 & mask) >> 24) + '.' +
str( (0x00ff0000 & mask) >> 16) + '.' +
str( (0x0000ff00 & mask) >> 8) + '.' +
str( (0x000000ff & mask)))
It's now easier to see what's going on, and that is:
Get the numeric mask by padding the front with 1s and having the cidr make up the rest
For each bit, apply the mask
Concatenate all the bits together, separated by periods
This is very procedural and does not use any libraries.
Try this solution:
Python3
from ipaddress import IPv4Network
networks = {'n1':'10.1.0.0/21','n2':'10.2.0.0/22','n3':'10.3.0.0/23','n4':'10.4.0.0/24'}
for x,y in enumerate(networks):
print(IPv4Network(networks[y]).network_address, IPv4Network(networks[y]).netmask)
Result:
10.1.0.0 255.255.248.0
10.2.0.0 255.255.252.0
10.3.0.0 255.255.254.0
10.4.0.0 255.255.255.0
Python2
from netaddr import IPNetwork
networks = {'n1':'10.1.0.0/21','n2':'10.2.0.0/22','n3':'10.3.0.0/23','n4':'10.4.0.0/24'}
for x,y in enumerate(networks):
print(str(IPNetwork(networks[y]).network), str(IPNetwork(networks[y]).netmask))
Result:
('10.1.0.0', '255.255.248.0')
('10.2.0.0', '255.255.252.0')
('10.3.0.0', '255.255.254.0')
('10.4.0.0', '255.255.255.0')
Try this
lsIP = []
ans = 0
CIDR = 32
IP = [1] * CIDR
for i in range(len(IP)):
iIdx = i % 8
if iIdx == 0:
if i >= 8:
lsIP.append(ans)
ans = 0
ans += pow(2, 7 - iIdx)
lsIP.append(ans)
[lsIP.append(0) for i in range(4 - len(lsIP))]
print lsIP

why printf using ctypes from python does not print number as signed

I wrote the following code in C
short a = 0xFFFE;
printf("hex = 0x%X, signed short = %d\n", a & 0xFFFF, a);
Output ---> hex = 0xFFFE, signed short = -2
Now tying to do the same in Python using ctypes
from ctypes import *
mc = cdll.msvcrt
a = c_short(0xFFFE)
mc.printf("hex = 0x%X, signed short = %d\n", a, a)
Output ----> hex = 0xFFFE, signed short = 65534
I am not sure why the output is different? Any idea?
printf isn't being called correctly. Use %hX and %hd for passing shorts.
>>> from ctypes import *
>>> mc = cdll.msvcrt
>>> a=c_short(0xFFFE)
>>> mc.printf('hex=0x%hX, signed short=%hd\n',a,a)
hex=0xFFFE, signed short=-2
28

Does python Sha1 takes integer

How to take integer in hashlib.sha1(int).
Please see the code in which i am taking IP as string converting it as integer now at hash.sha1 doest take integer...
import hashlib
import socket
import struct
class blommy(object):
def __init__(self):
self.bitarray= [0]*2048
def hashes(self,ip):
#convert decimal dotted quad string to long integer"
intip= struct.unpack('>L',socket.inet_aton(ip))[0]
index = [0, 1]
hbyte = hashlib.sha1(intip) # how to take sha1 of integer??
index[0] = ord(hbyte[0])| ord(hbyte[1])<< 8
index[1] = ord(hbyte[2])| ord(hbyte[3])<< 8
Need to convert this C code to python. Please advice some part of code is written above. If i take ip as int I cannot compute sha1 + even if convert ip using socket than sha1 dont accept it suggestion? see comments below
//fixed parameters
k = 2
m = 256*8
//the filter
byte[m/8] bloom ##
function insertIP(byte[] ip) {
byte[20] hash = sha1(ip)
int index1 = hash[0] | hash[1] << 8 # how to in python?
int index2 = hash[2] | hash[3] << 8
// truncate index to m (11 bits required)
index1 %= m ## ?
index2 %= m ## ?
// set bits at index1 and index2
bloom[index1 / 8] |= 0x01 << index1 % 8 ## ??
bloom[index2 / 8] |= 0x01 << index2 % 8 ## ??
}
// insert IP 192.168.1.1 into the filter:
insertIP(byte[4] {192,168,1,1})
The answer to your question is no, you can calculate the hash of strings but not integers. Try something like:
hashlib.sha1(str(1234)).digest()
to get the hash of your integer as a string.

Conversion from IP string to integer, and backward in Python

i have a little problem with my script, where i need to convert ip in form 'xxx.xxx.xxx.xxx' to integer representation and go back from this form.
def iptoint(ip):
return int(socket.inet_aton(ip).encode('hex'),16)
def inttoip(ip):
return socket.inet_ntoa(hex(ip)[2:].decode('hex'))
In [65]: inttoip(iptoint('192.168.1.1'))
Out[65]: '192.168.1.1'
In [66]: inttoip(iptoint('4.1.75.131'))
---------------------------------------------------------------------------
error Traceback (most recent call last)
/home/thc/<ipython console> in <module>()
/home/thc/<ipython console> in inttoip(ip)
error: packed IP wrong length for inet_ntoa`
Anybody knows how to fix that?
#!/usr/bin/env python
import socket
import struct
def ip2int(addr):
return struct.unpack("!I", socket.inet_aton(addr))[0]
def int2ip(addr):
return socket.inet_ntoa(struct.pack("!I", addr))
print(int2ip(0xc0a80164)) # 192.168.1.100
print(ip2int('10.0.0.1')) # 167772161
Python 3 has ipaddress module which features very simple conversion:
int(ipaddress.IPv4Address("192.168.0.1"))
str(ipaddress.IPv4Address(3232235521))
In pure python without use additional module
def IP2Int(ip):
o = map(int, ip.split('.'))
res = (16777216 * o[0]) + (65536 * o[1]) + (256 * o[2]) + o[3]
return res
def Int2IP(ipnum):
o1 = int(ipnum / 16777216) % 256
o2 = int(ipnum / 65536) % 256
o3 = int(ipnum / 256) % 256
o4 = int(ipnum) % 256
return '%(o1)s.%(o2)s.%(o3)s.%(o4)s' % locals()
# Example
print('192.168.0.1 -> %s' % IP2Int('192.168.0.1'))
print('3232235521 -> %s' % Int2IP(3232235521))
Result:
192.168.0.1 -> 3232235521
3232235521 -> 192.168.0.1
You lose the left-zero-padding which breaks decoding of your string.
Here's a working function:
def inttoip(ip):
return socket.inet_ntoa(hex(ip)[2:].zfill(8).decode('hex'))
Below are the fastest and most straightforward (to the best of my knowledge)
convertors for IPv4 and IPv6:
try:
_str = socket.inet_pton(socket.AF_INET, val)
except socket.error:
raise ValueError
return struct.unpack('!I', _str)[0]
-------------------------------------------------
return socket.inet_ntop(socket.AF_INET, struct.pack('!I', n))
-------------------------------------------------
try:
_str = socket.inet_pton(socket.AF_INET6, val)
except socket.error:
raise ValueError
a, b = struct.unpack('!2Q', _str)
return (a << 64) | b
-------------------------------------------------
a = n >> 64
b = n & ((1 << 64) - 1)
return socket.inet_ntop(socket.AF_INET6, struct.pack('!2Q', a, b))
Python code not using inet_ntop() and struct module is like order of magnitude slower than this regardless of what it is doing.
One line
reduce(lambda out, x: (out << 8) + int(x), '127.0.0.1'.split('.'), 0)
Python3 oneliner (based on Thomas Webber's Python2 answer):
sum([int(x) << 8*i for i,x in enumerate(reversed(ip.split('.')))])
Left shifts are much faster than pow().
It can be done without using any library.
def iptoint(ip):
h=list(map(int,ip.split(".")))
return (h[0]<<24)+(h[1]<<16)+(h[2]<<8)+(h[3]<<0)
def inttoip(ip):
return ".".join(map(str,[((ip>>24)&0xff),((ip>>16)&0xff),((ip>>8)&0xff),((ip>>0)&0xff)]))
iptoint("8.8.8.8") # 134744072
inttoip(134744072) # 8.8.8.8
I used following:
ip2int = lambda ip: reduce(lambda a,b: long(a)*256 + long(b), ip.split('.'))
ip2int('192.168.1.1')
#output
3232235777L
# from int to ip
int2ip = lambda num: '.'.join( [ str((num >> 8*i) % 256) for i in [3,2,1,0] ])
int2ip(3232235777L)
#output
'192.168.1.1'
Let me give a more understandable way:
ip to int
def str_ip2_int(s_ip='192.168.1.100'):
lst = [int(item) for item in s_ip.split('.')]
print lst
# [192, 168, 1, 100]
int_ip = lst[3] | lst[2] << 8 | lst[1] << 16 | lst[0] << 24
return int_ip # 3232235876
The above:
lst = [int(item) for item in s_ip.split('.')]
equivalent to :
lst = map(int, s_ip.split('.'))
also:
int_ip = lst[3] | lst[2] << 8 | lst[1] << 16 | lst[0] << 24
equivalent to :
int_ip = lst[3] + (lst[2] << 8) + (lst[1] << 16) + (lst[0] << 24)
int_ip = lst[3] + lst[2] * pow(2, 8) + lst[1] * pow(2, 16) + lst[0] * pow(2, 24)
int to ip:
def int_ip2str(int_ip=3232235876):
a0 = str(int_ip & 0xff)
a1 = str((int_ip & 0xff00) >> 8)
a2 = str((int_ip & 0xff0000) >> 16)
a3 = str((int_ip & 0xff000000) >> 24)
return ".".join([a3, a2, a1, a0])
or:
def int_ip2str(int_ip=3232235876):
lst = []
for i in xrange(4):
shift_n = 8 * i
lst.insert(0, str((int_ip >> shift_n) & 0xff))
return ".".join(lst)
My approach is to straightforwardly look at the the number the way it is stored, rather than displayed, and to manipulate it from the display format to the stored format and vice versa.
So, from an IP address to an int:
def convertIpToInt(ip):
return sum([int(ipField) << 8*index for index, ipField in enumerate(reversed(ip.split('.')))])
This evaluates each field, and shifts it to its correct offset, and then sums them all up, neatly converting the IP address' display into its numerical value.
In the opposite direction, from an int to an IP address:
def convertIntToIp(ipInt):
return '.'.join([str(int(ipHexField, 16)) for ipHexField in (map(''.join, zip(*[iter(str(hex(ipInt))[2:].zfill(8))]*2)))])
The numerical representation is first converted into its hexadecimal string representation, which can be manipulated as a sequence, making it easier to break up. Then, pairs are extracted by mapping ''.join onto tuples of pairs provided by zipping a list of two references to an iterator of the IP string (see How does zip(*[iter(s)]*n) work?), and those pairs are in turn converted from hex string representations to int string representations, and joined by '.'.
def ip2int(ip):
"""
Convert IP string to integer
:param ip: IP string
:return: IP integer
"""
return reduce(lambda x, y: x * 256 + y, map(int, ip.split('.')))
def int2ip(num):
"""
Convert IP integer to string
:param num: IP integer
:return: IP string
"""
return '.'.join(map(lambda x: str(num // 256 ** x % 256), range(3, -1, -1)))

Python Network/cidr Calculations

I am working on building an embedded network appliance (linux based) and have come across the need to dynamically build daemon conf files. As such, I need to be able to do some network address calculations in the python code that will be building the conf files. I am not a programmer so I'm fearful I wrote a module that will fail to function as I'd hoped once the appliance starts shipping.
Below is what I have so far, its really pieced together with what I could find on this site and Google.
Is there a better method to find the network address and cidr for a network interface? Converting the netmask to a bin str and counting the 1's seems pretty inelegant.
import socket
import fcntl
import struct
SIOCGIFNETMASK = 0x891b
SIOCGIFADDR = 0x8915
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def _GetIfaceMask(iface):
return struct.unpack('L', fcntl.ioctl(s, SIOCGIFNETMASK, struct.pack('256s', iface))[20:24])[0]
def _GetIfaceAddr(iface):
return struct.unpack('L', fcntl.ioctl(s, SIOCGIFADDR, struct.pack('256s', iface[:15]))[20:24])[0]
def GetIfaceNet(iface):
net_addr = _GetIfaceAddr(iface) & _GetIfaceMask(iface)
return socket.inet_ntoa(struct.pack('L', net_addr))
def GetIfaceCidr(iface):
bin_str = bin(_GetIfaceMask(iface))[2:]
cidr = 0
for c in bin_str:
if c == '1': cidr += 1
return cidr
Thanks for any input, I really am somewhat lost on this. If this isn't the place for this type of feedback, please let me know.
This can be solved using a Hamming weight algorithm. Stolen from How to count the number of set bits in a 32-bit integer? and translated into Python:
def number_of_set_bits(x):
x -= (x >> 1) & 0x55555555
x = ((x >> 2) & 0x33333333) + (x & 0x33333333)
x = ((x >> 4) + x) & 0x0f0f0f0f
x += x >> 8
x += x >> 16
return x & 0x0000003f
Another, more readable solution (but running in O(log x)):
def number_of_set_bits(x):
n = 0
while x:
n += x & 1
x = x >> 1
return n
You may check iptools python module http://code.google.com/p/python-iptools/ it can convert from long to dotted ip format and vise versa.

Categories