Package dns :: Module ipv6
[hide private]
[frames] | no frames]

Source Code for Module dns.ipv6

  1  # Copyright (C) 2003-2007, 2009-2011 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   
 18  import base64 
 19  import re 
 20   
 21  import dns.exception 
 22  import dns.ipv4 
 23   
24 -def inet_ntoa(address):
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 # Compress the longest subsequence of 0-value chunks to :: 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 # We have an embedded IPv4 address 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
91 -def inet_aton(text):
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 # Our aim here is not something fast; we just want something that works. 102 # 103 104 if text == '::': 105 text = '0::' 106 # 107 # Get rid of the icky dot-quad syntax if we have it. 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 # Try to turn '::<whatever>' into ':<whatever>'; if no match try to 115 # turn '<whatever>::' into '<whatever>:' 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 # Now canonicalize into 8 chunks of 4 hex digits each 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 # Finally we can go to binary. 153 # 154 try: 155 return bytes.fromhex(text) 156 except: 157 raise dns.exception.SyntaxError
158