Conversion from IP string to integer, and backward in Python
Asked Answered
S

13

62

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?

Seagirt answered 11/4, 2011 at 10:2 Comment(2)
Doesn't work at all in my Python 2.6.6: inttoip raises a TypeError: Odd-length string.Saavedra
@Saavedra use socket.inet_ntoa(hex(ip)[2:].decode('hex')) for inttoipConfirmation
S
115
#!/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
Shugart answered 8/11, 2012 at 17:28 Comment(2)
This requires import struct.Sisyphus
3 times faster comparing to ipaddress.Anastassia
T
100

Python 3 has ipaddress module which features very simple conversion:

int(ipaddress.IPv4Address("192.168.0.1"))
str(ipaddress.IPv4Address(3232235521))
Terbium answered 7/4, 2016 at 11:38 Comment(3)
This should be the top answer. Python 2 has this module too, but not built in.Ruler
This module is so slowWrong
I've just ran this over 50 ip addresses with no noticable difference to my original script when I wasn't running the additional conversion and back back again.. seems quick enough to meCheroot
W
28

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
Widescreen answered 8/5, 2013 at 16:52 Comment(3)
i realise that this post is fairly old, but you can also use pow:: res = (o[0] * pow(256, 3)) + (o[1] * pow(256, 2)) + (o[2] * 256) + o[3]Longsighted
Dude, '%(o1)s.%(o2)s.%(o3)s.%(o4)s' % locals() is a veeeery bad style.Ruler
@SmitJohnth Thank you for giving the alternative solution ..., here, the new style can be f'{o1}.{o2}.{o3}.{o4}'Certitude
T
12

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'))
Timbuktu answered 11/4, 2011 at 10:17 Comment(2)
Yeah, you also fixed the [2:-1] slice to [2:], that was causing the error I commented about above.Saavedra
If ip is a LONG there will be a 'L' turd at the end of the string. Either replace hex(ip) with hex(int(ip)) or add .rstrip('L') after [2:].Red
X
8

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.

Xylol answered 11/4, 2011 at 11:10 Comment(1)
socket.inet_pton and inet_ntop are only available on UnixRed
C
6

One line

reduce(lambda out, x: (out << 8) + int(x), '127.0.0.1'.split('.'), 0)
Ceiba answered 17/6, 2017 at 13:30 Comment(1)
and by far more efficient/faster to left-shift than multiplyFilly
F
6

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().

Filly answered 6/3, 2020 at 10:13 Comment(0)
C
5

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
Canebrake answered 24/11, 2020 at 7:30 Comment(1)
correction: def iptoint(ip): h=list(map(int,ip.split("."))) return (h[0]<<24)+(h[1]<<16)+(h[2]<<8)+(h[3]<<0) Oddment
H
3

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'
Handal answered 31/1, 2019 at 13:46 Comment(0)
L
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)
Leyes answered 13/11, 2018 at 4:19 Comment(0)
C
0

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

Cephalothorax answered 25/12, 2018 at 13:0 Comment(0)
I
0
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)))
Indecision answered 23/5, 2022 at 9:49 Comment(0)
A
0

Also modern Python (>= 3.11) has a wonderful int.from_bytes and int.to_bytes methods:

>>> import socket
>>> socket.inet_aton('4.1.75.131')
b'\x04\x01K\x83'
>>> int.from_bytes(socket.inet_aton('4.1.75.131'))
67193731
>>> int.from_bytes(socket.inet_aton('10.0.0.1'))
167772161
>>>

# int2ip
>>> socket.inet_ntoa(167772161 .to_bytes(4))
'10.0.0.1'
Abessive answered 22/3 at 1:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.