Welcome, guest | Sign In | My Account | Store | Cart

Convert dotted-quad IP addresses to long integer and back, get network and host portions from an IP address, all nice and fast thanks to the builtin socket module (with a little help from the builtin struct module, too).

Python, 27 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# IP address manipulation functions, dressed up a bit

import socket, struct

def dottedQuadToNum(ip):
    "convert decimal dotted quad string to long integer"
    return struct.unpack('L',socket.inet_aton(ip))[0]

def numToDottedQuad(n):
    "convert long int to dotted quad string"
    return socket.inet_ntoa(struct.pack('L',n))
      
def makeMask(n):
    "return a mask of n bits as a long integer"
    return (2L<<n-1)-1

def ipToNetAndHost(ip, maskbits):
    "returns tuple (network, host) dotted-quad addresses given IP and mask size"
    # (by Greg Jorgensen)

    n = dottedQuadToNum(ip)
    m = makeMask(maskbits)

    host = n & m
    net = n - host

    return numToDottedQuad(net), numToDottedQuad(host)

As per http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65219, but Python "comes with batteries included", and thus offers excellent, fast and simple ways to perform many such tasks -- socket.inet_aton and .inet_ntoa to convert between dotted quads and packed strings, struct.pack and .unpack to convert between packed strings and other forms of data (here, longs).

It's generally better to use Python-supplied functionality -- it's most likely going to be faster than what one can recode oneself, and most likely also faster to code and requiring less maintenance.

3 comments

Tino Lange 19 years, 5 months ago  # | flag

Careful: byte-order -> example is not correct on usual (PC) platforms. Hi!

The interpretation via the struct-module is not correct on most platforms. You have to force interpretation in network (= big-endian) byte order, i.e. "!L" as format string, not just "L".

Tino

John Hazen 18 years, 1 month ago  # | flag

makeMask fails with argument of 0. Yes, obviously there's not much point to calling with 0, as it's a no-op, but "it's easier to ask forgiveness than permission."

Here's a version that works with the (valid) input of 0:

def makeMask(n):
    "return a mask of n bits as a long integer"
    return (1L&lt;&lt;n)-1
Socrates Varakliotis 17 years, 2 months ago  # | flag

IPv6? Is there a similar lib for IPv6 addresses?