Reputation: 31
I'm trying to read IPv6 addresses from /proc/net/tcp6
in Python 2.7. Here's a sample of the IPv6 representation that is used in /proc/net/tcp6
:
00000000000000000000000000000000
00000000000000000000000001000000
0000000000000000FFFF00001F00C80A
What I'm having trouble with is converting these to a "proper" IPv6 representation, as described on Wikipedia:
An IPv6 address is represented as eight groups of four hexadecimal digits, each group representing 16 bits (two octets). The groups are separated by colons (:). An example of an IPv6 address is:
2001:0db8:85a3:0000:0000:8a2e:0370:7334
[...] the example address can be further simplified:
2001:db8:85a3::8a2e:370:7334
It seems this can be done most easily with the help of socket.inet_ntop
and struct.pack
.
However I don't know which steps exactly to take to produce the specific format that these two functions require.
Any other methods using something else from Python 2.7 stdlib are just as welcome of course.
Just for comparison, here's how I'm doing it right now for IPv4 addresses that are read from /proc/net/tcp
:
>>> addr = '0101007F'
>>> addr = int(addr, 16)
>>> addr = struct.pack('<I', addr)
>>> addr = socket.inet_ntoa(addr)
>>> print addr
127.0.1.1
Unfortunately inet_ntoa
doesn't support IPv6 addresses and you have to use inet_ntop(AF_INET6, packed_ipv6)
instead.
However I don't know how to convert those strings above to a in6_addr
struct using the struct.pack
function.
Upvotes: 2
Views: 2995
Reputation: 31
Here's one way that works, and handles native endianness automatically:
def ipv6(addr):
addr = addr.decode('hex')
addr = struct.unpack('>IIII', addr)
addr = struct.pack('@IIII', *addr)
addr = socket.inet_ntop(socket.AF_INET6, addr)
return addr
Sample:
>>> ipv6('00000000000000000000000001000000')
'::1'
>>> ipv6('B80D01200000000067452301EFCDAB89')
'2001:db8::123:4567:89ab:cdef'
Steps:
decode('hex')
),>IIII
),@IIII
),socket.inet_ntop
, which finally produces the proper IPv6 representationOn systems that use little endian, the byte string will be converted from DCBA-HGFE-LKJI-PONM
to ABCD-EFGH-IJKL-MNOP
. See struct
module's byte order notation.
An alternative to the unpack
& pack
part, but twice as slow on my system, and it doesn't automatically handle native endianness (here little endian is assumed):
addr = ''.join(addr[i:i+4][::-1] for i in range(0, 16, 4))
Upvotes: 1
Reputation: 12409
Something like this?
from ipaddress import ip_address
components = [line[i:i+4] for i in range(0, len(line), 4)]
ipv6_string = ":".join(components)
print(ip_address(ipv6_string))
Upvotes: 0