59

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.

Hannele
  • 9,301
  • 6
  • 48
  • 68
user987055
  • 1,039
  • 4
  • 14
  • 25

11 Answers11

105

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'
Not_a_Golfer
  • 47,012
  • 14
  • 126
  • 92
  • 36
    love this line from the python documentation `The form '!' is available for those poor souls who claim they can’t remember whether network byte order is big-endian or little-endian.` – Not_a_Golfer Mar 06 '12 at 20:16
58

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'
ndemou
  • 4,691
  • 2
  • 30
  • 33
  • 1
    No need to use stuff like `2**16`, just use `<< 16` instead. – interestinglythere Nov 11 '14 at 06:32
  • 1
    Thanks for the tip interestinglythere. I do like this notation (it reminds me of my first 6502 assembler programs). – ndemou Nov 14 '14 at 15:35
  • User [brisebom](https://stackoverflow.com/users/1697876) tried to post this comment as an answer: *"Here is a simple benchmark test for most of the examples in @ndemou's answer. If you are already using the `ipaddress` module for your addresses, the IP int is precalculated so it is the fastest method. Otherwise, socket/struct is the fastest method by a quite a lot. https://ideone.com/cZU9Ar"* – Artjom B. May 05 '18 at 08:48
  • A kind soul did some benchmarks here https://ideone.com/cZU9Ar -- thanks to @brisebom and artjom-b for letting us know (I only repeat it here because the link in Artjom's comment got corrupted) – ndemou May 05 '18 at 15:16
  • 1
    `str(ipaddress.ip_address(16909060))` is a simpler way to convert integer to string. – Bob Stein Nov 04 '21 at 11:49
30

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
fred.yu
  • 865
  • 7
  • 10
7

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'))
manphiz
  • 191
  • 3
  • 8
  • 2
    For the hex(ipaddress.ip_address('192.168.1.1')), got error. 'IPv4Address' object cannot be interpreted as an integer. Seems to use hex(int(...)). It is good to know the new ipaddress module. – Peng Zhang Mar 15 '16 at 06:34
  • Last line should be `ipaddress.ip_address(3232235777).__str__()`. This really returns `'192.168.1.1'` which is what the question asks for – ndemou Aug 17 '16 at 15:54
6

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

Community
  • 1
  • 1
Tomer Zait
  • 1,756
  • 2
  • 14
  • 12
5

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

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] ])" 
rafaelc
  • 57,686
  • 15
  • 58
  • 82
Indu Sharma
  • 71
  • 1
  • 4
1
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')
The.Anti.9
  • 43,474
  • 48
  • 123
  • 161
Mohammad Shahid Siddiqui
  • 3,730
  • 2
  • 27
  • 12
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
Said Ali Samed
  • 110
  • 1
  • 2
0

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
victoria55
  • 225
  • 2
  • 6
0

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))
amir avira
  • 31
  • 4