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

Source Code for Module netaddr.strategy

  1  #!/usr/bin/env python 
  2  #----------------------------------------------------------------------------- 
  3  #   Copyright (c) 2008, 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 type logic, constants used to identify them and shared 
  9  strategy objects. 
 10  """ 
 11  import socket as _socket 
 12  import struct as _struct 
 13   
 14  from netaddr import BIG_ENDIAN_PLATFORM, AT_UNSPEC, AT_INET, AT_INET6, \ 
 15                      AT_LINK, AT_EUI64, AT_DESCR 
 16   
 17  #----------------------------------------------------------------------------- 
18 -def _BYTES_TO_BITS():
19 """ 20 Generates a 256 element list of 8-bit binary digit strings. List index is 21 equivalent to the bit string value. 22 """ 23 lookup = [] 24 bits_per_byte = range(7, -1, -1) 25 for num in range(256): 26 bits = 8*[None] 27 for i in bits_per_byte: 28 bits[i] = '01'[num&1] 29 num >>= 1 30 lookup.append(''.join(bits)) 31 return lookup
32 33 _BYTES_TO_BITS = _BYTES_TO_BITS() 34 35 #-----------------------------------------------------------------------------
36 -class AddrStrategy(object):
37 """ 38 Very basic support for all common operations performed on each network 39 type. 40 41 There are usually subclasses for each address type that over-ride methods 42 implemented here to optimise their performance and add additional 43 features. 44 """
45 - def __init__(self, width, word_size, delimiter, word_fmt='%x', 46 addr_type=AT_UNSPEC, hex_words=True, to_upper=False):
47 48 self.width = width 49 self.min_int = 0 50 self.max_int = 2 ** width - 1 51 self.word_size = word_size 52 self.word_count = width / word_size 53 self.min_word = 0 54 self.max_word = 2 ** word_size - 1 55 self.delimiter = delimiter 56 self.word_fmt = word_fmt 57 self.hex_words = hex_words 58 self.word_base = 16 59 self.addr_type = addr_type 60 self.to_upper = to_upper 61 62 if self.hex_words is False: 63 self.word_base = 10 64 65 try: 66 self.name = AT_DESCR[addr_type] 67 except KeyError: 68 self.name = AT_DESCR[AT_UNSPEC]
69
70 - def __repr__(self):
71 """ 72 @return: An executable Python statement that can recreate an object 73 with an equivalent state. 74 """ 75 return "netaddr.address.%s(%r, %r, %r, %r, %r, %r)" % \ 76 (self.__class__.__name__, self.width, self.word_size, 77 self.delimiter, self.addr_type, self.hex_words, self.to_upper)
78 79 #------------------------------------------------------------------------- 80 # Binary methods. 81 #------------------------------------------------------------------------- 82
83 - def valid_bits(self, bits):
84 """ 85 @param bits: A network address in readable binary form. 86 87 @return: C{True} if network address is valid for this address type, 88 C{False} otherwise. 89 """ 90 if not isinstance(bits, (str, unicode)): 91 return False 92 93 bits = bits.replace(self.delimiter, '') 94 95 if len(bits) != self.width: 96 return False 97 98 try: 99 if self.min_int <= int(bits, 2) <= self.max_int: 100 return True 101 except ValueError: 102 return False 103 return False
104
105 - def bits_to_int(self, bits):
106 """ 107 @param bits: A network address in readable binary form. 108 109 @return: A network byte order integer that is equivalent to value 110 represented by network address in readable binary form. 111 """ 112 words = self.bits_to_words(bits) 113 return self.words_to_int(words)
114
115 - def bits_to_str(self, bits):
116 """ 117 @param bits: A network address in readable binary form. 118 119 @return: A network address in string form that is equivalent to value 120 represented by network address in readable binary form. 121 """ 122 words = self.bits_to_words(bits) 123 return self.words_to_str(words)
124
125 - def bits_to_words(self, bits):
126 """ 127 @param bits: A network address in readable binary form. 128 129 @return: An integer word sequence that is equivalent to value 130 represented by network address in readable binary form. 131 """ 132 if not self.valid_bits(bits): 133 raise Exception('%r is not a valid readable binary form string' \ 134 ' for address type!' % bits) 135 136 word_bits = bits.split(self.delimiter) 137 if len(word_bits) != self.word_count: 138 raise Exception('invalid number of words found in binary form ' \ 139 'string for address type!' % bits) 140 141 return tuple([int(i, 2) for i in word_bits])
142 143 #------------------------------------------------------------------------- 144 # Integer methods. 145 #------------------------------------------------------------------------- 146
147 - def valid_int(self, int_val):
148 """ 149 @param int_val: A network byte order integer. 150 151 @return: C{True} if network byte order integer falls within the 152 boundaries of this address type, C{False} otherwise. 153 """ 154 if not isinstance(int_val, (int, long)): 155 return False 156 157 if self.min_int <= int_val <= self.max_int: 158 return True 159 160 return False
161
162 - def int_to_str(self, int_val):
163 """ 164 @param int_val: A network byte order integer. 165 166 @return: A network address in string form that is equivalent to value 167 represented by a network byte order integer. 168 """ 169 words = self.int_to_words(int_val) 170 tokens = [self.word_fmt % i for i in words] 171 addr = self.delimiter.join(tokens) 172 173 if self.to_upper is True: 174 return addr.upper() 175 176 return addr
177
178 - def int_to_bits(self, int_val):
179 """ 180 @param int_val: A network byte order integer. 181 182 @return: A network address in readable binary form that is equivalent 183 to value represented by a network byte order integer. 184 """ 185 bit_words = [] 186 for word in self.int_to_words(int_val): 187 bits = self.word_to_bits(word) 188 bit_words.append(bits) 189 190 return self.delimiter.join(bit_words)
191
192 - def int_to_words(self, int_val):
193 """ 194 @param int_val: A network byte order integer. 195 196 @return: An integer word sequence that is equivalent to value 197 represented by a network byte order integer. 198 """ 199 if not self.valid_int(int_val): 200 raise Exception('%r is not a valid int/long value supported ' \ 201 'by this address type!' % int_val) 202 203 words = [] 204 for i in range(self.word_count): 205 word = int_val & (2 ** self.word_size - 1) 206 words.append(int(word)) 207 int_val >>= self.word_size 208 209 words.reverse() 210 return tuple(words)
211 212 #------------------------------------------------------------------------- 213 # String methods. 214 #------------------------------------------------------------------------- 215
216 - def valid_str(self, addr):
217 """ 218 @param addr: A network address in string form. 219 220 @return: C{True} if network address in string form is valid for this 221 address type, C{False} otherwise. 222 """ 223 if not isinstance(addr, (str, unicode)): 224 return False 225 226 tokens = addr.split(self.delimiter) 227 if len(tokens) != self.word_count: 228 return False 229 230 try: 231 for token in tokens: 232 int_val = int(token, self.word_base) 233 if not self.min_word <= int_val <= self.max_word: 234 return False 235 except TypeError: 236 return False 237 except ValueError: 238 return False 239 return True
240
241 - def str_to_int(self, addr):
242 """ 243 @param addr: A network address in string form. 244 245 @return: A network byte order integer that is equivalent to value 246 represented by network address in string form. 247 """ 248 words = self.str_to_words(addr) 249 return self.words_to_int(words)
250
251 - def str_to_bits(self, addr):
252 """ 253 @param addr: A network address in string form. 254 255 @return: A network address in readable binary form that is equivalent 256 to value represented by network address in string form. 257 """ 258 words = self.str_to_words(addr) 259 return self.words_to_bits(words)
260
261 - def str_to_words(self, addr):
262 """ 263 @param addr: A network address in string form. 264 265 @return: An integer word sequence that is equivalent in value to the 266 network address in string form. 267 """ 268 if not self.valid_str(addr): 269 raise Exception('%r is not a recognised string representation' \ 270 ' of this address type!' % addr) 271 272 words = addr.split(self.delimiter) 273 return tuple([ int(word, self.word_base) for word in words ])
274 275 #------------------------------------------------------------------------- 276 # Word list methods. 277 #------------------------------------------------------------------------- 278
279 - def valid_words(self, words):
280 """ 281 @param words: A list or tuple containing integer word values. 282 283 @return: C{True} if word sequence is valid for this address type, 284 C{False} otherwise. 285 """ 286 if not isinstance(words, (list, tuple)): 287 return False 288 289 if len(words) != self.word_count: 290 return False 291 292 for i in words: 293 if not isinstance(i, (int, long)): 294 return False 295 296 if not self.min_word <= i <= self.max_word: 297 return False 298 return True
299
300 - def words_to_int(self, words):
301 """ 302 @param words: A list or tuple containing integer word values. 303 304 @return: A network byte order integer that is equivalent to value 305 represented by word sequence. 306 """ 307 if not self.valid_words(words): 308 raise Exception('%r is not a valid word list!' % words) 309 310 # tuples have no reverse() method and reversed() is only available 311 # in Python 2.4. Ugly but necessary. 312 if isinstance(words, tuple): 313 words = list(words) 314 words.reverse() 315 316 int_val = 0 317 for i, num in enumerate(words): 318 word = num 319 word = word << self.word_size * i 320 int_val = int_val | word 321 322 return int_val
323
324 - def words_to_str(self, words):
325 """ 326 @param words: A list or tuple containing integer word values. 327 328 @return: A network address in string form that is equivalent to value 329 represented by word sequence. 330 """ 331 if not self.valid_words(words): 332 raise Exception('%r is not a valid word list!' % words) 333 334 tokens = [self.word_fmt % i for i in words] 335 addr = self.delimiter.join(tokens) 336 return addr
337
338 - def words_to_bits(self, words):
339 """ 340 @param words: A list or tuple containing integer word values. 341 342 @return: A network address in readable binary form that is equivalent 343 to value represented by word sequence. 344 """ 345 if not self.valid_words(words): 346 raise Exception('%r is not a valid word list!' % words) 347 348 bit_words = [] 349 for word in words: 350 bits = self.word_to_bits(word) 351 bit_words.append(bits) 352 353 return self.delimiter.join(bit_words)
354 355 #------------------------------------------------------------------------- 356 # Other methods. 357 #------------------------------------------------------------------------- 358
359 - def word_to_bits(self, int_val):
360 """ 361 @param int_val: An individual integer word value. 362 363 @return: An integer word value for this address type in a fixed width 364 readable binary form. 365 """ 366 bits = [] 367 368 while int_val: 369 bits.append(_BYTES_TO_BITS[int_val&255]) 370 int_val >>= 8 371 372 bits.reverse() 373 bit_str = ''.join(bits) or '0'*self.word_size 374 return ('0'*self.word_size+bit_str)[-self.word_size:]
375
376 - def description(self):
377 """ 378 @return: String detailing setup of this L{AddrStrategy} instance. 379 Useful for debugging. 380 """ 381 tokens = [] 382 for k in sorted(self.__dict__): 383 v = self.__dict__[k] 384 if isinstance(v, bool): 385 tokens.append("%s: %r" % (k, v)) 386 elif isinstance(v, (int, long)): 387 tokens.append( 388 "%s: %r (%s)" % (k, v, hex(v).rstrip('L').lower())) 389 else: 390 tokens.append("%s: %r" % (k, v)) 391 return "\n".join(tokens)
392 393 #-----------------------------------------------------------------------------
394 -class IPv4Strategy(AddrStrategy):
395 """ 396 An optimised L{AddrStrategy} for IPv4 addresses. 397 398 It uses C{pack()} and C{unpack()} from the C{struct} module along with the 399 C{inet_ntoa()} and C{inet_aton()} functions from the C{socket} module. 400 This makes it approx. 2.5 times faster than a standard L{AddrStrategy} 401 configured for IPv4. 402 403 However, keep in mind that these modules might not be available everywhere 404 that Python itself is. Runtimes such as Google App Engine gut the 405 C{socket} module. C{struct} is also limited to processing 32-bit integers 406 which is fine for IPv4 but isn't suitable for IPv6. 407 """
408 - def __init__(self):
409 """Constructor.""" 410 super(self.__class__, self).__init__(width=32, word_size=8, 411 word_fmt='%d', delimiter='.', addr_type=AT_INET, hex_words=False)
412
413 - def str_to_int(self, addr):
414 """ 415 @param addr: An IPv4 dotted decimal address in string form. 416 417 @return: A network byte order integer that is equivalent to value 418 represented by the IPv4 dotted decimal address string. 419 """ 420 if not self.valid_str(addr): 421 raise Exception('%r is not a valid IPv4 dotted decimal' \ 422 ' address string.!' % addr) 423 return _struct.unpack('>I', _socket.inet_aton(addr))[0]
424
425 - def int_to_str(self, int_val):
426 """ 427 @param int_val: A network byte order integer. 428 429 @return: An IPv4 dotted decimal address string that is equivalent to 430 value represented by a 32 bit integer in network byte order. 431 """ 432 if not self.valid_int(int_val): 433 raise Exception('%r is not a valid 32-bit int or long!' % int_val) 434 return _socket.inet_ntoa(_struct.pack('>I', int_val))
435
436 - def int_to_words(self, int_val):
437 """ 438 @param int_val: A network byte order integer. 439 440 @return: An integer word (octet) sequence that is equivalent to value 441 represented by network byte order integer. 442 """ 443 if not self.valid_int(int_val): 444 raise Exception('%r is not a valid int/long value supported ' \ 445 'by this address type!' % int_val) 446 return _struct.unpack('4B', _struct.pack('>I', int_val))
447
448 - def words_to_int(self, octets):
449 """ 450 @param octets: A list or tuple containing integer octets. 451 452 @return: A network byte order integer that is equivalent to value 453 represented by word (octet) sequence. 454 """ 455 if not self.valid_words(octets): 456 raise Exception('%r is not a valid octet list for an IPv4 ' \ 457 'address!' % octets) 458 return _struct.unpack('>I', _struct.pack('4B', *octets))[0]
459
460 - def int_to_arpa(self, int_val):
461 """ 462 @param int_val: A network byte order integer. 463 464 @return: The reverse DNS lookup for an IPv4 address in network byte 465 order integer form. 466 """ 467 words = ["%d" % i for i in self.int_to_words(int_val)] 468 words.reverse() 469 words.extend(['in-addr', 'arpa']) 470 return '.'.join(words)
471 472 #-----------------------------------------------------------------------------
473 -class IPv6Strategy(AddrStrategy):
474 """ 475 Implements the operations that can be performed on an Internet Protocol 476 version 6 network address in accordance with RFC 4291. 477 478 NB - This class would benefit greatly from access to inet_pton/inet_ntop() 479 function calls in Python's socket module. Sadly, they aren't available so 480 we'll have to put up with the pure-Python implementation here (for now at 481 least). 482 """
483 - def __init__(self):
484 """Constructor.""" 485 super(self.__class__, self).__init__(addr_type=AT_INET6, 486 width=128, word_size=16, word_fmt='%x', delimiter=':')
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 #TODO: Reduce the length of this method ... 496 if not isinstance(addr, (str, unicode)): 497 return False 498 499 if '::' in addr: 500 # IPv6 compact mode. 501 try: 502 prefix, suffix = addr.split('::') 503 except ValueError: 504 return False 505 506 l_prefix = [] 507 l_suffix = [] 508 509 if prefix != '': 510 l_prefix = prefix.split(':') 511 512 if suffix != '': 513 l_suffix = suffix.split(':') 514 515 # IPv6 compact IPv4 compatibility mode. 516 if len(l_suffix) and '.' in l_suffix[-1]: 517 ipv4_str = l_suffix[-1] 518 if ST_IPV4.valid_str(ipv4_str): 519 ipv4_int = ST_IPV4.str_to_int(ipv4_str) 520 ipv4_words = ST_IPV4.int_to_words(ipv4_int) 521 l_suffix.pop() 522 l_suffix.append( 523 ''.join(["%x" % i for i in ipv4_words[0:2]])) 524 l_suffix.append( 525 ''.join(["%x" % i for i in ipv4_words[2:]])) 526 527 token_count = len(l_prefix) + len(l_suffix) 528 529 if not 0 <= token_count <= self.word_count - 1: 530 return False 531 532 try: 533 for token in l_prefix + l_suffix: 534 word = int(token, 16) 535 if not self.min_word <= word <= self.max_word: 536 return False 537 except ValueError: 538 return False 539 else: 540 # IPv6 verbose mode. 541 if ':' in addr: 542 tokens = addr.split(':') 543 544 if '.' in addr: 545 ipv6_prefix = tokens[:-1] 546 if ipv6_prefix[:-1] != ['0', '0', '0', '0', '0']: 547 return False 548 if ipv6_prefix[-1].lower() not in ('0', 'ffff'): 549 return False 550 # IPv6 verbose IPv4 compatibility mode. 551 if len(tokens) != (self.word_count - 1): 552 return False 553 ipv4_str = tokens[-1] 554 if ST_IPV4.valid_str(ipv4_str): 555 ipv4_int = ST_IPV4.str_to_int(ipv4_str) 556 ipv4_words = ST_IPV4.int_to_words(ipv4_int) 557 tokens.pop() 558 tokens.append( 559 ''.join(["%x" % i for i in ipv4_words[0:2]])) 560 tokens.append( 561 ''.join(["%x" % i for i in ipv4_words[2:]])) 562 else: 563 # IPv6 verbose mode. 564 if len(tokens) != self.word_count: 565 return False 566 try: 567 for token in tokens: 568 word = int(token, 16) 569 if not self.min_word <= word <= self.max_word: 570 return False 571 except ValueError: 572 return False 573 else: 574 return False 575 576 return True
577
578 - def str_to_int(self, addr):
579 """ 580 @param addr: An IPv6 address in string form. 581 582 @return: The equivalent network byte order integer for a given IPv6 583 address. 584 """ 585 if not self.valid_str(addr): 586 raise Exception("'%s' is an invalid IPv6 address!" % addr) 587 588 values = [] 589 590 if addr == '::': 591 # Unspecified address. 592 return 0 593 elif '::' in addr: 594 # Abbreviated form IPv6 address. 595 prefix, suffix = addr.split('::') 596 597 if prefix == '': 598 l_prefix = ['0'] 599 else: 600 l_prefix = prefix.split(':') 601 602 if suffix == '': 603 l_suffix = ['0'] 604 else: 605 l_suffix = suffix.split(':') 606 607 # Check for IPv4 compatibility address form. 608 if len(l_suffix) and '.' in l_suffix[-1]: 609 if len(l_suffix) > 2: 610 return False 611 if len(l_suffix) == 2 and l_suffix[0].lower() != 'ffff': 612 return False 613 614 ipv4_str = l_suffix[-1] 615 if ST_IPV4.valid_str(ipv4_str): 616 ipv4_int = ST_IPV4.str_to_int(ipv4_str) 617 ipv4_words = ST_IPV4.int_to_words(ipv4_int) 618 l_suffix.pop() 619 l_suffix.append( 620 ''.join(["%x" % i for i in ipv4_words[0:2]])) 621 l_suffix.append( 622 ''.join(["%x" % i for i in ipv4_words[2:]])) 623 624 gap_size = 8 - ( len(l_prefix) + len(l_suffix) ) 625 626 values = ["%04x" % int(i, 16) for i in l_prefix] \ 627 + ['0000' for i in range(gap_size)] \ 628 + ["%04x" % int(i, 16) for i in l_suffix] 629 else: 630 # Verbose form IPv6 address. 631 if '.' in addr: 632 # IPv4 compatiblility mode. 633 tokens = addr.split(':') 634 ipv4_str = tokens[-1] 635 if ST_IPV4.valid_str(ipv4_str): 636 ipv4_int = ST_IPV4.str_to_int(ipv4_str) 637 ipv4_words = ST_IPV4.int_to_words(ipv4_int) 638 tokens.pop() 639 tokens.append(''.join(["%x" % i for i in ipv4_words[0:2]])) 640 tokens.append(''.join(["%x" % i for i in ipv4_words[2:]])) 641 642 values = ["%04x" % int(i, 16) for i in tokens] 643 else: 644 # non IPv4 compatiblility mode. 645 values = ["%04x" % int(i, 16) for i in addr.split(':')] 646 647 value = int(''.join(values), 16) 648 649 return value
650
651 - def int_to_str(self, int_val, compact=True, word_fmt=None):
652 """ 653 @param int_val: A network byte order integer. 654 655 @param compact: (optional) A boolean flag indicating if compact 656 formatting should be used. If True, this method uses the '::' 657 string to represent the first adjacent group of words with a value 658 of zero. Default: True 659 660 @param word_fmt: (optional) The Python format string used to override 661 formatting for each word. 662 663 @return: The IPv6 string form equal to the network byte order integer 664 value provided. 665 """ 666 # Use basic parent class implementation if compact string form is 667 # not required. 668 if not compact: 669 return super(self.__class__, self).int_to_str(int_val) 670 671 the_word_fmt = self.word_fmt 672 if word_fmt is not None: 673 the_word_fmt = word_fmt 674 675 if not self.valid_int(int_val): 676 raise Exception('%r is not a valid int/long value supported ' \ 677 'by this address type!' % int_val) 678 679 tokens = [] 680 for i in range(self.word_count): 681 word = int_val & (2 ** self.word_size - 1) 682 tokens += [the_word_fmt % word] 683 int_val >>= self.word_size 684 685 tokens.reverse() 686 687 # This can probably be optimised. 688 if compact == True: 689 new_tokens = [] 690 compact_start = False 691 compact_end = False 692 for token in tokens: 693 if token == '0': 694 if compact_start == False and compact_end == False: 695 new_tokens += [''] 696 compact_start = True 697 elif compact_start == True and compact_end == False: 698 pass 699 else: 700 new_tokens += ['0'] 701 else: 702 if compact_start == True: 703 compact_end = True 704 new_tokens += [token] 705 706 # Post loop fixups. 707 if len(new_tokens) == 1 and new_tokens[0] == '': 708 new_tokens += ['', ''] 709 elif new_tokens[-1] == '': 710 new_tokens += [''] 711 elif new_tokens[0] == '': 712 new_tokens.insert(0, '') 713 714 tokens = new_tokens 715 716 return ':'.join(tokens)
717
718 - def int_to_arpa(self, int_val):
719 """ 720 @param int_val: A network byte order integer. 721 722 @return: The reverse DNS lookup for an IPv6 address in network byte 723 order integer form. 724 """ 725 addr = self.int_to_str(int_val, word_fmt='%04x') 726 tokens = list(addr.replace(':', '')) 727 tokens.reverse() 728 # We won't support ip6.int here - see RFC 3152 for details. 729 tokens = tokens + ['ip6', 'arpa'] 730 return '.'.join(tokens)
731 732 #-----------------------------------------------------------------------------
733 -class EUI48Strategy(AddrStrategy):
734 """ 735 Implements the operations that can be performed on an IEEE 48-bit EUI 736 (Extended Unique Identifer). For all intents and purposes here, a MAC 737 address. 738 739 Supports most common MAC address formats including Cisco's string format. 740 """
741 - def __init__(self):
742 """Constructor.""" 743 super(self.__class__, self).__init__(addr_type=AT_LINK, width=48, 744 word_size=8, word_fmt='%02x', delimiter='-', to_upper=True)
745
746 - def valid_str(self, addr):
747 """ 748 @param addr: An EUI-48 or MAC address in string form. 749 750 @return: C{True} if MAC address string is valid, C{False} otherwise. 751 """ 752 if not isinstance(addr, (str, unicode)): 753 return False 754 755 try: 756 if '.' in addr: 757 # Cisco style. 758 words = [int("0x%s" % i, 0) for i in addr.split('.')] 759 if len(words) != 3: 760 return False 761 for i in words: 762 if not (0 <= i <= 0xffff): 763 return False 764 else: 765 if '-' in addr: 766 # Windows style. 767 words = [int("0x%s" % i, 0) for i in addr.split('-')] 768 elif ':' in addr: 769 # UNIX style. 770 words = [int("0x%s" % i, 0) for i in addr.split(':')] 771 else: 772 return False 773 if len(words) != 6: 774 return False 775 for i in words: 776 if not (0 <= i <= 0xff): 777 return False 778 except TypeError: 779 return False 780 except ValueError: 781 return False 782 783 return True
784
785 - def str_to_words(self, addr):
786 """ 787 @param addr: An EUI-48 or MAC address in string form. 788 789 Returns an integer word sequence that is equivalent in value to MAC 790 address in string form. 791 """ 792 if not self.valid_str(addr): 793 raise Exception('%r is not a recognised string representation' \ 794 ' of this address type!' % addr) 795 796 if ':' in addr: 797 # UNIX style. 798 words = addr.split(':') 799 return tuple([ int(word, self.word_base) for word in words ]) 800 elif '-' in addr: 801 # Windows style. 802 words = addr.split('-') 803 return tuple([ int(word, self.word_base) for word in words ]) 804 elif '.' in addr: 805 # Cisco style. 806 words = [] 807 for num in addr.split('.'): 808 octets = [] 809 int_val = int(num, 16) 810 for i in range(2): 811 word = int_val & 0xff 812 octets.append(int(word)) 813 int_val >>= 8 814 octets.reverse() 815 words.extend(octets) 816 return tuple(words)
817
818 - def int_to_str(self, int_val, delimiter=None, word_fmt=None, 819 to_upper=True):
820 """ 821 @param int_val: A network byte order integer. 822 823 @param delimiter: (optional) A delimiter string override to be used 824 instead of the default between words in string value returned. 825 826 @param word_fmt: (optional) A Python format string override used to 827 format each word of address instead of the default. 828 829 @return: A MAC address in string form that is equivalent to value 830 represented by a network byte order integer. 831 """ 832 the_delimiter = self.delimiter 833 if delimiter is not None: 834 the_delimiter = delimiter 835 836 the_word_fmt = self.word_fmt 837 if word_fmt is not None: 838 the_word_fmt = word_fmt 839 840 the_to_upper = self.to_upper 841 if to_upper is not True: 842 the_to_upper = to_upper 843 844 words = self.int_to_words(int_val) 845 tokens = [the_word_fmt % i for i in words] 846 addr = the_delimiter.join(tokens) 847 848 if the_to_upper is True: 849 return addr.upper() 850 851 return addr
852 853 #----------------------------------------------------------------------------- 854 # Shared strategy objects for supported address types. 855 #----------------------------------------------------------------------------- 856 857 #----------------------------- 858 # Optimised strategy objects 859 #----------------------------- 860 861 #: A shared strategy object supporting all operations on IPv4 addresses. 862 ST_IPV4 = IPv4Strategy() 863 #: A shared strategy object supporting all operations on IPv6 addresses. 864 ST_IPV6 = IPv6Strategy() 865 #: A shared strategy object supporting all operations on EUI-48 & MAC addresses. 866 ST_EUI48 = EUI48Strategy() 867 868 #---------------------------- 869 # Standard strategy objects 870 #---------------------------- 871 872 #: A shared strategy object supporting all operations on EUI-64 addresses. 873 ST_EUI64 = AddrStrategy(addr_type=AT_EUI64, width=64, word_size=8, 874 word_fmt='%02x', delimiter='-', to_upper=True) 875 876 #----------------------------------------------------------------------------- 877 if __name__ == '__main__': 878 pass 879