Discussion:
Packing and unpacking IP addresses into 32-bit integers
Mike Fletcher
1999-08-09 22:13:15 UTC
Permalink
Wouldn't it be something like:
'>bbbb' or '!bbbb'

instead (for portability to non-big-endian machines (I'm assuming the packed
representation is supposed to have network byte order))?

Just a thought,
Mike

-----Original Message-----
From: python-list-request at cwi.nl [mailto:python-list-request at cwi.nl]On
Behalf Of Steven D. Majewski
Sent: August 9, 1999 4:50 PM
To: python-list at cwi.nl
Subject: Re: Packing and unpacking IP addresses into 32-bit integers

...
and use either struct.pack or array to coerce it into a binary string:

a = apply( struct.pack, [ 'bbbb' ] + adr )
Fred L. Drake, Jr.
1999-08-10 16:36:30 UTC
Permalink
Post by Mike Fletcher
'>bbbb' or '!bbbb'
instead (for portability to non-big-endian machines (I'm assuming the packed
representation is supposed to have network byte order))?
Mike,
There are no byte-ordering issues with byte-sized values. Since the
x.x.x.x is already in a specific order, the issue doesn't come up at
all here if you're only interested in coverting the dot-notation to &
from the network-byte-order binary structure.


-Fred

--
Fred L. Drake, Jr. <fdrake at acm.org>
Corporation for National Research Initiatives
Ben Gertzfield
1999-08-09 21:42:44 UTC
Permalink
Thanks. Here's what I came up with finally. I decided to avoid use
of apply() for clarity, as these are dense enough as it is. :)

import string, struct

def inet_aton(packme):
"""Given a IP address as a string of the form 123.45.67.89, pack
it into the 32-bit binary representation (struct in_addr) used
in C and other languages."""

a, b, c, d = map(string.atoi, string.split(packme, '.'))
return struct.pack('BBBB', a, b, c, d)

def inet_ntoa(packed):
"""Unpacks a 32-bit binary representation of an IP address into a
string and return it in dotted-quad (123.45.67.89) format."""

quads = map(str, struct.unpack('BBBB', packed))
return string.join(quads, '.')

I'm not sure if it's overly-compact, or if I ought to do things with
binary arithmetic for clarity. Anyway, it seems to work. Thanks for
the tip!

Ben
--
Brought to you by the letters O and Q and the number 5.
"I choose YOU! Pikachu!"
Debian GNU/Linux maintainer of Gimp and GTK+ -- http://www.debian.org/
Ben Gertzfield
1999-08-09 20:00:39 UTC
Permalink
I noticed that the 'socket' module in Python has slightly different
behavior for gethostbyname() than I'm used to.

In Python, gethostbyname() returns a string, not a packed IP address
(a 32-bit integer) of the IP address, as C and Perl do. However, I
need to talk with C over the network, and the 'struct' module doesn't
deal with packing or unpacking IP addresses.

Do I have to use a regular expression to split up the dotted quads
that gethostbyname() returns into the component bytes and then use
binary shifts and or'ing to get them into a standard 32-bit integer
format? Or is there a better way that I'm totally missing?

Ben
--
Brought to you by the letters C and X and the number 3.
"A beldam is an old lady."
Debian GNU/Linux maintainer of Gimp and GTK+ -- http://www.debian.org/
Steven D. Majewski
1999-08-09 20:50:29 UTC
Permalink
Post by Ben Gertzfield
I noticed that the 'socket' module in Python has slightly different
behavior for gethostbyname() than I'm used to.
In Python, gethostbyname() returns a string, not a packed IP address
(a 32-bit integer) of the IP address, as C and Perl do. However, I
need to talk with C over the network, and the 'struct' module doesn't
deal with packing or unpacking IP addresses.
Do I have to use a regular expression to split up the dotted quads
that gethostbyname() returns into the component bytes and then use
binary shifts and or'ing to get them into a standard 32-bit integer
format? Or is there a better way that I'm totally missing?
No you don't have to use regular expressions and binary shifts and or's:

First, map int or string.atoi onto the result of applying string.split
to the return string of gethostbyname -- that will give you a list of ints.

adr = map( string.atoi, string.split( gethostbyname( name ), '.' ))

and use either struct.pack or array to coerce it into a binary string:

a = apply( struct.pack, [ 'bbbb' ] + adr )

(or longer, but less cryptically)

a = array( 'b')
a.fromlist( adr )
a.tostring()
a



---| Steven D. Majewski (804-982-0831) <sdm7g at Virginia.EDU> |---
---| Department of Molecular Physiology and Biological Physics |---
---| University of Virginia Health Sciences Center |---
---| P.O. Box 10011 Charlottesville, VA 22906-0011 |---
Ben Gertzfield
1999-08-10 01:52:32 UTC
Permalink
Mike> Wouldn't it be something like: '>bbbb' or '!bbbb'

Mike> instead (for portability to non-big-endian machines (I'm
Mike> assuming the packed representation is supposed to have
Mike> network byte order))?

Unfortunately Python isn't smart enough to assume that:

struct.pack('!bbbb', a, b, c, d)

means

struct.pack('!bbbb', d, c, b, a)

but it's easy enough to just change the order of the arguments, which
is what I did, since it's well-defined which order the arguments
will come in (they'll always come in a b c d and go out d c b a).
--
Brought to you by the letters N and G and the number 7.
"You have my pills!"
Debian GNU/Linux maintainer of Gimp and GTK+ -- http://www.debian.org/
Loading...