1 # This file is part of python-rwhoisd
3 # Copyright (C) 2008 David E. Blacka
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 import socket, re, struct
22 # a simplified regex that just makes sure that the IPv6 address string
23 # isn't obviously invalid.
24 v6char_re = re.compile(r'^[0-9a-f:]+(:(\d{1,3}\.){3}\d{1,3})?$', re.I)
26 def v6str_to_addr(addrstr):
27 """Convert IPv6 addresses into its packed numerical value."""
29 # first make sure the address is made of valid IPv6 address
31 if not v6char_re.match(addrstr):
32 raise socket.error("Invalid IPv6 address: '%s'" % (addrstr))
34 toks = addrstr.split(":")
35 blanks = toks.count('')
37 # convert our IPv4 section.
39 packed_v4 = socket.inet_aton(toks[-1])
40 unpacked_v4 = [ "%x" % (x) for x in struct.unpack("!HH", packed_v4) ]
41 toks[-1:] = unpacked_v4
43 if len(toks) > 8 or blanks > 3:
44 raise socket.error("Invalid IPv6 address: '%s'" % (addrstr))
46 # three blanks must be ::
49 raise socket.error("Invalid IPv6 address: '%s'" % (addrstr))
52 # convert the tokens into a regular array of 8 things by inserting
53 # zero strings for the elided section.
55 # two blanks must be ::blah or blah::
57 z = ['0'] * (8 - len(toks) + 2)
58 if addrstr.startswith("::"):
60 elif addrstr.endswith("::"):
63 raise socket.error("Invalid IPv6 address: '%s'" % (addrstr))
64 # one blank is the blah::blah
66 z = ['0'] * (8 - len(toks) + 1)
71 raise socket.error("Invalid IPv6 address: '%s'" % (addrstr))
73 toks = [ int(t, 16) for t in toks ]
76 raise socket.error("Invalid IPv6 address: '%s'" % (addrstr))
77 return struct.pack("!8H", *toks)
79 def v6addr_to_str(addr):
80 """Convert a packed numerical IPv6 address into a string. This
81 routine doesn't (yet) create an elided section."""
84 raise socket.error("incorrect address length: %s (should be 16)" %
86 nums = [ x for x in struct.unpack("!8H", addr)]
88 # elding support mostly cobbled from the glibc version of
91 # look for the longest string of zeros.
92 cur_base = best_base = cur_len = best_len = -1
97 cur_base, cur_len = i, 1
102 if best_base == -1 or cur_len > best_len:
103 best_base, best_len = cur_base, cur_len
107 if best_base == -1 or cur_len > best_len:
108 best_base, best_len = cur_base, cur_len
110 # if we have a valid string of zeros, replace them with the token.
111 if best_base != -1 and best_len > 1:
112 nums[best_base:best_base + best_len] = [':']
123 strs = [ n_to_str(x) for x in nums ]
124 return ":".join(strs)
127 def inet_pton(af, ip):
128 if af == socket.AF_INET:
129 return socket.inet_aton(ip)
130 if af == socket.AF_INET6:
131 return v6str_to_addr(ip)
132 raise socket.error("Address family not supported by protocol")
134 def inet_ntop(af, packed_ip):
135 if af == socket.AF_INET:
136 return socket.inet_ntoa(packed_ip)
137 if af == socket.AF_INET6:
138 return v6addr_to_str(packed_ip)
139 raise socket.error("Address family not supported by protocol")
143 socket.inet_pton(socket.AF_INET6, "::1")
144 except (AttributeError, NameError, socket.error):
145 socket.inet_pton = inet_pton
146 socket.inet_ntop = inet_ntop
147 socket.AF_INET6 = 'AF_INET6'