1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """IPv6 helper functions."""
17
18 import base64
19 import re
20
21 import dns.exception
22 import dns.ipv4
23
25 """Convert a network format IPv6 address into text.
26
27 @param address: the binary address
28 @type address: bytes
29 @rtype: string
30 @raises ValueError: the address isn't 16 bytes long
31 """
32
33 if len(address) != 16:
34 raise ValueError("IPv6 addresses are 16 bytes long")
35 hex = str(base64.b16encode(address), encoding='utf_8').lower()
36 chunks = []
37 i = 0
38 l = len(hex)
39 while i < l:
40 chunk = hex[i : i + 4].lstrip('0')
41 if chunk == '':
42 chunk = '0'
43 chunks.append(chunk)
44 i += 4
45
46
47
48 best_start = 0
49 best_len = 0
50 start = -1
51 last_was_zero = False
52 for i in range(8):
53 if chunks[i] != '0':
54 if last_was_zero:
55 end = i
56 current_len = end - start
57 if current_len > best_len:
58 best_start = start
59 best_len = current_len
60 last_was_zero = False
61 elif not last_was_zero:
62 start = i
63 last_was_zero = True
64 if last_was_zero:
65 end = 8
66 current_len = end - start
67 if current_len > best_len:
68 best_start = start
69 best_len = current_len
70 if best_len > 0:
71 if best_start == 0 and \
72 (best_len == 6 or
73 best_len == 5 and chunks[5] == 'ffff'):
74
75 if best_len == 6:
76 prefix = '::'
77 else:
78 prefix = '::ffff:'
79 hex = prefix + dns.ipv4.inet_ntoa(address[12:])
80 else:
81 hex = ':'.join(chunks[:best_start]) + '::' + \
82 ':'.join(chunks[best_start + best_len:])
83 else:
84 hex = ':'.join(chunks)
85 return hex
86
87 _v4_ending = re.compile(r'(.*):(\d+\.\d+\.\d+\.\d+)$')
88 _colon_colon_start = re.compile(r'::.*')
89 _colon_colon_end = re.compile(r'.*::$')
90
92 """Convert a text format IPv6 address into network format.
93
94 @param text: the textual address
95 @type text: string
96 @rtype: bytes
97 @raises dns.exception.SyntaxError: the text was not properly formatted
98 """
99
100
101
102
103
104 if text == '::':
105 text = '0::'
106
107
108
109 m = _v4_ending.match(text)
110 if not m is None:
111 b = dns.ipv4.inet_aton(m.group(2))
112 text = "%s:%02x%02x:%02x%02x" % (m.group(1), b[0], b[1], b[2], b[3])
113
114
115
116
117 m = _colon_colon_start.match(text)
118 if not m is None:
119 text = text[1:]
120 else:
121 m = _colon_colon_end.match(text)
122 if not m is None:
123 text = text[:-1]
124
125
126
127 chunks = text.split(':')
128 l = len(chunks)
129 if l > 8:
130 raise dns.exception.SyntaxError
131 seen_empty = False
132 canonical = []
133 for c in chunks:
134 if c == '':
135 if seen_empty:
136 raise dns.exception.SyntaxError
137 seen_empty = True
138 for i in range(0, 8 - l + 1):
139 canonical.append('0000')
140 else:
141 lc = len(c)
142 if lc > 4:
143 raise dns.exception.SyntaxError
144 if lc != 4:
145 c = ('0' * (4 - lc)) + c
146 canonical.append(c)
147 if l < 8 and not seen_empty:
148 raise dns.exception.SyntaxError
149 text = ''.join(canonical)
150
151
152
153
154 try:
155 return bytes.fromhex(text)
156 except:
157 raise dns.exception.SyntaxError
158