133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. 233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# 333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# Permission to use, copy, modify, and distribute this software and its 433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# documentation for any purpose with or without fee is hereby granted, 533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# provided that the above copyright notice and this permission notice 633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# appear in all copies. 733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# 833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES 933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR 1133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 1433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 1633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck"""IPv6 helper functions.""" 1733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 1833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport re 1933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 2033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport dns.exception 2133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport dns.ipv4 2233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 2333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck_leading_zero = re.compile(r'0+([0-9a-f]+)') 2433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 2533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef inet_ntoa(address): 2633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """Convert a network format IPv6 address into text. 2733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 2833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck @param address: the binary address 2933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck @type address: string 3033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck @rtype: string 3133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck @raises ValueError: the address isn't 16 bytes long 3233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """ 3333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 3433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if len(address) != 16: 3533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck raise ValueError("IPv6 addresses are 16 bytes long") 3633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck hex = address.encode('hex_codec') 3733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck chunks = [] 3833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck i = 0 3933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck l = len(hex) 4033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck while i < l: 4133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck chunk = hex[i : i + 4] 4233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # strip leading zeros. we do this with an re instead of 4333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # with lstrip() because lstrip() didn't support chars until 4433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # python 2.2.2 4533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck m = _leading_zero.match(chunk) 4633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if not m is None: 4733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck chunk = m.group(1) 4833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck chunks.append(chunk) 4933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck i += 4 5033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # 5133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # Compress the longest subsequence of 0-value chunks to :: 5233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # 5333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck best_start = 0 5433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck best_len = 0 5533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck start = -1 5633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck last_was_zero = False 5733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck for i in xrange(8): 5833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if chunks[i] != '0': 5933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if last_was_zero: 6033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck end = i 6133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck current_len = end - start 6233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if current_len > best_len: 6333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck best_start = start 6433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck best_len = current_len 6533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck last_was_zero = False 6633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck elif not last_was_zero: 6733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck start = i 6833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck last_was_zero = True 6933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if last_was_zero: 7033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck end = 8 7133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck current_len = end - start 7233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if current_len > best_len: 7333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck best_start = start 7433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck best_len = current_len 7533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if best_len > 0: 7633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if best_start == 0 and \ 7733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck (best_len == 6 or 7833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck best_len == 5 and chunks[5] == 'ffff'): 7933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # We have an embedded IPv4 address 8033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if best_len == 6: 8133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck prefix = '::' 8233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck else: 8333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck prefix = '::ffff:' 8433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck hex = prefix + dns.ipv4.inet_ntoa(address[12:]) 8533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck else: 8633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck hex = ':'.join(chunks[:best_start]) + '::' + \ 8733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck ':'.join(chunks[best_start + best_len:]) 8833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck else: 8933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck hex = ':'.join(chunks) 9033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return hex 9133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 9233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck_v4_ending = re.compile(r'(.*):(\d+)\.(\d+)\.(\d+)\.(\d+)$') 9333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck_colon_colon_start = re.compile(r'::.*') 9433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck_colon_colon_end = re.compile(r'.*::$') 9533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 9633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef inet_aton(text): 9733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """Convert a text format IPv6 address into network format. 9833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 9933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck @param text: the textual address 10033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck @type text: string 10133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck @rtype: string 10233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck @raises dns.exception.SyntaxError: the text was not properly formatted 10333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """ 10433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 10533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # 10633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # Our aim here is not something fast; we just want something that works. 10733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # 10833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 10933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if text == '::': 11033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck text = '0::' 11133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # 11233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # Get rid of the icky dot-quad syntax if we have it. 11333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # 11433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck m = _v4_ending.match(text) 11533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if not m is None: 11633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck text = "%s:%04x:%04x" % (m.group(1), 11733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck int(m.group(2)) * 256 + int(m.group(3)), 11833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck int(m.group(4)) * 256 + int(m.group(5))) 11933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # 12033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # Try to turn '::<whatever>' into ':<whatever>'; if no match try to 12133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # turn '<whatever>::' into '<whatever>:' 12233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # 12333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck m = _colon_colon_start.match(text) 12433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if not m is None: 12533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck text = text[1:] 12633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck else: 12733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck m = _colon_colon_end.match(text) 12833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if not m is None: 12933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck text = text[:-1] 13033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # 13133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # Now canonicalize into 8 chunks of 4 hex digits each 13233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # 13333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck chunks = text.split(':') 13433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck l = len(chunks) 13533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if l > 8: 13633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck raise dns.exception.SyntaxError 13733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck seen_empty = False 13833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck canonical = [] 13933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck for c in chunks: 14033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if c == '': 14133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if seen_empty: 14233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck raise dns.exception.SyntaxError 14333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck seen_empty = True 14433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck for i in xrange(0, 8 - l + 1): 14533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck canonical.append('0000') 14633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck else: 14733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck lc = len(c) 14833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if lc > 4: 14933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck raise dns.exception.SyntaxError 15033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if lc != 4: 15133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck c = ('0' * (4 - lc)) + c 15233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck canonical.append(c) 15333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if l < 8 and not seen_empty: 15433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck raise dns.exception.SyntaxError 15533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck text = ''.join(canonical) 15633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 15733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # 15833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # Finally we can go to binary. 15933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # 16033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck try: 16133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return text.decode('hex_codec') 16233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck except TypeError: 16333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck raise dns.exception.SyntaxError 164