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))
I need to bruteforce some of the address space using python. At the moment this is my code:
offsets = [
"\x00","\x01","\x02","\x03","\x04","\x05","\x06","\x07","\x08","\x09","\x0a","\x0b","\x0c","\x0d","\x0e","\x0f"
,"\x10","\x11","\x12","\x13","\x14","\x15","\x16","\x17","\x18","\x19","\x1a","\x1b","\x1c","\x1d","\x1e","\x1f"
,"\x20","\x21","\x22","\x23","\x24","\x25","\x26","\x27","\x28","\x29","\x2a","\x2b","\x2c","\x2d","\x2e","\x2f"
,"\x30","\x31","\x32","\x33","\x34","\x35","\x36","\x37","\x38","\x39","\x3a","\x3b","\x3c","\x3d","\x3e","\x3f"
,"\x40","\x41","\x42","\x43","\x44","\x45","\x46","\x47","\x48","\x49","\x4a","\x4b","\x4c","\x4d","\x4e","\x4f"
,"\x50","\x51","\x52","\x53","\x54","\x55","\x56","\x57","\x58","\x59","\x5a","\x5b","\x5c","\x5d","\x5e","\x5f"
,"\x60","\x61","\x62","\x63","\x64","\x65","\x66","\x67","\x68","\x69","\x6a","\x6b","\x6c","\x6d","\x6e","\x6f"
,"\x70","\x71","\x72","\x73","\x74","\x75","\x76","\x77","\x78","\x79","\x7a","\x7b","\x7c","\x7d","\x7e","\x7f"
,"\x80","\x81","\x82","\x83","\x84","\x85","\x86","\x87","\x88","\x89","\x8a","\x8b","\x8c","\x8d","\x8e","\x8f"
,"\x90","\x91","\x92","\x93","\x94","\x95","\x96","\x97","\x98","\x99","\x9a","\x9b","\x9c","\x9d","\x9e","\x9f"
,"\xa0","\xa1","\xa2","\xa3","\xa4","\xa5","\xa6","\xa7","\xa8","\xa9","\xaa","\xab","\xac","\xad","\xae","\xaf"
,"\xb0","\xb1","\xb2","\xb3","\xb4","\xb5","\xb6","\xb7","\xb8","\xb9","\xba","\xbb","\xbc","\xbd","\xbe","\xbf"
,"\xc0","\xc1","\xc2","\xc3","\xc4","\xc5","\xc6","\xc7","\xc8","\xc9","\xca","\xcb","\xcc","\xcd","\xce","\xcf"
,"\xd0","\xd1","\xd2","\xd3","\xd4","\xd5","\xd6","\xd7","\xd8","\xd9","\xda","\xdb","\xdc","\xdd","\xde","\xdf"
,"\xe0","\xe1","\xe2","\xe3","\xe4","\xe5","\xe6","\xe7","\xe8","\xe9","\xea","\xeb","\xec","\xed","\xee","\xef"
,"\xf0","\xf1","\xf2","\xf3","\xf4","\xf5","\xf6","\xf7","\xf8","\xf9","\xfa","\xfb","\xfc","\xfd","\xfe","\xff"]
for i in xrange(110, 256):
num = offsets[i]
address = "\xee" + num + "\xff\xbf"
print `address`
And the output last part of the output:
'\xee\xfa\xff\xbf'
'\xee\xfb\xff\xbf'
'\xee\xfc\xff\xbf'
'\xee\xfd\xff\xbf'
'\xee\xfe\xff\xbf'
'\xee\xff\xff\xbf'
My question is if it is possible to get rid of the "offsets" array, and do it in a much cleaner way?
Sure is, just iterate over the xrange and call chr() on the current item:
>>> for i in xrange(110, 256):
... print "\xee" + chr(i) + "\xff\xbf"
Notice that it'll print the actual characters. If you just want to print the values, you can use the backticks, however a more pythonic approach is to use repr():
>>> for i in xrange(110, 256):
... print(repr("\xee" + chr(i) + "\xff\xbf"))
...
-- SNIP --
'\xee\xfa\xff\xbf'
'\xee\xfb\xff\xbf'
'\xee\xfc\xff\xbf'
'\xee\xfd\xff\xbf'
'\xee\xfe\xff\xbf'
'\xee\xff\xff\xbf'
for i in xrange(110, 256):
address = "\xee" + "\\" + hex(i)[1:] + "\xff\xbf"
print `address`
You can generate the offsets array in a one-liner:
offsets = ["0x{:02x}".format(_) for _ in range(0x100)]
You could just do the math, and let struct construct the 4-byte sequence.
base = b'\xee\x00\xff\xbf' #assuming little-endian for the math coming up
struct.unpack('I',base)
Out[89]: (3221160174,)
#showing they're the same, no magic involved
int('ee',16) + int('ff',16)*(16**4) + int('bf',16)*(16**6)
Out[90]: 3221160174
#equivalent to bitshifting, if you prefer
int('ee',16) + (int('ff',16) << 16) + (int('bf',16) << 24)
Out[91]: 3221160174
So that gives
start = 3221160174
[struct.pack('I', start + (x<<8)) for x in range(256)]
Out[93]:
[b'\xee\x00\xff\xbf',
b'\xee\x01\xff\xbf',
b'\xee\x02\xff\xbf',
b'\xee\x03\xff\xbf',
b'\xee\x04\xff\xbf',
b'\xee\x05\xff\xbf',
b'\xee\x06\xff\xbf',
#snip...
b'\xee\xff\xff\xbf']
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)))