source: trunk/server/lib/dnspython/dns/ipv6.py

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 5.0 KB
Line 
1# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc.
2#
3# Permission to use, copy, modify, and distribute this software and its
4# documentation for any purpose with or without fee is hereby granted,
5# provided that the above copyright notice and this permission notice
6# appear in all copies.
7#
8# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
9# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
11# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
14# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
16"""IPv6 helper functions."""
17
18import re
19
20import dns.exception
21import dns.ipv4
22
23_leading_zero = re.compile(r'0+([0-9a-f]+)')
24
25def inet_ntoa(address):
26 """Convert a network format IPv6 address into text.
27
28 @param address: the binary address
29 @type address: string
30 @rtype: string
31 @raises ValueError: the address isn't 16 bytes long
32 """
33
34 if len(address) != 16:
35 raise ValueError("IPv6 addresses are 16 bytes long")
36 hex = address.encode('hex_codec')
37 chunks = []
38 i = 0
39 l = len(hex)
40 while i < l:
41 chunk = hex[i : i + 4]
42 # strip leading zeros. we do this with an re instead of
43 # with lstrip() because lstrip() didn't support chars until
44 # python 2.2.2
45 m = _leading_zero.match(chunk)
46 if not m is None:
47 chunk = m.group(1)
48 chunks.append(chunk)
49 i += 4
50 #
51 # Compress the longest subsequence of 0-value chunks to ::
52 #
53 best_start = 0
54 best_len = 0
55 start = -1
56 last_was_zero = False
57 for i in xrange(8):
58 if chunks[i] != '0':
59 if last_was_zero:
60 end = i
61 current_len = end - start
62 if current_len > best_len:
63 best_start = start
64 best_len = current_len
65 last_was_zero = False
66 elif not last_was_zero:
67 start = i
68 last_was_zero = True
69 if last_was_zero:
70 end = 8
71 current_len = end - start
72 if current_len > best_len:
73 best_start = start
74 best_len = current_len
75 if best_len > 0:
76 if best_start == 0 and \
77 (best_len == 6 or
78 best_len == 5 and chunks[5] == 'ffff'):
79 # We have an embedded IPv4 address
80 if best_len == 6:
81 prefix = '::'
82 else:
83 prefix = '::ffff:'
84 hex = prefix + dns.ipv4.inet_ntoa(address[12:])
85 else:
86 hex = ':'.join(chunks[:best_start]) + '::' + \
87 ':'.join(chunks[best_start + best_len:])
88 else:
89 hex = ':'.join(chunks)
90 return hex
91
92_v4_ending = re.compile(r'(.*):(\d+)\.(\d+)\.(\d+)\.(\d+)$')
93_colon_colon_start = re.compile(r'::.*')
94_colon_colon_end = re.compile(r'.*::$')
95
96def inet_aton(text):
97 """Convert a text format IPv6 address into network format.
98
99 @param text: the textual address
100 @type text: string
101 @rtype: string
102 @raises dns.exception.SyntaxError: the text was not properly formatted
103 """
104
105 #
106 # Our aim here is not something fast; we just want something that works.
107 #
108
109 if text == '::':
110 text = '0::'
111 #
112 # Get rid of the icky dot-quad syntax if we have it.
113 #
114 m = _v4_ending.match(text)
115 if not m is None:
116 text = "%s:%04x:%04x" % (m.group(1),
117 int(m.group(2)) * 256 + int(m.group(3)),
118 int(m.group(4)) * 256 + int(m.group(5)))
119 #
120 # Try to turn '::<whatever>' into ':<whatever>'; if no match try to
121 # turn '<whatever>::' into '<whatever>:'
122 #
123 m = _colon_colon_start.match(text)
124 if not m is None:
125 text = text[1:]
126 else:
127 m = _colon_colon_end.match(text)
128 if not m is None:
129 text = text[:-1]
130 #
131 # Now canonicalize into 8 chunks of 4 hex digits each
132 #
133 chunks = text.split(':')
134 l = len(chunks)
135 if l > 8:
136 raise dns.exception.SyntaxError
137 seen_empty = False
138 canonical = []
139 for c in chunks:
140 if c == '':
141 if seen_empty:
142 raise dns.exception.SyntaxError
143 seen_empty = True
144 for i in xrange(0, 8 - l + 1):
145 canonical.append('0000')
146 else:
147 lc = len(c)
148 if lc > 4:
149 raise dns.exception.SyntaxError
150 if lc != 4:
151 c = ('0' * (4 - lc)) + c
152 canonical.append(c)
153 if l < 8 and not seen_empty:
154 raise dns.exception.SyntaxError
155 text = ''.join(canonical)
156
157 #
158 # Finally we can go to binary.
159 #
160 try:
161 return text.decode('hex_codec')
162 except TypeError:
163 raise dns.exception.SyntaxError
Note: See TracBrowser for help on using the repository browser.