1#----------------------------------------------------------------------------- 2# Copyright (c) 2008 by David P. D. Moss. All rights reserved. 3# 4# Released under the BSD license. See the LICENSE file for details. 5#----------------------------------------------------------------------------- 6""" 7IPv6 address logic. 8""" 9import struct as _struct 10 11OPT_IMPORTS = False 12 13# Check whether we need to use fallback code or not. 14try: 15 import socket as _socket 16 # These might all generate exceptions on different platforms. 17 if not _socket.has_ipv6: 18 raise Exception('IPv6 disabled') 19 _socket.inet_pton 20 _socket.AF_INET6 21 from _socket import (inet_pton as _inet_pton, inet_ntop as _inet_ntop, 22 AF_INET6) 23 OPT_IMPORTS = True 24except Exception: 25 from netaddr.fbsocket import (inet_pton as _inet_pton, inet_ntop as _inet_ntop, 26 AF_INET6) 27 28from netaddr.core import AddrFormatError 29from netaddr.strategy import ( 30 valid_words as _valid_words, int_to_words as _int_to_words, 31 words_to_int as _words_to_int, valid_bits as _valid_bits, 32 bits_to_int as _bits_to_int, int_to_bits as _int_to_bits, 33 valid_bin as _valid_bin, int_to_bin as _int_to_bin, 34 bin_to_int as _bin_to_int) 35 36#: The width (in bits) of this address type. 37width = 128 38 39#: The individual word size (in bits) of this address type. 40word_size = 16 41 42#: The separator character used between each word. 43word_sep = ':' 44 45#: The AF_* constant value of this address type. 46family = AF_INET6 47 48#: A friendly string name address type. 49family_name = 'IPv6' 50 51#: The version of this address type. 52version = 6 53 54#: The number base to be used when interpreting word values as integers. 55word_base = 16 56 57#: The maximum integer value that can be represented by this address type. 58max_int = 2 ** width - 1 59 60#: The number of words in this address type. 61num_words = width // word_size 62 63#: The maximum integer value for an individual word in this address type. 64max_word = 2 ** word_size - 1 65 66#: A dictionary mapping IPv6 CIDR prefixes to the equivalent netmasks. 67prefix_to_netmask = dict( 68 [(i, max_int ^ (2 ** (width - i) - 1)) for i in range(0, width+1)]) 69 70#: A dictionary mapping IPv6 netmasks to their equivalent CIDR prefixes. 71netmask_to_prefix = dict( 72 [(max_int ^ (2 ** (width - i) - 1), i) for i in range(0, width+1)]) 73 74#: A dictionary mapping IPv6 CIDR prefixes to the equivalent hostmasks. 75prefix_to_hostmask = dict( 76 [(i, (2 ** (width - i) - 1)) for i in range(0, width+1)]) 77 78#: A dictionary mapping IPv6 hostmasks to their equivalent CIDR prefixes. 79hostmask_to_prefix = dict( 80 [((2 ** (width - i) - 1), i) for i in range(0, width+1)]) 81 82#----------------------------------------------------------------------------- 83# Dialect classes. 84#----------------------------------------------------------------------------- 85 86class ipv6_compact(object): 87 """An IPv6 dialect class - compact form.""" 88 #: The format string used to converting words into string values. 89 word_fmt = '%x' 90 91 #: Boolean flag indicating if IPv6 compaction algorithm should be used. 92 compact = True 93 94class ipv6_full(ipv6_compact): 95 """An IPv6 dialect class - 'all zeroes' form.""" 96 97 #: Boolean flag indicating if IPv6 compaction algorithm should be used. 98 compact = False 99 100class ipv6_verbose(ipv6_compact): 101 """An IPv6 dialect class - extra wide 'all zeroes' form.""" 102 103 #: The format string used to converting words into string values. 104 word_fmt = '%.4x' 105 106 #: Boolean flag indicating if IPv6 compaction algorithm should be used. 107 compact = False 108 109 110def valid_str(addr, flags=0): 111 """ 112 :param addr: An IPv6 address in presentation (string) format. 113 114 :param flags: decides which rules are applied to the interpretation of the 115 addr value. Future use - currently has no effect. 116 117 :return: ``True`` if IPv6 address is valid, ``False`` otherwise. 118 """ 119 if addr == '': 120 raise AddrFormatError('Empty strings are not supported!') 121 122 try: 123 _inet_pton(AF_INET6, addr) 124 except: 125 return False 126 return True 127 128 129def str_to_int(addr, flags=0): 130 """ 131 :param addr: An IPv6 address in string form. 132 133 :param flags: decides which rules are applied to the interpretation of the 134 addr value. Future use - currently has no effect. 135 136 :return: The equivalent unsigned integer for a given IPv6 address. 137 """ 138 try: 139 packed_int = _inet_pton(AF_INET6, addr) 140 return packed_to_int(packed_int) 141 except Exception: 142 raise AddrFormatError('%r is not a valid IPv6 address string!' % (addr,)) 143 144 145def int_to_str(int_val, dialect=None): 146 """ 147 :param int_val: An unsigned integer. 148 149 :param dialect: (optional) a Python class defining formatting options. 150 151 :return: The IPv6 presentation (string) format address equivalent to the 152 unsigned integer provided. 153 """ 154 if dialect is None: 155 dialect = ipv6_compact 156 157 addr = None 158 159 try: 160 packed_int = int_to_packed(int_val) 161 if dialect.compact: 162 # Default return value. 163 addr = _inet_ntop(AF_INET6, packed_int) 164 else: 165 # Custom return value. 166 words = list(_struct.unpack('>8H', packed_int)) 167 tokens = [dialect.word_fmt % word for word in words] 168 addr = word_sep.join(tokens) 169 except Exception: 170 raise ValueError('%r is not a valid 128-bit unsigned integer!' % (int_val,)) 171 172 return addr 173 174 175def int_to_arpa(int_val): 176 """ 177 :param int_val: An unsigned integer. 178 179 :return: The reverse DNS lookup for an IPv6 address in network byte 180 order integer form. 181 """ 182 addr = int_to_str(int_val, ipv6_verbose) 183 tokens = list(addr.replace(':', '')) 184 tokens.reverse() 185 # We won't support ip6.int here - see RFC 3152 for details. 186 tokens = tokens + ['ip6', 'arpa', ''] 187 return '.'.join(tokens) 188 189 190def int_to_packed(int_val): 191 """ 192 :param int_val: the integer to be packed. 193 194 :return: a packed string that is equivalent to value represented by an 195 unsigned integer. 196 """ 197 words = int_to_words(int_val, 4, 32) 198 return _struct.pack('>4I', *words) 199 200 201def packed_to_int(packed_int): 202 """ 203 :param packed_int: a packed string containing an unsigned integer. 204 It is assumed that string is packed in network byte order. 205 206 :return: An unsigned integer equivalent to value of network address 207 represented by packed binary string. 208 """ 209 words = list(_struct.unpack('>4I', packed_int)) 210 211 int_val = 0 212 for i, num in enumerate(reversed(words)): 213 word = num 214 word = word << 32 * i 215 int_val = int_val | word 216 217 return int_val 218 219 220def valid_words(words): 221 return _valid_words(words, word_size, num_words) 222 223 224def int_to_words(int_val, num_words=None, word_size=None): 225 if num_words is None: 226 num_words = globals()['num_words'] 227 if word_size is None: 228 word_size = globals()['word_size'] 229 return _int_to_words(int_val, word_size, num_words) 230 231 232def words_to_int(words): 233 return _words_to_int(words, word_size, num_words) 234 235 236def valid_bits(bits): 237 return _valid_bits(bits, width, word_sep) 238 239 240def bits_to_int(bits): 241 return _bits_to_int(bits, width, word_sep) 242 243 244def int_to_bits(int_val, word_sep=None): 245 if word_sep is None: 246 word_sep = globals()['word_sep'] 247 return _int_to_bits(int_val, word_size, num_words, word_sep) 248 249 250def valid_bin(bin_val): 251 return _valid_bin(bin_val, width) 252 253 254def int_to_bin(int_val): 255 return _int_to_bin(int_val, width) 256 257 258def bin_to_int(bin_val): 259 return _bin_to_int(bin_val, width) 260