Package netaddr :: Module strategy
[hide private]
[frames] | no frames]

Source Code for Module netaddr.strategy

  1  #!/usr/bin/env python 
  2  #----------------------------------------------------------------------------- 
  3  #   Copyright (c) 2008-2009, David P. D. Moss. All rights reserved. 
  4  # 
  5  #   Released under the BSD license. See the LICENSE file for details. 
  6  #----------------------------------------------------------------------------- 
  7  """ 
  8  network address conversion logic, constants and shared strategy objects. 
  9  """ 
 10  import struct as _struct 
 11  import re as _re 
 12  from netaddr.util import BYTES_TO_BITS as _BYTES_TO_BITS 
 13   
 14  #   Check whether we need to use fallback code or not. 
 15  try: 
 16      import socket as _socket 
 17      #   Check for a common bug on Windows and some other socket modules. 
 18      _socket.inet_aton('255.255.255.255') 
 19      from socket import inet_aton as _inet_aton, \ 
 20                         inet_ntoa as _inet_ntoa, \ 
 21                         AF_INET as _AF_INET 
 22  except: 
 23      from netaddr.fallback import inet_aton as _inet_aton, \ 
 24                                   inet_ntoa as _inet_ntoa, \ 
 25                                   AF_INET as _AF_INET 
 26  try: 
 27      import socket as _socket 
 28      #   These might all generate exceptions on different platforms. 
 29      _socket.inet_pton 
 30      _socket.AF_INET6 
 31      from socket import inet_pton as _inet_pton, \ 
 32                         inet_ntop as _inet_ntop, \ 
 33                         AF_INET6 as _AF_INET6 
 34  except: 
 35      from netaddr.fallback import inet_pton as _inet_pton, \ 
 36                                   inet_ntop as _inet_ntop, \ 
 37                                   AF_INET6 as _AF_INET6 
 38   
 39  from netaddr import BIG_ENDIAN_PLATFORM, AT_UNSPEC, AT_INET, AT_INET6, \ 
 40                      AT_LINK, AT_EUI64, AT_NAMES, AddrFormatError 
 41   
 42  #----------------------------------------------------------------------------- 
43 -class AddrStrategy(object):
44 """Basic support for common operations performed on each address type""" 45 46 #: Lookup table for struct module format strings. 47 STRUCT_FORMATS = { 48 8 : 'B', # unsigned char 49 16 : 'H', # unsigned short 50 32 : 'I', # unsigned int 51 } 52
53 - def __init__(self, width, word_size, word_sep, word_fmt='%x', 54 addr_type=AT_UNSPEC, word_base=16):
55 """ 56 Constructor. 57 58 @param width: size of address in bits. 59 (e.g. 32 - IPv4, 48 - MAC, 128 - IPv6) 60 61 @param word_size: size of each word. 62 (e.g. 8 - octets, 16 - hextets) 63 64 @param word_sep: separator between each word. 65 (e.g. '.' - IPv4, ':' - IPv6, '-' - EUI-48) 66 67 @param word_fmt: format string for each word. 68 (Default: '%x') 69 70 @param addr_type: address type. 71 (Default: AT_UNSPEC) 72 73 @param word_base: number base used to convert each word using int(). 74 (Default: 16) 75 """ 76 77 self.width = width 78 self.max_int = 2 ** width - 1 79 self.word_size = word_size 80 self.num_words = width / word_size 81 self.max_word = 2 ** word_size - 1 82 self.word_sep = word_sep 83 self.word_fmt = word_fmt 84 self.word_base = word_base 85 self.addr_type = addr_type 86 87 try: 88 self.name = AT_NAMES[addr_type] 89 except KeyError: 90 self.name = AT_NAMES[AT_UNSPEC]
91
92 - def __repr__(self):
93 """@return: executable Python string to recreate equivalent object""" 94 return "%s(%r, %r, %r, %r, %r, %r)" % (self.__class__.__name__, 95 self.width, self.word_size, self.word_sep, self.addr_type, 96 self.word_base)
97 98 #------------------------------------------------------------------------- 99 # Binary methods. 100 #------------------------------------------------------------------------- 101
102 - def valid_bits(self, bits):
103 """ 104 @param bits: A network address in readable binary form. 105 106 @return: C{True} if network address is valid for this address type, 107 C{False} otherwise. 108 """ 109 if not isinstance(bits, (str, unicode)): 110 return False 111 112 bits = bits.replace(self.word_sep, '') 113 114 if len(bits) != self.width: 115 return False 116 117 try: 118 if 0 <= int(bits, 2) <= self.max_int: 119 return True 120 except ValueError: 121 return False 122 return False
123
124 - def bits_to_int(self, bits):
125 """ 126 @param bits: A network address in readable binary form. 127 128 @return: An unsigned integer that is equivalent to value represented 129 by network address in readable binary form. 130 """ 131 if not self.valid_bits(bits): 132 raise ValueError('%r is not a valid binary form string for ' \ 133 'address type!' % bits) 134 135 return int(bits.replace(self.word_sep, ''), 2)
136 137 #------------------------------------------------------------------------- 138 # Integer methods. 139 #------------------------------------------------------------------------- 140
141 - def valid_int(self, int_val):
142 """ 143 @param int_val: An unsigned integer. 144 145 @return: C{True} if integer falls within the boundaries of this 146 address type, C{False} otherwise. 147 """ 148 if not isinstance(int_val, (int, long)): 149 return False 150 151 return 0 <= int_val <= self.max_int
152
153 - def int_to_str(self, int_val):
154 """ 155 @param int_val: An unsigned integer. 156 157 @return: A network address in string form that is equivalent to value 158 represented by an unsigned integer. 159 """ 160 words = self.int_to_words(int_val) 161 tokens = [self.word_fmt % i for i in words] 162 addr = self.word_sep.join(tokens) 163 164 return addr
165
166 - def int_to_bits(self, int_val, word_sep=None):
167 """ 168 @param int_val: An unsigned integer. 169 170 @param word_sep: (optional) the separator to insert between words. 171 Default: None - use default separator for address type. 172 173 @return: A network address in readable binary form that is equivalent 174 to value represented by an unsigned integer. 175 """ 176 bit_words = [] 177 178 for word in self.int_to_words(int_val): 179 bits = [] 180 while word: 181 bits.append(_BYTES_TO_BITS[word&255]) 182 word >>= 8 183 bits.reverse() 184 bit_str = ''.join(bits) or '0'*self.word_size 185 bits = ('0'*self.word_size+bit_str)[-self.word_size:] 186 bit_words.append(bits) 187 188 if word_sep is not None: 189 # Custom separator. 190 if not hasattr(word_sep, 'join'): 191 raise ValueError('Word separator must be a string!') 192 return word_sep.join(bit_words) 193 194 # Default separator. 195 return self.word_sep.join(bit_words)
196
197 - def int_to_bin(self, int_val):
198 """ 199 @param int_val: An unsigned integer. 200 201 @return: A network address in standard binary representation format 202 that is equivalent to integer address value. Essentially a back 203 port of the bin() builtin in Python 2.6.x and higher. 204 """ 205 bit_words = [] 206 207 for word in self.int_to_words(int_val): 208 bits = [] 209 while word: 210 bits.append(_BYTES_TO_BITS[word&255]) 211 word >>= 8 212 bits.reverse() 213 bit_str = ''.join(bits) or '0'*self.word_size 214 bits = ('0'*self.word_size+bit_str)[-self.word_size:] 215 bit_words.append(bits) 216 217 return '0b' + ''.join(bit_words)
218
219 - def int_to_words(self, int_val, num_words=None, word_size=None):
220 """ 221 @param int_val: An unsigned integer to be divided up into words. 222 223 @param num_words: (optional) number of words expected in return value 224 tuple. Uses address type default if not specified. 225 226 @param word_size: (optional) size/width of individual words (in bits). 227 Uses address type default if not specified. 228 """ 229 if not self.valid_int(int_val): 230 raise IndexError('integer %r is out of bounds!' % hex(int_val)) 231 232 # Set defaults for optional args. 233 if num_words is None: 234 num_words = self.num_words 235 if word_size is None: 236 word_size = self.word_size 237 238 max_word_size = 2 ** word_size - 1 239 240 words = [] 241 for _ in range(num_words): 242 word = int_val & max_word_size 243 words.append(int(word)) 244 int_val >>= word_size 245 246 return tuple(reversed(words))
247
248 - def int_to_packed(self, int_val):
249 """ 250 @param int_val: the integer to be packed. 251 252 @return: a packed string that is equivalent to value represented by an 253 unsigned integer. 254 """ 255 256 words = self.int_to_words(int_val, self.num_words, self.word_size) 257 258 try: 259 fmt = '>%d%s' % (self.num_words, AddrStrategy.STRUCT_FORMATS[ 260 self.word_size]) 261 except KeyError: 262 raise ValueError('unsupported word size: %d!' % self.word_size) 263 264 return _struct.pack(fmt, *words)
265 266 267 #------------------------------------------------------------------------- 268 # Packed string methods. 269 #------------------------------------------------------------------------- 270
271 - def packed_to_int(self, packed_int):
272 """ 273 @param packed_int: a packed string containing an unsigned integer. 274 It is assumed that the string is packed in network byte order. 275 276 @return: An unsigned integer equivalent to value of network address 277 represented by packed binary string. 278 """ 279 try: 280 fmt = '>%d%s' % (self.num_words, AddrStrategy.STRUCT_FORMATS[ 281 self.word_size]) 282 except KeyError: 283 raise ValueError('unsupported word size: %d!' % self.word_size) 284 285 words = list(_struct.unpack(fmt, packed_int)) 286 287 int_val = 0 288 for i, num in enumerate(reversed(words)): 289 word = num 290 word = word << self.word_size * i 291 int_val = int_val | word 292 293 return int_val
294 295 #------------------------------------------------------------------------- 296 # String methods. 297 #------------------------------------------------------------------------- 298
299 - def valid_str(self, addr):
300 """ 301 @param addr: A network address in string form. 302 303 @return: C{True} if network address in string form is valid for this 304 address type, C{False} otherwise. 305 """ 306 if not isinstance(addr, (str, unicode)): 307 return False 308 309 tokens = addr.split(self.word_sep) 310 if len(tokens) != self.num_words: 311 return False 312 313 try: 314 for token in tokens: 315 if not 0 <= int(token, self.word_base) <= \ 316 self.max_word: 317 return False 318 except TypeError: 319 return False 320 except ValueError: 321 return False 322 return True
323
324 - def str_to_int(self, addr):
325 """ 326 @param addr: A network address in string form. 327 328 @return: An unsigned integer equivalent to value represented by network 329 address in string form. 330 """ 331 if not self.valid_str(addr): 332 raise ValueError('%r is not a recognised string representation' \ 333 ' of this address type!' % addr) 334 335 tokens = addr.split(self.word_sep) 336 words = [ int(token, self.word_base) for token in tokens ] 337 338 return self.words_to_int(words)
339 340 #------------------------------------------------------------------------- 341 # Word list methods. 342 #------------------------------------------------------------------------- 343
344 - def valid_words(self, words):
345 """ 346 @param words: A sequence containing integer word values. 347 348 @return: C{True} if word sequence is valid for this address type, 349 C{False} otherwise. 350 """ 351 if not hasattr(words, '__iter__'): 352 return False 353 354 if len(words) != self.num_words: 355 return False 356 357 for i in words: 358 if not isinstance(i, (int, long)): 359 return False 360 361 if not 0 <= i <= self.max_word: 362 return False 363 return True
364
365 - def words_to_int(self, words):
366 """ 367 @param words: A list or tuple containing integer word values. 368 369 @return: An unsigned integer that is equivalent to value represented 370 by word sequence. 371 """ 372 if not self.valid_words(words): 373 raise ValueError('%r is not a valid word list!' % words) 374 375 int_val = 0 376 for i, num in enumerate(reversed(words)): 377 word = num 378 word = word << self.word_size * i 379 int_val = int_val | word 380 381 return int_val
382 383 #-----------------------------------------------------------------------------
384 -class IPv4Strategy(AddrStrategy):
385 """An L{AddrStrategy} for IPv4 address processing."""
386 - def __init__(self):
387 """Constructor.""" 388 super(IPv4Strategy, self).__init__(width=32, word_size=8, 389 word_fmt='%d', word_sep='.', addr_type=AT_INET, word_base=10)
390
391 - def valid_str(self, addr):
392 """ 393 @param addr: An IP address in presentation (string) format. 394 395 @return: C{True} if network address in string form is valid for this 396 address type, C{False} otherwise. 397 """ 398 if addr == '': 399 raise AddrFormatError('Empty strings are not supported!') 400 401 try: 402 _inet_aton(addr) 403 except: 404 return False 405 return True
406
407 - def str_to_int(self, addr):
408 """ 409 @param addr: An IPv4 dotted decimal address in string form. 410 411 @return: An unsigned integer that is equivalent to value represented 412 by the IPv4 dotted decimal address string. 413 """ 414 if addr == '': 415 raise AddrFormatError('Empty strings are not supported!') 416 try: 417 return _struct.unpack('>I', _inet_aton(addr))[0] 418 except: 419 raise AddrFormatError('%r is not a valid IPv4 address string!' \ 420 % addr)
421
422 - def int_to_str(self, int_val):
423 """ 424 @param int_val: An unsigned integer. 425 426 @return: An IPv4 dotted decimal address string that is equivalent to 427 value represented by a 32 bit unsigned integer. 428 """ 429 if self.valid_int(int_val): 430 return _inet_ntoa(_struct.pack('>I', int_val)) 431 else: 432 raise ValueError('%r is not a valid 32-bit unsigned integer!' \ 433 % int_val)
434
435 - def int_to_words(self, int_val, num_words=None, word_size=None):
436 """ 437 @param int_val: An unsigned integer. 438 439 @param num_words: (unused) *** interface compatibility only *** 440 441 @param word_size: (unused) *** interface compatibility only *** 442 443 @return: An integer word (octet) sequence that is equivalent to value 444 represented by an unsigned integer. 445 """ 446 if not self.valid_int(int_val): 447 raise ValueError('%r is not a valid integer value supported ' \ 448 'by this address type!' % int_val) 449 return _struct.unpack('4B', _struct.pack('>I', int_val))
450
451 - def words_to_int(self, octets):
452 """ 453 @param octets: A list or tuple containing integer octets. 454 455 @return: An unsigned integer that is equivalent to value represented 456 by word (octet) sequence. 457 """ 458 if not self.valid_words(octets): 459 raise ValueError('%r is not a valid octet list for an IPv4 ' \ 460 'address!' % octets) 461 return _struct.unpack('>I', _struct.pack('4B', *octets))[0]
462
463 - def int_to_arpa(self, int_val):
464 """ 465 @param int_val: An unsigned integer. 466 467 @return: The reverse DNS lookup for an IPv4 address in network byte 468 order integer form. 469 """ 470 words = ["%d" % i for i in self.int_to_words(int_val)] 471 words.reverse() 472 words.extend(['in-addr', 'arpa', '']) 473 return '.'.join(words)
474 475 #-----------------------------------------------------------------------------
476 -class IPv6Strategy(AddrStrategy):
477 """ 478 An L{AddrStrategy} for IPv6 address processing. 479 480 Implements the operations that can be performed on an IPv6 network address 481 in accordance with RFC 4291. 482 """
483 - def __init__(self):
484 """Constructor.""" 485 super(IPv6Strategy, self).__init__(addr_type=AT_INET6, 486 width=128, word_size=16, word_fmt='%x', word_sep=':')
487
488 - def valid_str(self, addr):
489 """ 490 @param addr: An IPv6 address in string form. 491 492 @return: C{True} if IPv6 network address string is valid, C{False} 493 otherwise. 494 """ 495 if addr == '': 496 raise AddrFormatError('Empty strings are not supported!') 497 498 try: 499 _inet_pton(_AF_INET6, addr) 500 except _socket.error: 501 return False 502 except TypeError: 503 return False 504 except ValueError: 505 return False 506 return True
507
508 - def str_to_int(self, addr):
509 """ 510 @param addr: An IPv6 address in string form. 511 512 @return: The equivalent unsigned integer for a given IPv6 address. 513 """ 514 if addr == '': 515 raise AddrFormatError('Empty strings are not supported!') 516 try: 517 packed_int = _inet_pton(_AF_INET6, addr) 518 return self.packed_to_int(packed_int) 519 except Exception, e: 520 raise AddrFormatError('%r is not a valid IPv6 address string!' \ 521 % addr)
522
523 - def int_to_str(self, int_val, compact=True, word_fmt=None):
524 """ 525 @param int_val: An unsigned integer. 526 527 @param compact: (optional) A boolean flag indicating if compact 528 formatting should be used. If True, this method uses the '::' 529 string to represent the first adjacent group of words with a value 530 of zero. Default: True 531 532 @param word_fmt: (optional) The Python format string used to override 533 formatting for each word. Only applies when compact is False. 534 535 @return: The IPv6 string form equal to the unsigned integer provided. 536 """ 537 try: 538 packed_int = self.int_to_packed(int_val) 539 if compact: 540 # Default return value. 541 return _inet_ntop(_AF_INET6, packed_int) 542 else: 543 # Custom return value. 544 if word_fmt is None: 545 word_fmt = self.word_fmt 546 words = list(_struct.unpack('>8H', packed_int)) 547 tokens = [word_fmt % word for word in words] 548 return self.word_sep.join(tokens) 549 except Exception, e: 550 raise ValueError('%r is not a valid 128-bit unsigned integer!' \ 551 % int_val)
552
553 - def int_to_packed(self, int_val):
554 """ 555 @param int_val: the integer to be packed. 556 557 @return: a packed string that is equivalent to value represented by an 558 unsigned integer (in network byte order). 559 """ 560 # Here we've over-ridden the normal values to get the fastest 561 # possible conversion speeds. Still quite slow versus IPv4 speed ups. 562 num_words = 4 563 word_size = 32 564 565 words = self.int_to_words(int_val, num_words, word_size) 566 567 try: 568 fmt = '>%d%s'% (num_words, AddrStrategy.STRUCT_FORMATS[word_size]) 569 except KeyError: 570 raise ValueError('unsupported word size: %d!' % word_size) 571 572 return _struct.pack(fmt, *words)
573
574 - def packed_to_int(self, packed_int):
575 """ 576 @param packed_int: a packed string containing an unsigned integer. 577 It is assumed that string is packed in network byte order. 578 579 @return: An unsigned integer that is equivalent to value of network 580 address represented by packed binary string. 581 """ 582 # Here we've over-ridden the normal values to get the fastest 583 # conversion speeds. Still quite slow versus IPv4 speed ups. 584 num_words = 4 585 word_size = 32 586 587 try: 588 fmt = '>%d%s'% (num_words, AddrStrategy.STRUCT_FORMATS[word_size]) 589 except KeyError: 590 raise ValueError('unsupported word size: %d!' % word_size) 591 592 words = list(_struct.unpack(fmt, packed_int)) 593 594 int_val = 0 595 for i, num in enumerate(reversed(words)): 596 word = num 597 word = word << word_size * i 598 int_val = int_val | word 599 600 return int_val
601
602 - def int_to_arpa(self, int_val):
603 """ 604 @param int_val: An unsigned integer. 605 606 @return: The reverse DNS lookup for an IPv6 address in network byte 607 order integer form. 608 """ 609 addr = self.int_to_str(int_val, compact=False, word_fmt='%.4x') 610 tokens = list(addr.replace(':', '')) 611 tokens.reverse() 612 # We won't support ip6.int here - see RFC 3152 for details. 613 tokens = tokens + ['ip6', 'arpa', ''] 614 return '.'.join(tokens)
615 616 #-----------------------------------------------------------------------------
617 -class EUI48Strategy(AddrStrategy):
618 """ 619 Implements the operations that can be performed on an IEEE 48-bit EUI 620 (Extended Unique Identifer) a.k.a. a MAC (Media Access Control) layer 2 621 address. 622 623 Supports all common (and some less common MAC string formats including 624 Cisco's 'triple hextet' format and also bare MACs that contain no 625 delimiters. 626 """ 627 # Regular expression to match the numerous different MAC formats. 628 RE_MAC_FORMATS = ( 629 # 2 bytes x 6 (UNIX, Windows, EUI-48) 630 '^' + ':'.join(['([0-9A-F]{1,2})'] * 6) + '$', 631 '^' + '-'.join(['([0-9A-F]{1,2})'] * 6) + '$', 632 633 # 4 bytes x 3 (Cisco) 634 '^' + ':'.join(['([0-9A-F]{1,4})'] * 3) + '$', 635 '^' + '-'.join(['([0-9A-F]{1,4})'] * 3) + '$', 636 637 # 6 bytes x 2 (PostgreSQL) 638 '^' + '-'.join(['([0-9A-F]{5,6})'] * 2) + '$', 639 '^' + ':'.join(['([0-9A-F]{5,6})'] * 2) + '$', 640 641 # 12 bytes (bare, no delimiters) 642 '^(' + ''.join(['[0-9A-F]'] * 12) + ')$', 643 '^(' + ''.join(['[0-9A-F]'] * 11) + ')$', 644 ) 645 # For efficiency, replace each string regexp with its compiled 646 # equivalent. 647 RE_MAC_FORMATS = [_re.compile(_, _re.IGNORECASE) for _ in RE_MAC_FORMATS] 648
649 - def __init__(self, word_fmt='%.2X', word_sep='-'):
650 """ 651 Constructor. 652 653 @param word_sep: separator between each word. 654 (Default: '-') 655 656 @param word_fmt: format string for each hextet. 657 (Default: '%02x') 658 """ 659 super(self.__class__, self).__init__(addr_type=AT_LINK, width=48, 660 word_size=8, word_fmt=word_fmt, word_sep=word_sep)
661 662
663 - def reset(self):
664 """ 665 Resets the internal state of this strategy to safe default values. 666 """ 667 # These are the settings for EUI-48 specific formatting. 668 self.width = 48 669 self.max_int = 2 ** self.width - 1 670 self.word_size = 8 671 self.num_words = self.width / self.word_size 672 self.max_word = 2 ** self.word_size - 1 673 self.word_sep = '-' 674 self.word_fmt = '%.2X' 675 self.word_base = 16 676 self.addr_type = AT_LINK
677
678 - def valid_str(self, addr):
679 """ 680 @param addr: An EUI-48 or MAC address in string form. 681 682 @return: C{True} if MAC address string is valid, C{False} otherwise. 683 """ 684 if not isinstance(addr, (str, unicode)): 685 return False 686 687 for regexp in EUI48Strategy.RE_MAC_FORMATS: 688 match_result = regexp.findall(addr) 689 if len(match_result) != 0: 690 return True 691 return False
692
693 - def str_to_int(self, addr):
694 """ 695 @param addr: An EUI-48 or MAC address in string form. 696 697 @return: An unsigned integer that is equivalent to value represented 698 by EUI-48/MAC string address. 699 """ 700 words = [] 701 if isinstance(addr, (str, unicode)): 702 found_match = False 703 for regexp in EUI48Strategy.RE_MAC_FORMATS: 704 match_result = regexp.findall(addr) 705 if len(match_result) != 0: 706 found_match = True 707 if isinstance(match_result[0], tuple): 708 words = match_result[0] 709 else: 710 words = (match_result[0],) 711 break 712 if not found_match: 713 raise AddrFormatError('%r is not a supported MAC format!' \ 714 % addr) 715 else: 716 raise TypeError('%r is not str() or unicode()!' % addr) 717 718 int_val = None 719 720 if len(words) == 6: 721 # 2 bytes x 6 (UNIX, Windows, EUI-48) 722 int_val = int(''.join(['%.2x' % int(w, 16) for w in words]), 16) 723 elif len(words) == 3: 724 # 4 bytes x 3 (Cisco) 725 int_val = int(''.join(['%.4x' % int(w, 16) for w in words]), 16) 726 elif len(words) == 2: 727 # 6 bytes x 2 (PostgreSQL) 728 int_val = int(''.join(['%.6x' % int(w, 16) for w in words]), 16) 729 elif len(words) == 1: 730 # 12 bytes (bare, no delimiters) 731 int_val = int('%012x' % int(words[0], 16), 16) 732 else: 733 raise AddrFormatError('unexpected word count in MAC address %r!' \ 734 % addr) 735 736 return int_val
737
738 - def int_to_str(self, int_val, word_sep=None, word_fmt=None):
739 """ 740 @param int_val: An unsigned integer. 741 742 @param word_sep: (optional) The separator used between words in an 743 address string. 744 745 @param word_fmt: (optional) A Python format string used to format 746 each word of address. 747 748 @return: A MAC address in string form that is equivalent to value 749 represented by an unsigned integer. 750 """ 751 _word_sep = self.word_sep 752 if word_sep is not None: 753 _word_sep = word_sep 754 755 _word_fmt = self.word_fmt 756 if word_fmt is not None: 757 _word_fmt = word_fmt 758 759 words = self.int_to_words(int_val) 760 tokens = [_word_fmt % i for i in words] 761 addr = _word_sep.join(tokens) 762 763 return addr
764 765 #----------------------------------------------------------------------------- 766 # Shared strategy objects for supported address types. 767 #----------------------------------------------------------------------------- 768 769 #: A shared strategy object supporting all operations on IPv4 addresses. 770 ST_IPV4 = IPv4Strategy() 771 772 #: A shared strategy object supporting all operations on IPv6 addresses. 773 ST_IPV6 = IPv6Strategy() 774 775 #: A shared strategy object supporting all operations on EUI-48/MAC addresses. 776 ST_EUI48 = EUI48Strategy() 777 778 #: A shared strategy object supporting all operations on EUI-64 addresses. 779 ST_EUI64 = AddrStrategy(addr_type=AT_EUI64, width=64, word_size=8, \ 780 word_fmt='%.2X', word_sep='-') 781 782 #----------------------------------------------------------------------------- 783 if __name__ == '__main__': 784 pass 785