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

Source Code for Module dns.ipv6

  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   
 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: string 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: string 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 text = "%s:%04x:%04x" % (m.group(1), 112 int(m.group(2)) * 256 + int(m.group(3)), 113 int(m.group(4)) * 256 + int(m.group(5))) 114 # 115 # Try to turn '::<whatever>' into ':<whatever>'; if no match try to 116 # turn '<whatever>::' into '<whatever>:' 117 # 118 m = _colon_colon_start.match(text) 119 if not m is None: 120 text = text[1:] 121 else: 122 m = _colon_colon_end.match(text) 123 if not m is None: 124 text = text[:-1] 125 # 126 # Now canonicalize into 8 chunks of 4 hex digits each 127 # 128 chunks = text.split(':') 129 l = len(chunks) 130 if l > 8: 131 raise dns.exception.SyntaxError 132 seen_empty = False 133 canonical = [] 134 for c in chunks: 135 if c == '': 136 if seen_empty: 137 raise dns.exception.SyntaxError 138 seen_empty = True 139 for i in range(0, 8 - l + 1): 140 canonical.append('0000') 141 else: 142 lc = len(c) 143 if lc > 4: 144 raise dns.exception.SyntaxError 145 if lc != 4: 146 c = ('0' * (4 - lc)) + c 147 canonical.append(c) 148 if l < 8 and not seen_empty: 149 raise dns.exception.SyntaxError 150 text = ''.join(canonical) 151 152 # 153 # Finally we can go to binary. 154 # 155 try: 156 return bytes.fromhex(text) 157 except TypeError: 158 raise dns.exception.SyntaxError
159