1
2
3
4
5
6
7 """
8 network address conversion logic, constants and shared strategy objects.
9 """
10 import socket as _socket
11 import struct as _struct
12 import re as _re
13
14 USE_IPV4_OPT=True
15
16 try:
17
18 _socket.inet_aton('255.255.255.255')
19 except:
20 USE_IPV4_OPT=False
21
22 from netaddr import BIG_ENDIAN_PLATFORM, AT_UNSPEC, AT_INET, AT_INET6, \
23 AT_LINK, AT_EUI64, AT_NAMES, AddrFormatError
24
25
27 """
28 Generates a 256 element list of 8-bit binary digit strings. List index is
29 equivalent to the bit string value.
30 """
31 lookup = []
32 bits_per_byte = range(7, -1, -1)
33 for num in range(256):
34 bits = 8*[None]
35 for i in bits_per_byte:
36 bits[i] = '01'[num&1]
37 num >>= 1
38 lookup.append(''.join(bits))
39 return lookup
40
41 _BYTES_TO_BITS = _BYTES_TO_BITS()
42
43
45 """Basic support for common operations performed on each address type"""
46
47
48 STRUCT_FORMATS = {
49 8 : 'B',
50 16 : 'H',
51 32 : 'I',
52 }
53
54 - def __init__(self, width, word_size, word_sep, word_fmt='%x',
55 addr_type=AT_UNSPEC, word_base=16, uppercase=False):
56 """
57 Constructor.
58
59 @param width: size of address in bits.
60 (e.g. 32 - IPv4, 48 - MAC, 128 - IPv6)
61
62 @param word_size: size of each word.
63 (e.g. 8 - octets, 16 - hextets)
64
65 @param word_sep: separator between each word.
66 (e.g. '.' - IPv4, ':' - IPv6, '-' - EUI-48)
67
68 @param word_fmt: format string for each word.
69 (Default: '%x')
70
71 @param addr_type: address type.
72 (Default: AT_UNSPEC)
73
74 @param word_base: number base used to convert each word using int().
75 (Default: 16)
76
77 @param uppercase: uppercase address.
78 (Default: False)
79 """
80
81 self.width = width
82 self.max_int = 2 ** width - 1
83 self.word_size = word_size
84 self.num_words = width / word_size
85 self.max_word = 2 ** word_size - 1
86 self.word_sep = word_sep
87 self.word_fmt = word_fmt
88 self.word_base = word_base
89 self.addr_type = addr_type
90 self.uppercase = uppercase
91
92 try:
93 self.name = AT_NAMES[addr_type]
94 except KeyError:
95 self.name = AT_NAMES[AT_UNSPEC]
96
98 """@return: executable Python string to recreate equivalent object"""
99 return "%s(%r, %r, %r, %r, %r, %r)" % (self.__class__.__name__,
100 self.width, self.word_size, self.word_sep, self.addr_type,
101 self.word_base, self.uppercase)
102
103
104
105
106
108 """
109 @param bits: A network address in readable binary form.
110
111 @return: C{True} if network address is valid for this address type,
112 C{False} otherwise.
113 """
114 if not isinstance(bits, (str, unicode)):
115 return False
116
117 bits = bits.replace(self.word_sep, '')
118
119 if len(bits) != self.width:
120 return False
121
122 try:
123 if 0 <= int(bits, 2) <= self.max_int:
124 return True
125 except ValueError:
126 return False
127 return False
128
130 """
131 @param bits: A network address in readable binary form.
132
133 @return: A network byte order integer that is equivalent to value
134 represented by network address in readable binary form.
135 """
136 if not self.valid_bits(bits):
137 raise ValueError('%r is not a valid binary form string for ' \
138 'address type!' % bits)
139
140 word_bits = bits.split(self.word_sep)
141 if len(word_bits) != self.num_words:
142 raise ValueError('invalid number of words within binary form ' \
143 'string for address type!' % bits)
144
145 words = tuple([int(i, 2) for i in word_bits])
146
147 return self.words_to_int(words)
148
149
150
151
152
154 """
155 @param int_val: A network byte order integer.
156
157 @return: C{True} if network byte order integer falls within the
158 boundaries of this address type, C{False} otherwise.
159 """
160 if not isinstance(int_val, (int, long)):
161 return False
162
163 return 0 <= int_val <= self.max_int
164
166 """
167 @param int_val: A network byte order integer.
168
169 @return: A network address in string form that is equivalent to value
170 represented by a network byte order integer.
171 """
172 words = self.int_to_words(int_val)
173 tokens = [self.word_fmt % i for i in words]
174 addr = self.word_sep.join(tokens)
175
176 if self.uppercase is True:
177 return addr.upper()
178
179 return addr
180
182 """
183 @param int_val: A network byte order integer.
184
185 @return: A network address in readable binary form that is equivalent
186 to value represented by a network byte order integer.
187 """
188 bit_words = []
189
190 for word in self.int_to_words(int_val):
191 bits = []
192 while word:
193 bits.append(_BYTES_TO_BITS[word&255])
194 word >>= 8
195 bits.reverse()
196 bit_str = ''.join(bits) or '0'*self.word_size
197 bits = ('0'*self.word_size+bit_str)[-self.word_size:]
198 bit_words.append(bits)
199
200 return self.word_sep.join(bit_words)
201
203 """
204 @param int_val: A network byte order integer.
205
206 @return: A network address in standard binary representation format
207 that is equivalent to integer address value. Essentially a back
208 port of the bin() builtin in Python 2.6.x and higher.
209 """
210 bit_words = []
211
212 for word in self.int_to_words(int_val):
213 bits = []
214 while word:
215 bits.append(_BYTES_TO_BITS[word&255])
216 word >>= 8
217 bits.reverse()
218 bit_str = ''.join(bits) or '0'*self.word_size
219 bits = ('0'*self.word_size+bit_str)[-self.word_size:]
220 bit_words.append(bits)
221
222 return '0b' + ''.join(bit_words)
223
224 - def int_to_words(self, int_val, num_words=None, word_size=None):
225 """
226 @param int_val: A network byte order integer to be split.
227
228 @param num_words: (optional) number of words expected in return value
229 tuple. Uses address type default if not specified.
230
231 @param word_size: (optional) size/width of individual words (in bits).
232 Uses address type default if not specified.
233 """
234 if not self.valid_int(int_val):
235 raise IndexError('integer %r is out of bounds!' % hex(int_val))
236
237
238 if num_words is None:
239 num_words = self.num_words
240 if word_size is None:
241 word_size = self.word_size
242
243 max_word_size = 2 ** word_size - 1
244
245 words = []
246 for _ in range(num_words):
247 word = int_val & max_word_size
248 words.append(int(word))
249 int_val >>= word_size
250 words.reverse()
251
252 return tuple(words)
253
255 """
256 @param int_val: the integer to be packed.
257
258 @return: a packed string that is equivalent to value represented by a
259 network byte order integer.
260 """
261
262 words = self.int_to_words(int_val, self.num_words, self.word_size)
263
264 try:
265 fmt = '>%d%s' % (self.num_words, AddrStrategy.STRUCT_FORMATS[
266 self.word_size])
267 except KeyError:
268 raise ValueError('unsupported word size: %d!' % self.word_size)
269
270 return _struct.pack(fmt, *words)
271
272
273
274
275
276
278 """
279 @param packed_int: a packed string containing an unsigned integer.
280 Network byte order is assumed.
281
282 @return: A network byte order integer that is equivalent to value
283 of network address represented by packed binary string.
284 """
285 try:
286 fmt = '>%d%s' % (self.num_words, AddrStrategy.STRUCT_FORMATS[
287 self.word_size])
288 except KeyError:
289 raise ValueError('unsupported word size: %d!' % self.word_size)
290
291 words = list(_struct.unpack(fmt, packed_int))
292 words.reverse()
293
294 int_val = 0
295 for i, num in enumerate(words):
296 word = num
297 word = word << self.word_size * i
298 int_val = int_val | word
299
300 return int_val
301
302
303
304
305
307 """
308 @param addr: A network address in string form.
309
310 @return: C{True} if network address in string form is valid for this
311 address type, C{False} otherwise.
312 """
313 if not isinstance(addr, (str, unicode)):
314 return False
315
316 tokens = addr.split(self.word_sep)
317 if len(tokens) != self.num_words:
318 return False
319
320 try:
321 for token in tokens:
322 if not 0 <= int(token, self.word_base) <= \
323 self.max_word:
324 return False
325 except TypeError:
326 return False
327 except ValueError:
328 return False
329 return True
330
332 """
333 @param addr: A network address in string form.
334
335 @return: A network byte order integer that is equivalent to value
336 represented by network address in string form.
337 """
338 if not self.valid_str(addr):
339 raise ValueError('%r is not a recognised string representation' \
340 ' of this address type!' % addr)
341
342 tokens = addr.split(self.word_sep)
343 words = [ int(token, self.word_base) for token in tokens ]
344
345 return self.words_to_int(words)
346
347
348
349
350
352 """
353 @param words: A sequence containing integer word values.
354
355 @return: C{True} if word sequence is valid for this address type,
356 C{False} otherwise.
357 """
358 if not hasattr(words, '__iter__'):
359 return False
360
361 if len(words) != self.num_words:
362 return False
363
364 for i in words:
365 if not isinstance(i, (int, long)):
366 return False
367
368 if not 0 <= i <= self.max_word:
369 return False
370 return True
371
373 """
374 @param words: A list or tuple containing integer word values.
375
376 @return: A network byte order integer that is equivalent to value
377 represented by word sequence.
378 """
379 if not self.valid_words(words):
380 raise ValueError('%r is not a valid word list!' % words)
381
382
383
384 if isinstance(words, tuple):
385 words = list(words)
386 words.reverse()
387
388 int_val = 0
389 for i, num in enumerate(words):
390 word = num
391 word = word << self.word_size * i
392 int_val = int_val | word
393
394 return int_val
395
396
398 """
399 A 'safe' L{AddrStrategy} for IPv4 addresses. Unlike L{IPv4StrategyOpt}.
400
401 It contains all methods related to IPv4 addresses that the optimised
402 version has, without the reliance on the socket or struct modules. There
403 are several cases where the use of this class are preferable when either
404 the modules mentioned do not exist on certain Python implementations or
405 contain bugs like the infamous inet_aton('255.255.255.254') bug.
406
407 All methods shared between the optimised class and this one should be
408 defined here.
409 """
414
416 """
417 @param int_val: A network byte order integer.
418
419 @return: The reverse DNS lookup for an IPv4 address in network byte
420 order integer form.
421 """
422 words = ["%d" % i for i in self.int_to_words(int_val)]
423 words.reverse()
424 words.extend(['in-addr', 'arpa', ''])
425 return '.'.join(words)
426
427
429 """
430 An optimised L{AddrStrategy} for IPv4 addresses.
431
432 It uses C{pack()} and C{unpack()} from the C{struct} module along with the
433 C{inet_ntoa()} and C{inet_aton()} from the C{socket} module great improve
434 the speed of certain operations (approx. 2.5 times faster than a standard
435 L{AddrStrategy} configured for IPv4).
436
437 However, keep in mind that these modules might not be available everywhere
438 that Python itself is. Runtimes such as Google App Engine gut the
439 C{socket} module. C{struct} is also limited to processing 32-bit integers
440 which is fine for IPv4 but isn't suitable for IPv6.
441 """
445
447 """
448 @param addr: An IP address in presentation (string) format.
449
450 @return: C{True} if network address in string form is valid for this
451 address type, C{False} otherwise.
452 """
453 try:
454
455
456
457
458
459 _socket.inet_aton(addr)
460 except _socket.error:
461 return False
462 except TypeError:
463 return False
464 return True
465
467 """
468 @param addr: An IPv4 dotted decimal address in string form.
469
470 @return: A network byte order integer that is equivalent to value
471 represented by the IPv4 dotted decimal address string.
472 """
473 if not self.valid_str(addr):
474 raise ValueError('%r is not a valid IPv4 address string!' \
475 % addr)
476 return _struct.unpack('>I', _socket.inet_aton(addr))[0]
477
479 """
480 @param int_val: A network byte order integer.
481
482 @return: An IPv4 dotted decimal address string that is equivalent to
483 value represented by a 32 bit integer in network byte order.
484 """
485 if not self.valid_int(int_val):
486 raise ValueError('%r is not a valid 32-bit integer!' % int_val)
487 return _socket.inet_ntoa(_struct.pack('>I', int_val))
488
489 - def int_to_words(self, int_val, num_words=None, word_size=None):
490 """
491 @param int_val: A network byte order integer.
492
493 @param num_words: (unused) *** interface compatibility only ***
494
495 @param word_size: (unused) *** interface compatibility only ***
496
497 @return: An integer word (octet) sequence that is equivalent to value
498 represented by network byte order integer.
499 """
500 if not self.valid_int(int_val):
501 raise ValueError('%r is not a valid integer value supported ' \
502 'by this address type!' % int_val)
503 return _struct.unpack('4B', _struct.pack('>I', int_val))
504
506 """
507 @param octets: A list or tuple containing integer octets.
508
509 @return: A network byte order integer that is equivalent to value
510 represented by word (octet) sequence.
511 """
512 if not self.valid_words(octets):
513 raise ValueError('%r is not a valid octet list for an IPv4 ' \
514 'address!' % octets)
515 return _struct.unpack('>I', _struct.pack('4B', *octets))[0]
516
517
519 """
520 Implements the operations that can be performed on an Internet Protocol
521 version 6 network address in accordance with RFC 4291.
522
523 NB - This class would benefit greatly from access to inet_pton/inet_ntop()
524 function calls in Python's socket module. Sadly, they aren't available so
525 we'll have to put up with the pure-Python implementation here (for now at
526 least).
527 """
529 """Constructor."""
530 super(self.__class__, self).__init__(addr_type=AT_INET6,
531 width=128, word_size=16, word_fmt='%x', word_sep=':')
532
534 """
535 @param addr: An IPv6 address in string form.
536
537 @return: C{True} if IPv6 network address string is valid, C{False}
538 otherwise.
539 """
540
541 if not isinstance(addr, (str, unicode)):
542 return False
543
544 if '::' in addr:
545
546 try:
547 prefix, suffix = addr.split('::')
548 except ValueError:
549 return False
550
551 l_prefix = []
552 l_suffix = []
553
554 if prefix != '':
555 l_prefix = prefix.split(':')
556
557 if suffix != '':
558 l_suffix = suffix.split(':')
559
560
561 if len(l_suffix) and '.' in l_suffix[-1]:
562 ipv4_str = l_suffix[-1]
563 if ST_IPV4.valid_str(ipv4_str):
564 ipv4_int = ST_IPV4.str_to_int(ipv4_str)
565 ipv4_words = ST_IPV4.int_to_words(ipv4_int)
566 l_suffix.pop()
567 l_suffix.append(
568 ''.join(["%.2x" % i for i in ipv4_words[0:2]]))
569 l_suffix.append(
570 ''.join(["%.2x" % i for i in ipv4_words[2:4]]))
571
572 token_count = len(l_prefix) + len(l_suffix)
573
574 if not 0 <= token_count <= self.num_words - 1:
575 return False
576
577 try:
578 for token in l_prefix + l_suffix:
579 word = int(token, 16)
580 if not 0 <= word <= self.max_word:
581 return False
582 except ValueError:
583 return False
584 else:
585
586 if ':' in addr:
587 tokens = addr.split(':')
588
589 if '.' in addr:
590 ipv6_prefix = tokens[:-1]
591 if ipv6_prefix[:-1] != ['0', '0', '0', '0', '0']:
592 return False
593 if ipv6_prefix[-1].lower() not in ('0', 'ffff'):
594 return False
595
596 if len(tokens) != (self.num_words - 1):
597 return False
598 ipv4_str = tokens[-1]
599 if ST_IPV4.valid_str(ipv4_str):
600 ipv4_int = ST_IPV4.str_to_int(ipv4_str)
601 ipv4_words = ST_IPV4.int_to_words(ipv4_int)
602 tokens.pop()
603 tokens.append(
604 ''.join(["%.2x" % i for i in ipv4_words[0:2]]))
605 tokens.append(
606 ''.join(["%.2x" % i for i in ipv4_words[2:4]]))
607 else:
608
609 if len(tokens) != self.num_words:
610 return False
611 try:
612 for token in tokens:
613 word = int(token, 16)
614 if not 0 <= word <= self.max_word:
615 return False
616 except ValueError:
617 return False
618 else:
619 return False
620
621 return True
622
624 """
625 @param addr: An IPv6 address in string form.
626
627 @return: The equivalent network byte order integer for a given IPv6
628 address.
629 """
630 if not self.valid_str(addr):
631 raise ValueError("'%s' is an invalid IPv6 address!" % addr)
632
633 values = []
634
635 if addr == '::':
636
637 return 0
638 elif '::' in addr:
639
640 prefix, suffix = addr.split('::')
641
642 if prefix == '':
643 l_prefix = ['0']
644 else:
645 l_prefix = prefix.split(':')
646
647 if suffix == '':
648 l_suffix = ['0']
649 else:
650 l_suffix = suffix.split(':')
651
652
653 if len(l_suffix) and '.' in l_suffix[-1]:
654 if len(l_suffix) > 2:
655 return False
656 if len(l_suffix) == 2 and l_suffix[0].lower() != 'ffff':
657 return False
658
659 ipv4_str = l_suffix[-1]
660 if ST_IPV4.valid_str(ipv4_str):
661 ipv4_int = ST_IPV4.str_to_int(ipv4_str)
662 ipv4_words = ST_IPV4.int_to_words(ipv4_int)
663 l_suffix.pop()
664 l_suffix.append(
665 ''.join(["%.2x" % i for i in ipv4_words[0:2]]))
666 l_suffix.append(
667 ''.join(["%.2x" % i for i in ipv4_words[2:4]]))
668
669 gap_size = 8 - ( len(l_prefix) + len(l_suffix) )
670
671 values = ["%04x" % int(i, 16) for i in l_prefix] \
672 + ['0000' for i in range(gap_size)] \
673 + ["%04x" % int(i, 16) for i in l_suffix]
674 else:
675
676 if '.' in addr:
677
678 tokens = addr.split(':')
679 ipv4_str = tokens[-1]
680 if ST_IPV4.valid_str(ipv4_str):
681 ipv4_int = ST_IPV4.str_to_int(ipv4_str)
682 ipv4_words = ST_IPV4.int_to_words(ipv4_int)
683 tokens.pop()
684 tokens.append(''.join(["%.2x" % i for i in ipv4_words[0:2]]))
685 tokens.append(''.join(["%.2x" % i for i in ipv4_words[2:4]]))
686
687 values = ["%04x" % int(i, 16) for i in tokens]
688 else:
689
690 values = ["%04x" % int(i, 16) for i in addr.split(':')]
691
692 value = int(''.join(values), 16)
693
694 return value
695
696 - def int_to_str(self, int_val, compact=True, word_fmt=None):
697 """
698 @param int_val: A network byte order integer.
699
700 @param compact: (optional) A boolean flag indicating if compact
701 formatting should be used. If True, this method uses the '::'
702 string to represent the first adjacent group of words with a value
703 of zero. Default: True
704
705 @param word_fmt: (optional) The Python format string used to override
706 formatting for each word.
707
708 @return: The IPv6 string form equal to the network byte order integer
709 value provided.
710 """
711
712
713 if not compact:
714 return super(self.__class__, self).int_to_str(int_val)
715
716 _word_fmt = self.word_fmt
717 if word_fmt is not None:
718 _word_fmt = word_fmt
719
720 if not self.valid_int(int_val):
721 raise ValueError('%r is not a valid integer value supported ' \
722 'by this address type!' % int_val)
723
724 tokens = []
725 for i in range(self.num_words):
726 word = int_val & (2 ** self.word_size - 1)
727 tokens += [_word_fmt % word]
728 int_val >>= self.word_size
729
730 tokens.reverse()
731
732 if compact == True:
733 new_tokens = []
734
735 positions = []
736 within_run = False
737 start_index = None
738 num_tokens = 0
739
740
741 for idx, token in enumerate(tokens):
742 if token == '0':
743 within_run = True
744 if start_index is None:
745 start_index = idx
746 num_tokens += 1
747 else:
748 if num_tokens > 1:
749 positions.append((num_tokens, start_index))
750 within_run = False
751 start_index = None
752 num_tokens = 0
753
754 new_tokens.append(token)
755
756
757 if num_tokens > 1:
758 positions.append((num_tokens, start_index))
759
760
761 if len(positions) != 0:
762
763 positions.sort(lambda x, y: cmp(x[1], y[1]))
764 best_position = positions[0]
765 for position in positions:
766 if position[0] > best_position[0]:
767 best_position = position
768
769 (length, start_idx) = best_position
770 new_tokens = new_tokens[0:start_idx] + [''] + \
771 new_tokens[start_idx+length:]
772
773
774 if new_tokens[0] == '':
775 new_tokens.insert(0, '')
776
777 if new_tokens[-1] == '':
778 new_tokens.append('')
779
780 tokens = new_tokens
781
782 return self.word_sep.join(tokens)
783
785 """
786 @param int_val: A network byte order integer.
787
788 @return: The reverse DNS lookup for an IPv6 address in network byte
789 order integer form.
790 """
791 addr = self.int_to_str(int_val, word_fmt='%04x')
792 tokens = list(addr.replace(':', ''))
793 tokens.reverse()
794
795 tokens = tokens + ['ip6', 'arpa', '']
796 return '.'.join(tokens)
797
798
800 """
801 Implements the operations that can be performed on an IEEE 48-bit EUI
802 (Extended Unique Identifer) a.k.a. a MAC (Media Access Control) layer 2
803 address.
804
805 Supports all common (and some less common MAC string formats including
806 Cisco's 'triple hextet' format and also bare MACs that contain no
807 delimiters.
808 """
809
810 RE_MAC_FORMATS = (
811
812 '^' + ':'.join(['([0-9A-F]{1,2})'] * 6) + '$',
813 '^' + '-'.join(['([0-9A-F]{1,2})'] * 6) + '$',
814
815
816 '^' + ':'.join(['([0-9A-F]{1,4})'] * 3) + '$',
817 '^' + '-'.join(['([0-9A-F]{1,4})'] * 3) + '$',
818
819
820 '^' + '-'.join(['([0-9A-F]{5,6})'] * 2) + '$',
821 '^' + ':'.join(['([0-9A-F]{5,6})'] * 2) + '$',
822
823
824 '^(' + ''.join(['[0-9A-F]'] * 12) + ')$',
825 '^(' + ''.join(['[0-9A-F]'] * 11) + ')$',
826 )
827
828
829 RE_MAC_FORMATS = [_re.compile(_, _re.IGNORECASE) for _ in RE_MAC_FORMATS]
830
831 - def __init__(self, word_fmt='%02x', word_sep='-', uppercase=True):
832 """
833 Constructor.
834
835 @param word_sep: separator between each word.
836 (Default: '-')
837
838 @param word_fmt: format string for each hextet.
839 (Default: '%02x')
840
841 @param uppercase: return uppercase MAC/EUI-48 addresses.
842 (Default: True)
843 """
844 super(self.__class__, self).__init__(addr_type=AT_LINK, width=48,
845 word_size=8, word_fmt=word_fmt, word_sep=word_sep,
846 uppercase=uppercase)
847
849 """
850 Resets the internal state of this strategy to safe default values.
851 """
852
853 self.width = 48
854 self.max_int = 2 ** self.width - 1
855 self.word_size = 8
856 self.num_words = self.width / self.word_size
857 self.max_word = 2 ** self.word_size - 1
858 self.word_sep = '-'
859 self.word_fmt = '%02x'
860 self.word_base = 16
861 self.addr_type = AT_LINK
862 self.uppercase = True
863
865 """
866 @param addr: An EUI-48 or MAC address in string form.
867
868 @return: C{True} if MAC address string is valid, C{False} otherwise.
869 """
870 if not isinstance(addr, (str, unicode)):
871 return False
872
873 for regexp in EUI48Strategy.RE_MAC_FORMATS:
874 match_result = regexp.findall(addr)
875 if len(match_result) != 0:
876 return True
877 return False
878
880 """
881 @param addr: An EUI-48 or MAC address in string form.
882
883 @return: A network byte order integer that is equivalent to value
884 represented by EUI-48/MAC string address.
885 """
886 words = []
887 if isinstance(addr, (str, unicode)):
888 found_match = False
889 for regexp in EUI48Strategy.RE_MAC_FORMATS:
890 match_result = regexp.findall(addr)
891 if len(match_result) != 0:
892 found_match = True
893 if isinstance(match_result[0], tuple):
894 words = match_result[0]
895 else:
896 words = (match_result[0],)
897 break
898 if not found_match:
899 raise AddrFormatError('%r is not a supported MAC format!' \
900 % addr)
901 else:
902 raise TypeError('%r is not str() or unicode()!' % addr)
903
904 int_val = None
905
906 if len(words) == 6:
907
908 int_val = int(''.join(['%02x' % int(w, 16) for w in words]), 16)
909 elif len(words) == 3:
910
911 int_val = int(''.join(['%04x' % int(w, 16) for w in words]), 16)
912 elif len(words) == 2:
913
914 int_val = int(''.join(['%06x' % int(w, 16) for w in words]), 16)
915 elif len(words) == 1:
916
917 int_val = int('%012x' % int(words[0], 16), 16)
918 else:
919 raise AddrFormatError('unexpected word count in MAC address %r!' \
920 % addr)
921
922 return int_val
923
924 - def int_to_str(self, int_val, word_sep=None, word_fmt=None):
925 """
926 @param int_val: A network byte order integer.
927
928 @param word_sep: (optional) The separator used between words in an
929 address string.
930
931 @param word_fmt: (optional) A Python format string used to format
932 each word of address.
933
934 @return: A MAC address in string form that is equivalent to value
935 represented by a network byte order integer.
936 """
937 _word_sep = self.word_sep
938 if word_sep is not None:
939 _word_sep = word_sep
940
941 _word_fmt = self.word_fmt
942 if word_fmt is not None:
943 _word_fmt = word_fmt
944
945 words = self.int_to_words(int_val)
946 tokens = [_word_fmt % i for i in words]
947 addr = _word_sep.join(tokens)
948
949 if self.uppercase:
950 return addr.upper()
951 else:
952 return addr.lower()
953
954
955
956
957
958
959 ST_IPV4 = None
960
961
962 if USE_IPV4_OPT is True:
963 ST_IPV4 = IPv4StrategyOpt()
964 else:
965 ST_IPV4 = IPv4StrategyStd()
966
967
968 ST_IPV6 = IPv6Strategy()
969
970 ST_EUI48 = EUI48Strategy()
971
972
973 ST_EUI64 = AddrStrategy(addr_type=AT_EUI64, width=64, word_size=8, \
974 word_fmt='%02x', word_sep='-', uppercase=True)
975
976
977 if __name__ == '__main__':
978 pass
979