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