1
2
3
4
5
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
15
16 try:
17
18
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
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
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
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
90
91
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
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
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
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
154
155
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
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
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
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
223
224
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
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
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
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
286
287
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
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
320
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
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
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
366
367
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
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
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 """
421
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
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 """
452
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
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
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
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
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 """
512 """Constructor."""
513 super(self.__class__, self).__init__(addr_type=AT_INET6,
514 width=128, word_size=16, word_fmt='%x', delimiter=':')
515
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
524 if not isinstance(addr, (str, unicode)):
525 return False
526
527 if '::' in addr:
528
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
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
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
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
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
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
620 return 0
621 elif '::' in addr:
622
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
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
659 if '.' in addr:
660
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
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
695
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
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
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
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
757 tokens = tokens + ['ip6', 'arpa', '']
758 return '.'.join(tokens)
759
760
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 """
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
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
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
795 words = [int("0x%s" % i, 0) for i in addr.split('-')]
796 elif ':' in addr:
797
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
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
826 words = addr.split(':')
827 return tuple([ int(word, self.word_base) for word in words ])
828 elif '-' in addr:
829
830 words = addr.split('-')
831 return tuple([ int(word, self.word_base) for word in words ])
832 elif '.' in addr:
833
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
883
884
885
886 ST_IPV4 = None
887
888
889 if USE_IPV4_OPT is True:
890 ST_IPV4 = IPv4StrategyOpt()
891 else:
892 ST_IPV4 = IPv4StrategyStd()
893
894
895 ST_IPV6 = IPv6Strategy()
896
897 ST_EUI48 = EUI48Strategy()
898
899
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