Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(3)

Delta Between Two Patch Sets: ipaddr.py

Issue 67107: collapse_address_list is too slow SVN Base: http://ipaddr-py.googlecode.com/svn/trunk/
Left Patch Set: uncommented new code Created 6 months, 1 week ago
Right Patch Set: Fixes for comments on Patch Set 6 Created 3 months, 2 weeks ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # 2 #
3 # Copyright 2007 Google Inc. 3 # Copyright 2007 Google Inc.
4 # Licensed to PSF under a Contributor Agreement. 4 # Licensed to PSF under a Contributor Agreement.
5 # 5 #
6 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License. 7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at 8 # You may obtain a copy of the License at
9 # 9 #
10 # http://www.apache.org/licenses/LICENSE-2.0 10 # http://www.apache.org/licenses/LICENSE-2.0
11 # 11 #
12 # Unless required by applicable law or agreed to in writing, software 12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS, 13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15 # implied. See the License for the specific language governing 15 # implied. See the License for the specific language governing
16 # permissions and limitations under the License. 16 # permissions and limitations under the License.
17 17
18 """An IPv4/IPv6 manipulation library in Python. 18 """An IPv4/IPv6 manipulation library in Python.
19 19
20 This library is used to create/poke/manipulate IPv4 and IPv6 addresses 20 This library is used to create/poke/manipulate IPv4 and IPv6 addresses
21 and prefixes. 21 and networks.
22 22
23 """ 23 """
24 24
25 __version__ = '1.0.2' 25 __version__ = 'trunk'
26 26
27 import struct 27 import struct
28 28
29 class Error(Exception): 29 class Error(Exception):
30 30
31 """Base class for exceptions.""" 31 """Base class for exceptions."""
32 32
33 33
34 class IPTypeError(Error): 34 class IPTypeError(Error):
35 35
36 """Tried to perform a v4 action on v6 object or vice versa.""" 36 """Tried to perform a v4 action on v6 object or vice versa."""
37 37
38 38
39 class IPAddressExclusionError(Error): 39 class IPAddressExclusionError(Error):
40 40
41 """An Error we should never see occurred in address exclusion.""" 41 """An Error we should never see occurred in address exclusion."""
42 42
43 43
44 class IPv4IpValidationError(Error): 44 class IPAddressIPValidationError(Error):
45 45
46 """Raised when an IPv4 address is invalid.""" 46 """Raised when a single address (v4 or v6) was given a network."""
47 47
48 def __init__(self, ip): 48 def __init__(self, ip):
49 Error.__init__(self) 49 Error.__init__(self)
50 self.ip = ip 50 self._ip = ip
51 51
52 def __str__(self): 52 def __str__(self):
53 return repr(self.ip) + ' is not a valid IPv4 address' 53 return "%s is not a valid address (hint, it's probably a network)" % (
54 54 repr(self._ip))
55
56 class IPv4IpValidationError(Error):
57
58 """Raised when an IPv4 address is invalid."""
59
60 def __init__(self, ip):
61 Error.__init__(self)
62 self._ip = ip
63
64 def __str__(self):
65 return repr(self._ip) + ' is not a valid IPv4 address'
55 66
56 class IPv4NetmaskValidationError(Error): 67 class IPv4NetmaskValidationError(Error):
57 68
58 """Raised when a netmask is invalid.""" 69 """Raised when a netmask is invalid."""
59 70
60 def __init__(self, netmask): 71 def __init__(self, netmask):
61 Error.__init__(self) 72 Error.__init__(self)
62 self.netmask = netmask 73 self.netmask = netmask
63 74
64 def __str__(self): 75 def __str__(self):
65 return repr(self.netmask) + ' is not a valid IPv4 netmask' 76 return repr(self.netmask) + ' is not a valid IPv4 netmask'
66 77
67 class IPRangeError(Error):
68
69 """Raised when an IP address range is invalid."""
70 78
71 class IPv6IpValidationError(Error): 79 class IPv6IpValidationError(Error):
72 80
73 """Raised when an IPv6 address is invalid.""" 81 """Raised when an IPv6 address is invalid."""
74 82
75 def __init__(self, ip): 83 def __init__(self, ip):
76 Error.__init__(self) 84 Error.__init__(self)
77 self.ip = ip 85 self._ip = ip
78 86
79 def __str__(self): 87 def __str__(self):
80 return repr(self.ip) + ' is not a valid IPv6 address' 88 return repr(self._ip) + ' is not a valid IPv6 network'
81 89
82 90
83 class IPv6NetmaskValidationError(Error): 91 class IPv6NetmaskValidationError(Error):
84 92
85 """Raised when an IPv6 netmask is invalid.""" 93 """Raised when an IPv6 netmask is invalid."""
86 94
87 def __init__(self, netmask): 95 def __init__(self, netmask):
88 Error.__init__(self) 96 Error.__init__(self)
89 self.netmask = netmask 97 self.netmask = netmask
90 98
91 def __str__(self): 99 def __str__(self):
92 return repr(self.netmask) + ' is not a valid IPv6 netmask' 100 return repr(self.netmask) + ' is not a valid IPv6 netmask'
93 101
94 102
95 class PrefixlenDiffInvalidError(Error): 103 class PrefixlenDiffInvalidError(Error):
96 104
97 """Raised when Sub/Supernets is called with a bad prefixlen_diff.""" 105 """Raised when Sub/Supernets is called with a bad prefixlen_diff."""
98 106
99 def __init__(self, error_str): 107 def __init__(self, error_str):
100 Error.__init__(self) 108 Error.__init__(self)
101 self.error_str = error_str 109 self.error_str = error_str
102 110
103 111
104 def IP(ipaddr): 112 def IP(address, host=False, version=None):
105 """Take an IP string/int and return an object of the correct type. 113 """Take an IP string/int and return an object of the correct type.
106 114
107 Args: 115 Args:
108 ipaddr: A string or integer, the IP address. Either IPv4 or 116 address: A string or integer, the IP address. Either IPv4 or
109 IPv6 addresses may be supplied; integers less than 2**32 will 117 IPv6 addresses may be supplied; integers less than 2**32 will
110 be considered to be IPv4. 118 be considered to be IPv4.
119 host: A bool indicating that a host rather than the default network
120 object should be created.
121 version: An Integer, if set, don't try to automatically
122 determine what the IP address type is. important for things
123 like IP(1), which could be IPv4 or IPv6.
111 124
112 Returns: 125 Returns:
113 An IPv4 or IPv6 object. 126 An IPv4 or IPv6 object.
114 127
115 Raises: 128 Raises:
116 ValueError: if the string passed isn't either a v4 or a v6 129 ValueError: if the string passed isn't either a v4 or a v6
117 address. 130 address.
118 131
119 """ 132 """
133 if version:
134 if version == 4:
135 return IPv4(address, host=host)
136 elif version == 6:
137 return IPv6(address, host=host)
120 138
121 try: 139 try:
122 return IPv4(ipaddr) 140 return IPv4(address, host=host)
123 except (IPv4IpValidationError, IPv4NetmaskValidationError): 141 except (IPv4IpValidationError, IPv4NetmaskValidationError):
124 pass 142 pass
125 143
126 try: 144 try:
127 return IPv6(ipaddr) 145 return IPv6(address, host=host)
128 except (IPv6IpValidationError, IPv6NetmaskValidationError): 146 except (IPv6IpValidationError, IPv6NetmaskValidationError):
129 pass 147 pass
130 148
131 raise ValueError('%r does not appear to be an IPv4 or IPv6 address' % 149 raise ValueError('%r does not appear to be an IPv4 or IPv6 address' %
132 ipaddr) 150 address)
151
152
153 def IPv4(address, host=False):
154 """Generic IPv4 Factory function..
155
156 Return an IPv4 address or network.
157 """
158 if host:
159 return IPv4Address(address)
160 return IPv4Network(address)
161
162
163 def IPv6(address, host=False):
164 """Generic IPv6 Factory function..
165
166 Return an IPv6 address or network.
167 """
168 if host:
169 return IPv6Address(address)
170 return IPv6Network(address)
133 171
134 172
135 def _find_address_range(addresses): 173 def _find_address_range(addresses):
136 """Find a sequence of addresses.""" 174 """Find a sequence of addresses.
175
176 Args:
177 addresses: a list of IPv4 or IPv6 addresses.
178
179 Returns:
180 A tuple containing the first and last IP addresses in the sequence.
181
182 """
137 first = last = addresses[0] 183 first = last = addresses[0]
138 for ip in addresses[1:]: 184 for ip in addresses[1:]:
139 if ip.ip == last.ip + 1: 185 if ip._ip == last._ip + 1:
140 last = ip 186 last = ip
141 else: 187 else:
142 break 188 break
143 return (first, last) 189 return (first, last)
144 190
145 def _get_prefix_length(number1, number2, bits): 191 def _get_prefix_length(number1, number2, bits):
146 """Get the number of leading bits that are same for two numbers.""" 192 """Get the number of leading bits that are same for two numbers.
193
194 Args:
195 number1: an integer.
196 number2: another integer.
197 bits: the maximum number of bits to compare.
198
199 Returns:
200 The number of leading bits that are the same for two numbers.
201
202 """
147 for i in range(bits): 203 for i in range(bits):
148 if number1 >> i == number2 >> i: 204 if number1 >> i == number2 >> i:
149 return bits - i 205 return bits - i
150 return 0 206 return 0
151 207
152 def _count_righthand_zero_bits(integer, bits): 208 def _count_righthand_zero_bits(number, bits):
153 """Count the number of zero bits on the right hand side.""" 209 """Count the number of zero bits on the right hand side.
154 if integer == 0: 210
211 Args:
212 number: an integer.
213 bits: maximum number of bits to count.
214
215 Returns:
216 The number of zero bits on the right hand side of the number.
217
218 """
219 if number == 0:
155 return bits 220 return bits
156 for i in range(bits): 221 for i in range(bits):
157 if (integer >> i) % 2: 222 if (number >> i) % 2:
158 return i 223 return i
159 224
160 def _highest_one_bit(number):
161 """Find the highest bit set to 1."""
162 value = 0
163 while number > 0:
164 number = number >> 1
165 value += 1
166 return value
167
168 def summarize_address_range(first, last): 225 def summarize_address_range(first, last):
169 """Summarize a network range given the first and last IP addresses.""" 226 """Summarize a network range given the first and last IP addresses.
170 227
228 Example:
229 >>> summarize_address_range(IPv4Address('1.1.1.0'),
230 IPv4Address('1.1.1.130'))
231 [IPv4Network('1.1.1.0/25'), IPv4Network('1.1.1.128/31'),
232 IPv4Network('1.1.1.130/32')]
233
234 Args:
235 first: the first IPv4 or IPv6 address in the range.
236 last: the last IPv4 or IPv6 address in the range.
237
238 Returns:
239 The address range collapsed to a list of IPv4 or IPv6 networks.
240
241 Raise:
242 IPTypeError:
243 If the first and last objects are not IP addresses.
244 If the first and last objects are not the same version.
245 ValueError:
246 If the last object is not greater than the first.
247 If the version is not 4 or 6.
248
249 """
250
251 if not (isinstance(first, BaseIP) and isinstance(last, BaseIP)):
252 raise IPTypeError("first and last must be IP addresses, not networks")
171 if first.version != last.version: 253 if first.version != last.version:
172 raise ValueError("IP addresses must be same version") 254 raise IPTypeError("IP addresses must be same version")
173 if first > last: 255 if first > last:
174 raise ValueError("last IP address must be greater than first") 256 raise ValueError("last IP address must be greater than first")
175 257
176 networks = [] 258 networks = []
177 259
178 if first.version == 4: 260 if first.version == 4:
179 ip = IPv4 261 ip = IPv4Network
180 elif first.version == 6: 262 elif first.version == 6:
181 ip = IPv6 263 ip = IPv6Network
182 else: 264 else:
183 raise ValueError("unknown IP version") 265 raise ValueError("unknown IP version")
184 266
185 try: 267 ip_bits = first._max_prefixlen
186 # shortcut if the range is on a network byte boundary 268 first = first._ip
187 net = ip("%s-%s" % (first.ip_ext, last.ip_ext)) 269 last = last._ip
270 while first <= last:
271 nbits = _count_righthand_zero_bits(first, ip_bits)
272 current = None
273 while nbits >= 0:
274 addend = 2**nbits - 1
275 current = first + addend
276 nbits -= 1
277 if current <= last:
278 break
279 prefix = _get_prefix_length(first, current, ip_bits)
280 net = ip(first)
281 net.prefixlen = prefix
188 networks.append(net) 282 networks.append(net)
189 except IPRangeError: 283 if current == ip._ALL_ONES:
190 ip_bits = first.max_prefixlen 284 break
191 while first <= last: 285 first = current + 1
192 nbits = _count_righthand_zero_bits(first.ip, ip_bits)
193 current = None
194 while True:
195 addend = 2**nbits - 1
196 current = first.ip + addend
197 nbits -= 1
198 if ip(current) <= last:
199 break
200 prefix = _get_prefix_length(first.ip, current, ip_bits)
201 networks.append(ip('%s/%s' % (first.ip_ext, prefix)))
202 first = ip(current + 1)
203 if current == ip._ALL_ONES:
204 break
205 return networks 286 return networks
206 287
207 def _collapse_address_list_recursive(addresses): 288 def _collapse_address_list_recursive(addresses):
208 """Loops through the addresses, collapsing concurrent netblocks. 289 """Loops through the addresses, collapsing concurrent netblocks.
209 290
210 Example: 291 Example:
211 292
212 ip1 = IPv4('1.1.0.0/24') 293 ip1 = IPv4('1.1.0.0/24')
213 ip2 = IPv4('1.1.1.0/24') 294 ip2 = IPv4('1.1.1.0/24')
214 ip3 = IPv4('1.1.2.0/24') 295 ip3 = IPv4('1.1.2.0/24')
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 collapse_address_list([IPv4('1.1.0.0/24'), IPv4('1.1.1.0/24')]) -> 338 collapse_address_list([IPv4('1.1.0.0/24'), IPv4('1.1.1.0/24')]) ->
258 [IPv4('1.1.0.0/23')] 339 [IPv4('1.1.0.0/23')]
259 340
260 Args: 341 Args:
261 addresses: A list of IPv4 or IPv6 objects. 342 addresses: A list of IPv4 or IPv6 objects.
262 343
263 Returns: 344 Returns:
264 A list of IPv4 or IPv6 objects depending on what we were passed. 345 A list of IPv4 or IPv6 objects depending on what we were passed.
265 346
266 """ 347 """
267 _addresses = []
268 i = 0 348 i = 0
269 ip_bits = addresses[0].max_prefixlen 349 addrs = []
270 # filter out IP addresses, dedup, and sort 350 ips = []
271 addrs = sorted(set([ip for ip in addresses if ip.prefixlen == ip_bits]), 351 nets = []
272 key=BaseIP._get_networks_key) 352 # split IP addresses and networks
273 nets = [ip for ip in addresses if ip.prefixlen < ip_bits] 353 for ip in addresses:
274 354 if isinstance(ip, BaseIP):
275 while i < len(addrs): 355 ips.append(ip)
276 (first, last) = _find_address_range(addrs[i:]) 356 elif ip._prefixlen == ip._max_prefixlen:
277 i = addrs.index(last) + 1 357 ips.append(ip.ip)
278 _addresses.extend( 358 else:
279 [IP(ip) for ip in summarize_address_range(first, last)]) 359 nets.append(ip)
360 # sort and dedup
361 ips = sorted(set(ips))
362 nets = sorted(set(nets))
363
364 while i < len(ips):
365 (first, last) = _find_address_range(ips[i:])
366 i = ips.index(last) + 1
367 addrs.extend(summarize_address_range(first, last))
280 368
281 return _collapse_address_list_recursive( 369 return _collapse_address_list_recursive(
282 sorted(_addresses + nets, key=BaseIP._get_networks_key)) 370 sorted(addrs + nets, key=BaseNet._get_networks_key))
283 371
284 # backwards compatibility 372 # backwards compatibility
285 CollapseAddrList = collapse_address_list 373 CollapseAddrList = collapse_address_list
286 374
287 # Test whether this Python implementation supports byte objects that 375 # Test whether this Python implementation supports byte objects that
288 # are not identical to str ones. 376 # are not identical to str ones.
289 # We need to exclude platforms where bytes == str so that we can 377 # We need to exclude platforms where bytes == str so that we can
290 # distinguish between packed representations and strings, for example 378 # distinguish between packed representations and strings, for example
291 # b'12::' (the IPv4 address 49.50.58.58) and '12::' (an IPv6 address). 379 # b'12::' (the IPv4 address 49.50.58.58) and '12::' (an IPv6 address).
292 try: 380 try:
293 _compat_has_real_bytes = bytes != str 381 _compat_has_real_bytes = bytes != str
294 except NameError: # <Python2.6 382 except NameError: # <Python2.6
295 _compat_has_real_bytes = False 383 _compat_has_real_bytes = False
296 384
297 class BaseIP(object): 385
386 class IPAddrBase(object):
387
388 """The mother class."""
389
390 def __index__(self):
391 return self._ip
392
393 def __int__(self):
394 return self._ip
395
396 def __hex__(self):
397 return hex(self._ip)
398
399
400 class BaseIP(IPAddrBase):
298 401
299 """A generic IP object. 402 """A generic IP object.
300 403
301 This IP class contains most of the methods which are used by 404 This IP class contains the version independent methods which are
302 the IPv4 and IPv6 classes. 405 used by single IP addresses.
303 406
304 """ 407 """
305 408
306 def __getitem__(self, n): 409 @property
307 if n >= 0: 410 def exploded(self):
308 if self.network + n > self.broadcast: 411 return self._explode_shorthand_ip_string()
309 raise IndexError 412
310 return self._string_from_ip_int(self.network + n) 413 @property
311 else: 414 def compressed(self):
312 n += 1 415 return str(self)
313 if self.broadcast + n < self.network: 416
314 raise IndexError 417 def __init__(self, address):
315 return self._string_from_ip_int(self.broadcast + n) 418 if '/' in str(address):
316 419 raise IPAddressIPValidationError(address)
317 def __lt__(self, other):
318 try:
319 return (self.version < other.version
320 or self.ip < other.ip
321 or self.netmask < other.netmask)
322 except AttributeError:
323 return NotImplemented
324
325 def __gt__(self, other):
326 try:
327 return (self.version > other.version
328 or self.ip > other.ip
329 or self.netmask > other.netmask)
330 except AttributeError:
331 return NotImplemented
332 420
333 def __eq__(self, other): 421 def __eq__(self, other):
334 try: 422 try:
335 return (self.version == other.version 423 return not (self._ip != other._ip
336 and self.ip == other.ip 424 or self._version != other._version)
337 and self.netmask == other.netmask)
338 except AttributeError: 425 except AttributeError:
339 return NotImplemented 426 return NotImplemented
340 427
341 def __ne__(self, other): 428 def __ne__(self, other):
342 eq = self.__eq__(other) 429 eq = self.__eq__(other)
343 if eq is NotImplemented: 430 if eq is NotImplemented:
344 return NotImplemented 431 return NotImplemented
345 return not eq 432 return not eq
346 433
347 def __le__(self, other): 434 def __le__(self, other):
348 gt = self.__gt__(other) 435 gt = self.__gt__(other)
349 if gt is NotImplemented: 436 if gt is NotImplemented:
350 return NotImplemented 437 return NotImplemented
351 return not gt 438 return not gt
352 439
353 def __ge__(self, other): 440 def __ge__(self, other):
354 lt = self.__lt__(other) 441 lt = self.__lt__(other)
355 if lt is NotImplemented: 442 if lt is NotImplemented:
356 return NotImplemented 443 return NotImplemented
357 return not lt 444 return not lt
358 445
446 def __lt__(self, other):
447 if self._version != other._version:
448 return self._version < other._version
449 if self._ip != other._ip:
450 return self._ip < other._ip
451 return False
452
453 def __gt__(self, other):
454 if self._version != other._version:
455 return self._version > other._version
456 if self._ip != other._ip:
457 return self._ip > other._ip
458 return False
459
359 def __repr__(self): 460 def __repr__(self):
360 return '%s(%r)' % (self.__class__.__name__, str(self)) 461 return '%s(%r)' % (self.__class__.__name__, str(self))
361 462
362 def __index__(self): 463 def __str__(self):
363 return self.ip 464 return '%s' % self._string_from_ip_int(self._ip)
364 465
365 def __int__(self): 466 def __hash__(self):
366 return self.ip 467 return hash(self._ip)
367 468
368 def __hex__(self): 469 @property
369 return hex(int(self)) 470 def version(self):
471 raise NotImplementedError('BaseIP has no version')
472
473
474 class BaseNet(IPAddrBase):
475
476 """A generic IP object.
477
478 This IP class contains the version independent methods which are
479 used by networks.
480
481 """
482
483 def __init__(self, address):
484 self._cache = {}
485
486 def __repr__(self):
487 return '%s(%r)' % (self.__class__.__name__, str(self))
488
489 def iterhosts(self):
490 """Generate Iterator over hosts in a network."""
491 cur = int(self.network)
492 bcast = int(self.broadcast)
493 while cur <= bcast:
494 cur += 1
495 yield IP(cur - 1, host=True, version=self._version)
496
497 def __iter__(self):
498 self._cur = int(self.network)
499 return self
500
501 def next(self):
502 if self._cur > int(self.broadcast):
503 raise StopIteration
504 self._cur += 1
505 return IP(self._cur - 1, host=True, version=self._version)
506
507 def __getitem__(self, n):
508 network = int(self.network)
509 broadcast = int(self.broadcast)
510 if n >= 0:
511 if network + n > broadcast:
512 raise IndexError
513 return IP(network + n, host=True, version=self._version)
514 else:
515 n += 1
516 if broadcast + n < network:
517 raise IndexError
518 return IP(broadcast + n, host=True,
519 version=self._version)
520
521 def __lt__(self, other):
522 try:
523 if self._version != other._version:
524 return self._version < other._version
525 if self._ip != other._ip:
526 return self._ip < other._ip
527 if self.netmask != other.netmask:
528 return self.netmask < other.netmask
529 return False
530 except AttributeError:
531 return NotImplemented
532
533 def __gt__(self, other):
534 try:
535 if self._version != other._version:
536 return self._version > other._version
537 if self._ip != other._ip:
538 return self._ip > other._ip
539 if self.netmask != other.netmask:
540 return self.netmask > other.netmask
541 return False
542 except AttributeError:
543 return NotImplemented
544
545 def __eq__(self, other):
546 try:
547 return (self._version == other._version
548 and self._ip == other._ip
549 and int(self.netmask) == int(other.netmask))
550 except AttributeError:
551 return NotImplemented
552
553 def __ne__(self, other):
554 eq = self.__eq__(other)
555 if eq is NotImplemented:
556 return NotImplemented
557 return not eq
558
559 def __str__(self):
560 return '%s/%s' % (str(self.ip),
561 str(self._prefixlen))
562
563 def __hash__(self):
564 return hash(self._ip ^ int(self.netmask))
565
566 def __contains__(self, other):
567 # Easy case, dealing with networks.
568 if isinstance(other, BaseNet):
569 return (int(self.network) <= int(other._ip) and
570 int(self.broadcast) >= int(other.broadcast))
571 elif isinstance(other, BaseIP):
572 # Check if we've got an Address
573 return (int(self.network) <= int(other._ip) <=
574 int(self.broadcast))
575 else:
576 return IP(other) in self
577
578 @property
579 def network(self):
580 x = self._cache.get('network')
581 if x is None:
582 x = IP(self._ip & int(self.netmask), host=True,
583 version=self._version)
584 self._cache['network'] = x
585 return x
586
587 @property
588 def broadcast(self):
589 x = self._cache.get('broadcast')
590 if x is None:
591 x = IP(self._ip | int(self.hostmask), host=True,
592 version=self._version)
593 self._cache['broadcast'] = x
594 return x
595
596 @property
597 def hostmask(self):
598 x = self._cache.get('hostmask')
599 if x is None:
600 x = IP(int(self.netmask) ^ self._ALL_ONES, host=True,
601 version=self._version)
602 self._cache['hostmask'] = x
603 return x
604
605 @property
606 def with_prefixlen(self):
607 return '%s/%d' % (str(self.ip), self._prefixlen)
608
609 @property
610 def with_netmask(self):
611 return '%s/%s' % (str(self.ip), str(self.netmask))
612
613 @property
614 def with_hostmask(self):
615 return '%s/%s' % (str(self.ip), str(self.hostmask))
616
617 @property
618 def numhosts(self):
619 """Number of hosts in the current subnet."""
620 return int(self.broadcast) - int(self.network) + 1
621
622 @property
623 def version(self):
624 raise NotImplementedError('BaseNet has no version')
625
626 prefixlen = property(
627 fget=lambda self: self._prefixlen,
628 fset=lambda self, prefixlen: self._set_prefix(prefixlen))
370 629
371 def address_exclude(self, other): 630 def address_exclude(self, other):
372 """Remove an address from a larger block. 631 """Remove an address from a larger block.
373 632
374 For example: 633 For example:
375 634
376 addr1 = IP('10.1.1.0/24') 635 addr1 = IP('10.1.1.0/24')
377 addr2 = IP('10.1.1.0/26') 636 addr2 = IP('10.1.1.0/26')
378 addr1.address_exclude(addr2) = 637 addr1.address_exclude(addr2) =
379 [IP('10.1.1.64/26'), IP('10.1.1.128/25')] 638 [IP('10.1.1.64/26'), IP('10.1.1.128/25')]
(...skipping 18 matching lines...) Expand all
398 657
399 Raises: 658 Raises:
400 IPTypeError: If self and other are of difffering address 659 IPTypeError: If self and other are of difffering address
401 versions. 660 versions.
402 IPAddressExclusionError: There was some unknown error in the 661 IPAddressExclusionError: There was some unknown error in the
403 address exclusion process. This likely points to a bug 662 address exclusion process. This likely points to a bug
404 elsewhere in this code. 663 elsewhere in this code.
405 ValueError: If other is not completely contained by self. 664 ValueError: If other is not completely contained by self.
406 665
407 """ 666 """
408 if not self.version == other.version: 667 if not self._version == other._version:
409 raise IPTypeError("%s and %s aren't of the same version" % ( 668 raise IPTypeError("%s and %s aren't of the same version" % (
410 str(self), str(other))) 669 str(self), str(other)))
411 670
412 if other not in self: 671 if other not in self:
413 raise ValueError('%s not contained in %s' % (str(other), 672 raise ValueError('%s not contained in %s' % (str(other),
414 str(self))) 673 str(self)))
415
416 ret_addrs = [] 674 ret_addrs = []
417 675
418 # Make sure we're comparing the network of other. 676 # Make sure we're comparing the network of other.
419 other = IP(other.network_ext + '/' + str(other.prefixlen)) 677 other = IP('%s/%s' % (str(other.network), str(other.prefixlen)),
678 version=other._version)
420 679
421 s1, s2 = self.subnet() 680 s1, s2 = self.subnet()
422 while s1 != other and s2 != other: 681 while s1 != other and s2 != other:
423 if other in s1: 682 if other in s1:
424 ret_addrs.append(s2) 683 ret_addrs.append(s2)
425 s1, s2 = s1.subnet() 684 s1, s2 = s1.subnet()
426 elif other in s2: 685 elif other in s2:
427 ret_addrs.append(s1) 686 ret_addrs.append(s1)
428 s1, s2 = s2.subnet() 687 s1, s2 = s2.subnet()
429 else: 688 else:
430 # If we got here, there's a bug somewhere. 689 # If we got here, there's a bug somewhere.
431 raise IPAddressExclusionError('Error performing exclusion: ' 690 raise IPAddressExclusionError('Error performing exclusion: '
432 's1: %s s2: %s other: %s' % 691 's1: %s s2: %s other: %s' %
433 (str(s1), str(s2), str(other))) 692 (str(s1), str(s2), str(other)))
434 if s1 == other: 693 if s1 == other:
435 ret_addrs.append(s2) 694 ret_addrs.append(s2)
436 elif s2 == other: 695 elif s2 == other:
437 ret_addrs.append(s1) 696 ret_addrs.append(s1)
438 else: 697 else:
439 # If we got here, there's a bug somewhere. 698 # If we got here, there's a bug somewhere.
440 raise IPAddressExclusionError('Error performing exclusion: ' 699 raise IPAddressExclusionError('Error performing exclusion: '
441 's1: %s s2: %s other: %s' % 700 's1: %s s2: %s other: %s' %
442 (str(s1), str(s2), str(other))) 701 (str(s1), str(s2), str(other)))
443 702
444 return sorted(ret_addrs, key=BaseIP._get_networks_key) 703 return sorted(ret_addrs, key=BaseNet._get_networks_key)
445 704
446 def compare_networks(self, other): 705 def compare_networks(self, other):
447 """Compare two IP objects. 706 """Compare two IP objects.
448 707
449 This is only concerned about the comparison of the integer 708 This is only concerned about the comparison of the integer
450 representation of the network addresses. This means that the 709 representation of the network addresses. This means that the
451 host bits aren't considered at all in this method. If you want 710 host bits aren't considered at all in this method. If you want
452 to compare host bits, you can easily enough do a 711 to compare host bits, you can easily enough do a
453 'HostA.ip < HostB.ip' 712 'HostA._ip < HostB._ip'
454 713
455 Args: 714 Args:
456 other: An IP object. 715 other: An IP object.
457 716
458 Returns: 717 Returns:
459 If the IP versions of self and other are the same, returns: 718 If the IP versions of self and other are the same, returns:
460 719
461 -1 if self < other: 720 -1 if self < other:
462 eg: IPv4('1.1.1.0/24') < IPv4('1.1.2.0/24') 721 eg: IPv4('1.1.1.0/24') < IPv4('1.1.2.0/24')
463 IPv6('1080::200C:417A') < IPv6('1080::200B:417B') 722 IPv6('1080::200C:417A') < IPv6('1080::200B:417B')
464 0 if self == other 723 0 if self == other
465 eg: IPv4('1.1.1.1/24') == IPv4('1.1.1.2/24') 724 eg: IPv4('1.1.1.1/24') == IPv4('1.1.1.2/24')
466 IPv6('1080::200C:417A/96') == IPv6('1080::200C:417B/96') 725 IPv6('1080::200C:417A/96') == IPv6('1080::200C:417B/96')
467 1 if self > other 726 1 if self > other
468 eg: IPv4('1.1.1.0/24') > IPv4('1.1.0.0/24') 727 eg: IPv4('1.1.1.0/24') > IPv4('1.1.0.0/24')
469 IPv6('1080::1:200C:417A/112') > 728 IPv6('1080::1:200C:417A/112') >
470 IPv6('1080::0:200C:417A/112') 729 IPv6('1080::0:200C:417A/112')
471 730
472 If the IP versions of self and other are different, returns: 731 If the IP versions of self and other are different, returns:
473 732
474 -1 if self.version < other.version 733 -1 if self._version < other._version
475 eg: IPv4('10.0.0.1/24') < IPv6('::1/128') 734 eg: IPv4('10.0.0.1/24') < IPv6('::1/128')
476 1 if self.version > other.version 735 1 if self._version > other._version
477 eg: IPv6('::1/128') > IPv4('255.255.255.0/24') 736 eg: IPv6('::1/128') > IPv4('255.255.255.0/24')
478 737
479 """ 738 """
480 if self.version < other.version: 739 if self._version < other._version:
481 return -1 740 return -1
482 if self.version > other.version: 741 if self._version > other._version:
483 return 1 742 return 1
484 # self.version == other.version below here: 743 # self._version == other._version below here:
485 if self.network < other.network: 744 if self.network < other.network:
486 return -1 745 return -1
487 if self.network > other.network: 746 if self.network > other.network:
488 return 1 747 return 1
489 # self.network == other.network below here: 748 # self.network == other.network below here:
490 if self.netmask < other.netmask: 749 if self.netmask < other.netmask:
491 return -1 750 return -1
492 if self.netmask > other.netmask: 751 if self.netmask > other.netmask:
493 return 1 752 return 1
494 # self.network == other.network and self.netmask == other.netmask 753 # self.network == other.network and self.netmask == other.netmask
495 return 0 754 return 0
496 755
497 def _get_networks_key(self): 756 def _get_networks_key(self):
498 """Network-only key function. 757 """Network-only key function.
499 758
500 Returns an object that identifies this address' network and 759 Returns an object that identifies this address' network and
501 netmask. This function is a suitable "key" argument for sorted() 760 netmask. This function is a suitable "key" argument for sorted()
502 and list.sort(). 761 and list.sort().
503 762
504 """ 763 """
505 return (self.version, self.network, self.netmask) 764 return (self._version, self.network, self.netmask)
506
507 prefixlen = property(
508 fget=lambda self: self._prefixlen,
509 fset=lambda self, prefixlen: self._set_prefix(prefixlen))
510
511 def __str__(self):
512 return '%s/%s' % (self._string_from_ip_int(self.ip),
513 str(self.prefixlen))
514
515 def __hash__(self):
516 return hash(self.ip ^ self.netmask)
517
518 def __contains__(self, other):
519 return self.network <= other.ip and self.broadcast >= other.broadcast
520
521 @property
522 def ip_ext(self):
523 """Dotted decimal or colon string version of the IP address."""
524 return self._string_from_ip_int(self.ip)
525
526 @property
527 def ip_ext_full(self):
528 """Canonical string version of the IP address."""
529 return self.ip_ext
530
531 @property
532 def broadcast(self):
533 """Integer representation of the broadcast address."""
534 return self.ip | self.hostmask
535
536 @property
537 def broadcast_ext(self):
538 """Dotted decimal or colon string version of the broadcast."""
539 return self._string_from_ip_int(self.broadcast)
540
541 @property
542 def hostmask(self):
543 """Integer representation of the hostmask."""
544 return self.netmask ^ self._ALL_ONES
545
546 @property
547 def hostmask_ext(self):
548 """Dotted decimal or colon string version of the hostmask."""
549 return self._string_from_ip_int(self.hostmask)
550
551 @property
552 def network(self):
553 """Integer representation of the network."""
554 return self.ip & self.netmask
555
556 @property
557 def network_ext(self):
558 """Dotted decimal or colon string version of the network."""
559 return self._string_from_ip_int(self.network)
560
561 @property
562 def netmask_ext(self):
563 """Dotted decimal or colon string version of the netmask."""
564 return self._string_from_ip_int(self.netmask)
565
566 @property
567 def numhosts(self):
568 """Number of hosts in the current subnet."""
569 return self.broadcast - self.network + 1
570
571 @property
572 def version(self):
573 raise NotImplementedError('BaseIP has no version')
574 765
575 def _ip_int_from_prefix(self, prefixlen=None): 766 def _ip_int_from_prefix(self, prefixlen=None):
576 """Turn the prefix length netmask into a int for comparison. 767 """Turn the prefix length netmask into a int for comparison.
577 768
578 Args: 769 Args:
579 prefixlen: An integer, the prefix length. 770 prefixlen: An integer, the prefix length.
580 771
581 Returns: 772 Returns:
582 An integer. 773 An integer.
583 774
584 """ 775 """
585 if not prefixlen and prefixlen != 0: 776 if not prefixlen and prefixlen != 0:
586 prefixlen = self.prefixlen 777 prefixlen = self._prefixlen
587 return self._ALL_ONES ^ (self._ALL_ONES >> prefixlen) 778 return self._ALL_ONES ^ (self._ALL_ONES >> prefixlen)
588 779
589 def _prefix_from_ip_int(self, ip_int, mask=32): 780 def _prefix_from_ip_int(self, ip_int, mask=32):
590 """Return prefix length from the decimal netmask. 781 """Return prefix length from the decimal netmask.
591 782
592 Args: 783 Args:
593 ip_int: An integer, the IP address. 784 ip_int: An integer, the IP address.
594 mask: The netmask. Defaults to 32. 785 mask: The netmask. Defaults to 32.
595 786
596 Returns: 787 Returns:
(...skipping 12 matching lines...) Expand all
609 """Turn a prefix length into a dotted decimal string. 800 """Turn a prefix length into a dotted decimal string.
610 801
611 Args: 802 Args:
612 prefixlen: An integer, the netmask prefix length. 803 prefixlen: An integer, the netmask prefix length.
613 804
614 Returns: 805 Returns:
615 A string, the dotted decimal netmask string. 806 A string, the dotted decimal netmask string.
616 807
617 """ 808 """
618 if not prefixlen: 809 if not prefixlen:
619 prefixlen = self.prefixlen 810 prefixlen = self._prefixlen
620 return self._string_from_ip_int(self._ip_int_from_prefix(prefixlen)) 811 return self._string_from_ip_int(self._ip_int_from_prefix(prefixlen))
621 812
622 # backwards compatibility 813 # backwards compatibility
623 AddressExclude = address_exclude 814 AddressExclude = address_exclude
624 CompareNetworks = compare_networks 815 CompareNetworks = compare_networks
625 Contains = __contains__ 816 Contains = __contains__
626 def set_prefix(self, prefixlen): self.prefixlen = prefixlen 817 def set_prefix(self, prefixlen): self.prefixlen = prefixlen
627 SetPrefix = set_prefix 818 SetPrefix = set_prefix
628 def get_prefix(self): return self.prefixlen 819 def get_prefix(self): return self.prefixlen
629 820
630 821
631 class IPv4(BaseIP): 822 class BaseV4(object):
632 823
633 """This class represents and manipulates 32-bit IPv4 addresses. 824 """Base IPv4 object.
634 825
635 Attributes: [examples for IPv4('1.2.3.4/27')] 826 The following methods are used by IPv4 objects in both single IP
636 .ip: 16909060 827 addresses and networks.
637 .ip_ext: '1.2.3.4'
638 .ip_ext_full: '1.2.3.4'
639 .network: 16909056L
640 .network_ext: '1.2.3.0'
641 .hostmask: 31L (0x1F)
642 .hostmask_ext: '0.0.0.31'
643 .broadcast: 16909087L (0x102031F)
644 .broadcast_ext: '1.2.3.31'
645 .netmask: 4294967040L (0xFFFFFFE0)
646 .netmask_ext: '255.255.255.224'
647 .prefixlen: 27
648 828
649 """ 829 """
650 830
651 # Equivalent to 255.255.255.255 or 32 bits of 1's. 831 # Equivalent to 255.255.255.255 or 32 bits of 1's.
652 _ALL_ONES = (2**32) - 1 832 _ALL_ONES = (2**32) - 1
653 833
654 def __init__(self, ipaddr): 834 def __init__(self, address):
655 """Instantiate a new IPv4 object. 835 self._version = 4
656 836 self._max_prefixlen = 32
657 Args: 837
658 ipaddr: A string or integer representing the IP [& network]. 838 def _explode_shorthand_ip_string(self, ip_str=None):
839 if not ip_str:
840 ip_str = str(self)
841 return ip_str
842
843 def _ip_int_from_string(self, ip_str):
844 """Turn the given IP string into an integer for comparison.
845
846 Args:
847 ip_str: A string, the IP ip_str.
848
849 Returns:
850 The IP ip_str as an integer.
851
852 """
853 packed_ip = 0
854 for oc in ip_str.split('.'):
855 packed_ip = (packed_ip << 8) | int(oc)
856 return packed_ip
857
858 def _string_from_ip_int(self, ip_int):
859 """Turns a 32-bit integer into dotted decimal notation.
860
861 Args:
862 ip_int: An integer, the IP address.
863
864 Returns:
865 The IP address as a string in dotted decimal notation.
866
867 """
868 octets = []
869 for _ in xrange(4):
870 octets.insert(0, str(ip_int & 0xFF))
871 ip_int >>= 8
872 return '.'.join(octets)
873
874 def _is_valid_ip(self, ip_str):
875 """Validate the dotted decimal notation IP/netmask string.
876
877 Args:
878 ip_str: A string, the IP ip_str.
879
880 Returns:
881 A boolean, True if the string is a valid dotted decimal IP
882 string.
883
884 """
885 octets = ip_str.split('.')
886 if len(octets) == 1:
887 # We have an integer rather than a dotted decimal IP.
888 try:
889 return int(ip_str) >= 0 and int(ip_str) <= self._ALL_ONES
890 except ValueError:
891 return False
892
893 if len(octets) != 4:
894 return False
895
896 for octet in octets:
897 try:
898 if not 0 <= int(octet) <= 255:
899 return False
900 except ValueError:
901 return False
902 return True
903
904 @property
905 def max_prefixlen(self):
906 return self._max_prefixlen
907
908 @property
909 def packed(self):
910 """The binary representation of this address."""
911 return struct.pack('!I', self._ip)
912
913 @property
914 def version(self):
915 return self._version
916
917
918 class IPv4Address(BaseV4, BaseIP):
919
920 """Represent and manipulate single IPv4 Addresses."""
921
922 def __init__(self, address):
923
924 """
925 Args:
926 address: A string or integer representing the IP
927 '192.168.1.1'
928
929 Additionally, an integer can be passed, so
930 IPv4Address('192.168.1.1') == IPv4Address(3232235777).
931 or, more generally
932 IPv4Address(int(IPv4Address('192.168.1.1'))) ==
933 IPv4Address('192.168.1.1')
934
935 Raises:
936 IPv4IpValidationError: If ipaddr isn't a valid IPv4 address.
937 IPv4NetmaskValidationError: If the netmask isn't valid for
938 an IPv4 address.
939
940 """
941 BaseIP.__init__(self, address)
942 BaseV4.__init__(self, address)
943
944 # Efficient constructor from integer.
945 if isinstance(address, int) or isinstance(address, long):
946 self._ip = address
947 if address < 0 or address > self._ALL_ONES:
948 raise IPv4IpValidationError(address)
949 return
950
951 # Constructing from a packed address
952 if _compat_has_real_bytes:
953 if isinstance(address, bytes) and len(address) == 4:
954 self._ip = struct.unpack('!I', address)[0]
955 return
956
957 # we have a string
958 if not self._is_valid_ip(address):
959 raise IPv4IpValidationError(address)
960
961 self._ip = self._ip_int_from_string(address)
962
963
964 class IPv4Network(BaseV4, BaseNet):
965
966 """This class represents and manipulates 32-bit IPv4 networks.
967
968 Attributes: [examples for IPv4Network('1.2.3.4/27')]
969 ._ip: 16909060
970 .ip: IPv4Address('1.2.3.4')
971 .network: IPv4Address('1.2.3.0')
972 .hostmask: IPv4Address('0.0.0.31')
973 .broadcast: IPv4Address('1.2.3.31')
974 .netmask: IPv4Address('255.255.255.224')
975 .prefixlen: 27
976
977 """
978
979 def __init__(self, address):
980 """Instantiate a new IPv4 network object.
981
982 Args:
983 address: A string or integer representing the IP [& network].
659 '192.168.1.1/32' 984 '192.168.1.1/32'
660 '192.168.1.1/255.255.255.255' 985 '192.168.1.1/255.255.255.255'
661 '192.168.1.1/0.0.0.255' 986 '192.168.1.1/0.0.0.255'
662 '192.168.1.1' 987 '192.168.1.1'
663 '192.168.1.0-192.168.1.0'
664 are all functionally the same in IPv4. That is to say, 988 are all functionally the same in IPv4. That is to say,
665 failing to provide a subnetmask will create an object with 989 failing to provide a subnetmask will create an object with
666 a mask of /32. A netmask of '255.255.255.255' is assumed 990 a mask of /32. A netmask of '255.255.255.255' is assumed
667 to be /32 and '0.0.0.0' is assumed to be /0, even though 991 to be /32 and '0.0.0.0' is assumed to be /0, even though
668 other netmasks can be expressed both as host- and 992 other netmasks can be expressed both as host- and
669 net-masks. (255.0.0.0 == 0.255.255.255) 993 net-masks. (255.0.0.0 == 0.255.255.255)
670 994
671 Additionally, an integer can be passed, so 995 Additionally, an integer can be passed, so
672 IPv4('192.168.1.1') == IPv4(3232235777). 996 IPv4Network('192.168.1.1') == IPv4Network(3232235777).
673 or, more generally 997 or, more generally
674 IPv4(IPv4('192.168.1.1').ip) == IPv4('192.168.1.1') 998 IPv4Network(int(IPv4Network('192.168.1.1'))) ==
999 IPv4Network('192.168.1.1')
675 1000
676 Raises: 1001 Raises:
677 IPv4IpValidationError: If ipaddr isn't a valid IPv4 address. 1002 IPv4IpValidationError: If ipaddr isn't a valid IPv4 address.
678 IPv4NetmaskValidationError: If the netmask isn't valid for 1003 IPv4NetmaskValidationError: If the netmask isn't valid for
679 an IPv4 address. 1004 an IPv4 address.
680 IPRangeError: If range of IP addresses is not valid. 1005
681 1006 """
682 """ 1007 BaseNet.__init__(self, address)
683 BaseIP.__init__(self) 1008 BaseV4.__init__(self, address)
684 self._version = 4
685 self._max_prefixlen = 32
686 1009
687 # Efficient constructor from integer. 1010 # Efficient constructor from integer.
688 if isinstance(ipaddr, int) or isinstance(ipaddr, long): 1011 if isinstance(address, int) or isinstance(address, long):
689 self.ip = ipaddr 1012 self._ip = address
1013 self.ip = IPv4Address(self._ip)
690 self._prefixlen = 32 1014 self._prefixlen = 32
691 self.netmask = self._ALL_ONES 1015 self.netmask = IPv4Address(self._ALL_ONES)
692 if ipaddr < 0 or ipaddr > self._ALL_ONES: 1016 if address < 0 or address > self._ALL_ONES:
693 raise IPv4IpValidationError(ipaddr) 1017 raise IPv4IpValidationError(address)
694 return 1018 return
695 1019
696 # Constructing from a packed address 1020 # Constructing from a packed address
697 if _compat_has_real_bytes: 1021 if _compat_has_real_bytes:
698 if isinstance(ipaddr, bytes) and len(ipaddr) == 4: 1022 if isinstance(address, bytes) and len(address) == 4:
699 self.ip = struct.unpack('!I', ipaddr)[0] 1023 self._ip = struct.unpack('!I', address)[0]
1024 self.ip = IPv4Address(self._ip)
700 self._prefixlen = 32 1025 self._prefixlen = 32
701 self.netmask = self._ALL_ONES 1026 self.netmask = IPv4Address(self._ALL_ONES)
702 return 1027 return
703
704 # Construct network from a range e.g. 1.1.1.0-1.1.1.255
705 addr = str(ipaddr).split('-')
706
707 if len(addr) > 2:
708 raise IPv4IpValidationError(ipaddr)
709
710 if len(addr) == 2:
711 if not self._is_valid_ip(addr[0]):
712 raise IPv4IpValidationError(addr[0])
713
714 if not self._is_valid_ip(addr[1]):
715 raise IPv4IpValidationError(addr[1])
716
717 self.ip = self._ip_int_from_string(addr[0])
718
719 last = self._ip_int_from_string(addr[1])
720 if last < self.ip:
721 raise IPRangeError("last address should be greater than "
722 "first.")
723 bits = _highest_one_bit(last - self.ip)
724 self._prefixlen = self.max_prefixlen - bits
725 self.netmask = self._ip_int_from_prefix(self._prefixlen)
726 if self.broadcast != last:
727 raise IPRangeError("range %s is not on a network byte "
728 "boundary." % ipaddr)
729 return
730 1028
731 # Assume input argument to be string or any object representation 1029 # Assume input argument to be string or any object representation
732 # which converts into a formatted IP prefix string. 1030 # which converts into a formatted IP prefix string.
733 addr = str(ipaddr).split('/') 1031 addr = str(address).split('/')
734 1032
735 if len(addr) > 2: 1033 if len(addr) > 2:
736 raise IPv4IpValidationError(ipaddr) 1034 raise IPv4IpValidationError(address)
737 1035
738 if not self._is_valid_ip(addr[0]): 1036 if not self._is_valid_ip(addr[0]):
739 raise IPv4IpValidationError(addr[0]) 1037 raise IPv4IpValidationError(addr[0])
740 1038
741 self.ip = self._ip_int_from_string(addr[0]) 1039 self._ip = self._ip_int_from_string(addr[0])
1040 self.ip = IPv4Address(self._ip)
742 1041
743 if len(addr) == 2: 1042 if len(addr) == 2:
744 mask = addr[1].split('.') 1043 mask = addr[1].split('.')
745 if len(mask) == 4: 1044 if len(mask) == 4:
746 # We have dotted decimal netmask. 1045 # We have dotted decimal netmask.
747 if not self._is_valid_netmask(addr[1]): 1046 if not self._is_valid_netmask(addr[1]):
748 raise IPv4NetmaskValidationError(addr[1]) 1047 raise IPv4NetmaskValidationError(addr[1])
749 if self._is_hostmask(addr[1]): 1048 if self._is_hostmask(addr[1]):
750 self.netmask = ( 1049 self.netmask = IPv4Address(
751 self._ip_int_from_string(addr[1]) ^ self._ALL_ONES) 1050 self._ip_int_from_string(addr[1]) ^ self._ALL_ONES)
752 else: 1051 else:
753 self.netmask = self._ip_int_from_string(addr[1]) 1052 self.netmask = IPv4Address(self._ip_int_from_string(
754 self._prefixlen = self._prefix_from_ip_int(self.netmask) 1053 addr[1]))
1054
1055 self._prefixlen = self._prefix_from_ip_int(int(self.netmask))
755 else: 1056 else:
756 # We have a netmask in prefix length form. 1057 # We have a netmask in prefix length form.
757 if not self._is_valid_netmask(addr[1]): 1058 if not self._is_valid_netmask(addr[1]):
758 raise IPv4NetmaskValidationError(addr[1]) 1059 raise IPv4NetmaskValidationError(addr[1])
759 self._prefixlen = int(addr[1]) 1060 self._prefixlen = int(addr[1])
760 self.netmask = self._ip_int_from_prefix(self._prefixlen) 1061 self.netmask = IPv4Address(self._ip_int_from_prefix(
1062 self._prefixlen))
761 else: 1063 else:
762 self._prefixlen = 32 1064 self._prefixlen = 32
763 self.netmask = self._ip_int_from_prefix(self._prefixlen) 1065 self.netmask = IPv4Address(self._ip_int_from_prefix(
1066 self._prefixlen))
1067
764 1068
765 def _set_prefix(self, prefixlen): 1069 def _set_prefix(self, prefixlen):
766 """Change the prefix length. 1070 """Change the prefix length of an IPv4 network object.
767 1071
768 Args: 1072 Args:
769 prefixlen: An integer, the new prefix length. 1073 prefixlen: An integer, the new prefix length.
770 1074
771 Raises: 1075 Raises:
772 IPv4NetmaskValidationError: If prefixlen is out of bounds. 1076 IPv4NetmaskValidationError: If prefixlen is out of bounds.
773 1077
774 """ 1078 """
775 if not 0 <= prefixlen <= 32: 1079 if not 0 <= prefixlen <= 32:
776 raise IPv4NetmaskValidationError(prefixlen) 1080 raise IPv4NetmaskValidationError(prefixlen)
777 self._prefixlen = prefixlen 1081 self._prefixlen = prefixlen
778 self.netmask = self._ip_int_from_prefix(self._prefixlen) 1082 self.netmask = IPv4Address(self._ip_int_from_prefix(self._prefixlen))
1083 # invalidate the element cache
1084 self._cache['network'] = None
1085 self._cache['hostmask'] = None
1086 self._cache['broadcast'] = None
779 1087
780 def subnet(self, prefixlen_diff=1): 1088 def subnet(self, prefixlen_diff=1):
781 """The subnets which join to make the current subnet. 1089 """The subnets which join to make the current subnet.
782 1090
783 In the case that self contains only one IP 1091 In the case that self contains only one IP
784 (self._prefixlen == 32), return a list with just ourself. 1092 (self._prefixlen == 32), return a list with just ourself.
785 1093
786 Args: 1094 Args:
787 prefixlen_diff: An integer, the amount the prefix length 1095 prefixlen_diff: An integer, the amount the prefix length
788 should be increased by. Given a /24 network and a 1096 should be increased by. Given a /24 network and a
789 prefixlen_diff of 3, for example, 8 subnets of size /27 1097 prefixlen_diff of 3, for example, 8 subnets of size /27
790 will be returned. The default value of 1 splits the 1098 will be returned. The default value of 1 splits the
791 current network into two halves. 1099 current network into two halves.
792 1100
793 Returns: 1101 Returns:
794 A list of IPv4 objects. 1102 A list of IPv4 network objects.
795 1103
796 Raises: 1104 Raises:
797 PrefixlenDiffInvalidError: The prefixlen_diff is too small 1105 PrefixlenDiffInvalidError: The prefixlen_diff is too small
798 or too large. 1106 or too large.
799 1107
800 """ 1108 """
801 if self._prefixlen == 32: 1109 if self._prefixlen == 32:
802 return [self] 1110 return [self]
803 1111
804 if prefixlen_diff < 0: 1112 if prefixlen_diff < 0:
805 raise PrefixlenDiffInvalidError('prefix length diff must be > 0') 1113 raise PrefixlenDiffInvalidError('prefix length diff must be > 0')
806 new_prefixlen = self.prefixlen + prefixlen_diff 1114 new_prefixlen = self._prefixlen + prefixlen_diff
807 1115
808 if not self._is_valid_netmask(str(new_prefixlen)): 1116 if not self._is_valid_netmask(str(new_prefixlen)):
809 raise PrefixlenDiffInvalidError( 1117 raise PrefixlenDiffInvalidError(
810 'prefix length diff %d is invalid for netblock %s' % ( 1118 'prefix length diff %d is invalid for netblock %s' % (
811 new_prefixlen, str(self))) 1119 new_prefixlen, str(self)))
812 1120
813 first = IPv4( 1121 first = IPv4('%s/%s' % (str(self.network),
814 self._string_from_ip_int(self.network) + '/' + 1122 str(self._prefixlen + prefixlen_diff)))
815 str(self._prefixlen + prefixlen_diff))
816 subnets = [first] 1123 subnets = [first]
817 current = first 1124 current = first
818 while True: 1125 while True:
819 broadcast = current.broadcast 1126 broadcast = current.broadcast
820 if broadcast == self.broadcast: 1127 if broadcast == self.broadcast:
821 break 1128 break
822 current = IPv4(self._string_from_ip_int(broadcast + 1) + '/' + 1129 current = IPv4('%d/%s' % (int(broadcast) + 1, str(new_prefixlen)))
823 str(new_prefixlen))
824 subnets.append(current) 1130 subnets.append(current)
825 1131
826 return subnets 1132 return subnets
827 1133
828 def supernet(self, prefixlen_diff=1): 1134 def supernet(self, prefixlen_diff=1):
829 """The supernet containing the current network. 1135 """The supernet containing the current network.
830 1136
831 Args: 1137 Args:
832 prefixlen_diff: An integer, the amount the prefix length of 1138 prefixlen_diff: An integer, the amount the prefix length of
833 the network should be decreased by. For example, given a 1139 the network should be decreased by. For example, given a
834 /24 network and a prefixlen_diff of 3, a supernet with a 1140 /24 network and a prefixlen_diff of 3, a supernet with a
835 /21 netmask is returned. 1141 /21 netmask is returned.
836 1142
837 Returns: 1143 Returns:
838 An IPv4 object. 1144 An IPv4 network object.
839 1145
840 Raises: 1146 Raises:
841 PrefixlenDiffInvalidError: If 1147 PrefixlenDiffInvalidError: If
842 self.prefixlen - prefixlen_diff < 0. I.e., you have a 1148 self.prefixlen - prefixlen_diff < 0. I.e., you have a
843 negative prefix length. 1149 negative prefix length.
844 1150
845 """ 1151 """
846 if self.prefixlen == 0: 1152 if self._prefixlen == 0:
847 return self 1153 return self
848 if self.prefixlen - prefixlen_diff < 0: 1154 if self.prefixlen - prefixlen_diff < 0:
849 raise PrefixlenDiffInvalidError( 1155 raise PrefixlenDiffInvalidError(
850 'current prefixlen is %d, cannot have a prefixlen_diff of %d' % 1156 'current prefixlen is %d, cannot have a prefixlen_diff of %d' %
851 (self.prefixlen, prefixlen_diff)) 1157 (self.prefixlen, prefixlen_diff))
852 return IPv4(self.ip_ext + '/' + str(self.prefixlen - prefixlen_diff)) 1158 return IPv4('%s/%s' % (str(self.network),
1159 str(self.prefixlen - prefixlen_diff)))
853 1160
854 @property 1161 @property
855 def is_private(self): 1162 def is_private(self):
856 """Test if this address is allocated for private networks. 1163 """Test if this address is allocated for private networks.
857 1164
858 Returns: 1165 Returns:
859 A boolean, True if the address is reserved per RFC 1918. 1166 A boolean, True if the address is reserved per RFC 1918.
860 1167
861 """ 1168 """
862 return (self in IPv4('10.0.0.0/8') or 1169 return (self in IPv4('10.0.0.0/8') or
(...skipping 23 matching lines...) Expand all
886 1193
887 @property 1194 @property
888 def is_link_local(self): 1195 def is_link_local(self):
889 """Test if the address is reserved for link-local. 1196 """Test if the address is reserved for link-local.
890 1197
891 Returns: 1198 Returns:
892 A boolean, True if the address is link-local per RFC 3927. 1199 A boolean, True if the address is link-local per RFC 3927.
893 1200
894 """ 1201 """
895 return self in IPv4('169.254.0.0/16') 1202 return self in IPv4('169.254.0.0/16')
896
897 @property
898 def version(self):
899 return self._version
900
901 @property
902 def max_prefixlen(self):
903 return self._max_prefixlen
904
905 @property
906 def packed(self):
907 """The binary representation of this address."""
908 return struct.pack('!I', self.ip)
909 1203
910 def _is_hostmask(self, ip_str): 1204 def _is_hostmask(self, ip_str):
911 """Test if the IP string is a hostmask (rather than a netmask). 1205 """Test if the IP string is a hostmask (rather than a netmask).
912 1206
913 Args: 1207 Args:
914 ip_str: A string, the potential hostmask. 1208 ip_str: A string, the potential hostmask.
915 1209
916 Returns: 1210 Returns:
917 A boolean, True if the IP string is a hostmask. 1211 A boolean, True if the IP string is a hostmask.
918 1212
919 """ 1213 """
920 parts = [int(x) for x in ip_str.split('.')] 1214 parts = [int(x) for x in ip_str.split('.')]
921 if parts[0] < parts[-1]: 1215 if parts[0] < parts[-1]:
922 return True 1216 return True
923 return False 1217 return False
924
925 def _ip_int_from_string(self, ip_str):
926 """Turn the given IP string into an integer for comparison.
927
928 Args:
929 ip_str: A string, the IP address.
930
931 Returns:
932 The IP address as an integer.
933
934 """
935 packed_ip = 0
936 for oc in ip_str.split('.'):
937 packed_ip = (packed_ip << 8) | int(oc)
938 return packed_ip
939
940 def _string_from_ip_int(self, ip_int):
941 """Turns a 32-bit integer into dotted decimal notation.
942
943 Args:
944 ip_int: An integer, the IP address.
945
946 Returns:
947 The IP address as a string in dotted decimal notation.
948
949 """
950 octets = []
951 for _ in xrange(4):
952 octets.insert(0, str(ip_int & 0xFF))
953 ip_int >>= 8
954 return '.'.join(octets)
955
956 def _is_valid_ip(self, ip_str):
957 """Validate the dotted decimal notation IP/netmask string.
958
959 Args:
960 ip_str: A string, the IP address.
961
962 Returns:
963 A boolean, True if the string is a valid dotted decimal IP
964 string.
965
966 """
967 octets = ip_str.split('.')
968 if len(octets) == 1:
969 # We have an integer rather than a dotted decimal IP.
970 try:
971 return int(ip_str) >= 0 and int(ip_str) <= self._ALL_ONES
972 except ValueError:
973 return False
974
975 if len(octets) != 4:
976 return False
977
978 for octet in octets:
979 try:
980 if not 0 <= int(octet) <= 255:
981 return False
982 except ValueError:
983 return False
984 return True
985 1218
986 def _is_valid_netmask(self, netmask): 1219 def _is_valid_netmask(self, netmask):
987 """Verify that the netmask is valid. 1220 """Verify that the netmask is valid.
988 1221
989 Args: 1222 Args:
990 netmask: A string, either a prefix or dotted decimal 1223 netmask: A string, either a prefix or dotted decimal
991 netmask. 1224 netmask.
992 1225
993 Returns: 1226 Returns:
994 A boolean, True if the prefix represents a valid IPv4 1227 A boolean, True if the prefix represents a valid IPv4
995 netmask. 1228 netmask.
996 1229
997 """ 1230 """
998 if len(netmask.split('.')) == 4: 1231 if len(netmask.split('.')) == 4:
999 return self._is_valid_ip(netmask) 1232 return self._is_valid_ip(netmask)
1000 try: 1233 try:
1001 netmask = int(netmask) 1234 netmask = int(netmask)
1002 except ValueError: 1235 except ValueError:
1003 return False 1236 return False
1004 return 0 <= netmask <= 32 1237 return 0 <= netmask <= 32
1005 1238
1006 # backwards compatibility 1239 # backwards compatibility
1007 Subnet = subnet 1240 Subnet = subnet
1008 Supernet = supernet 1241 Supernet = supernet
1009 IsRFC1918 = lambda self: self.is_private 1242 IsRFC1918 = lambda self: self.is_private
1010 IsMulticast = lambda self: self.is_multicast 1243 IsMulticast = lambda self: self.is_multicast
1011 IsLoopback = lambda self: self.is_loopback 1244 IsLoopback = lambda self: self.is_loopback
1012 IsLinkLocal = lambda self: self.is_link_local 1245 IsLinkLocal = lambda self: self.is_link_local
1013 1246
1014 class IPv6(BaseIP): 1247
1015 1248 class BaseV6(object):
1016 """This class respresents and manipulates 128-bit IPv6 addresses. 1249
1017 1250 """Base IPv6 object.
1018 Attributes: [examples for IPv6('2001:658:22A:CAFE:200::1/64')] 1251
1019 .ip: 42540616829182469433547762482097946625L 1252 The following methods are used by IPv6 objects in both single IP
1020 .ip_ext: '2001:658:22a:cafe:200::1' 1253 addresses and networks.
1021 .ip_ext_full: '2001:0658:022a:cafe:0200:0000:0000:0001'
1022 .network: 42540616829182469433403647294022090752L
1023 .network_ext: '2001:658:22a:cafe::'
1024 .hostmask: 18446744073709551615L
1025 .hostmask_ext: '::ffff:ffff:ffff:ffff'
1026 .broadcast: 42540616829182469451850391367731642367L
1027 .broadcast_ext: '2001:658:22a:cafe:ffff:ffff:ffff:ffff'
1028 .netmask: 340282366920938463444927863358058659840L
1029 .netmask_ext: 64
1030 .prefixlen: 64
1031 1254
1032 """ 1255 """
1033 1256
1034 _ALL_ONES = (2**128) - 1 1257 _ALL_ONES = (2**128) - 1
1035 1258
1036 def __init__(self, ipaddr): 1259 def __init__(self, address):
1037 """Instantiate a new IPv6 object.
1038
1039 Args:
1040 ipaddr: A string or integer representing the IP or the IP
1041 and prefix/netmask.
1042 '2001:4860::/128'
1043 '2001:4860:0000:0000:0000:0000:0000:0000/128'
1044 '2001:4860::'
1045 are all functionally the same in IPv6. That is to say,
1046 failing to provide a subnetmask will create an object with
1047 a mask of /128.
1048
1049 Additionally, an integer can be passed, so
1050 IPv6('2001:4860::') ==
1051 IPv6(42541956101370907050197289607612071936L).
1052 or, more generally
1053 IPv6(IPv6('2001:4860::').ip) == IPv6('2001:4860::')
1054
1055 Raises:
1056 IPv6IpValidationError: If ipaddr isn't a valid IPv6 address.
1057 IPv6NetmaskValidationError: If the netmask isn't valid for
1058 an IPv6 address.
1059 IPRangeError: If range of IP addresses is not valid.
1060
1061 """
1062 BaseIP.__init__(self)
1063 self._version = 6 1260 self._version = 6
1064 self._max_prefixlen = 128 1261 self._max_prefixlen = 128
1065 1262
1066 # Efficient constructor from integer. 1263 def _ip_int_from_string(self, ip_str=None):
1067 if isinstance(ipaddr, long) or isinstance(ipaddr, int): 1264 """Turn an IPv6 ip_str into an integer.
1068 self.ip = ipaddr 1265
1069 self._prefixlen = 128 1266 Args:
1070 self.netmask = self._ALL_ONES 1267 ip_str: A string, the IPv6 ip_str.
1071 if ipaddr < 0 or ipaddr > self._ALL_ONES: 1268
1072 raise IPv6IpValidationError(ipaddr) 1269 Returns:
1073 return 1270 A long, the IPv6 ip_str.
1074
1075 # Constructing from a packed address
1076 if _compat_has_real_bytes:
1077 if isinstance(ipaddr, bytes) and len(ipaddr) == 16:
1078 tmp = struct.unpack('!QQ', ipaddr)
1079 self.ip = (tmp[0] << 64) | tmp[1]
1080 self._prefixlen = 128
1081 self.netmask = self._ALL_ONES
1082 return
1083
1084 addr_str = str(ipaddr)
1085 if not addr_str:
1086 raise IPv6IpValidationError('')
1087
1088 # Construct network from a range e.g. ::-::15
1089 addr = addr_str.split('-')
1090
1091 if len(addr) > 2:
1092 raise IPv6IpValidationError(ipaddr)
1093
1094 if len(addr) == 2:
1095 if not self._is_valid_ip(addr[0]):
1096 raise IPv6IpValidationError(addr[0])
1097
1098 if not self._is_valid_ip(addr[1]):
1099 raise IPv6IpValidationError(addr[1])
1100
1101 self.ip = self._ip_int_from_string(addr[0])
1102
1103 last = self._ip_int_from_string(addr[1])
1104 if last < self.ip:
1105 raise IPRangeError("last address should be greater than "
1106 "first.")
1107 bits = _highest_one_bit(last - self.ip)
1108 self._prefixlen = self.max_prefixlen - bits
1109 self.netmask = self._ip_int_from_prefix(self._prefixlen)
1110 if self._ip_int_from_string(IPv6(self)[-1]) != last:
1111 raise IPRangeError("range %s is not on a network byte "
1112 "boundary." % ipaddr)
1113 return
1114
1115 # Assume input argument to be string or any object representation
1116 # which converts into a formatted IP prefix string.
1117 addr = addr_str.split('/')
1118 if len(addr) > 1:
1119 if self._is_valid_netmask(addr[1]):
1120 self._prefixlen = int(addr[1])
1121 else:
1122 raise IPv6NetmaskValidationError(addr[1])
1123 else:
1124 self._prefixlen = 128
1125
1126 self.netmask = self._ip_int_from_prefix(self._prefixlen)
1127
1128 if not self._is_valid_ip(addr[0]):
1129 raise IPv6IpValidationError(addr[0])
1130
1131 self.ip = self._ip_int_from_string(addr[0])
1132
1133 @property
1134 def ip_ext_full(self):
1135 """Returns the expanded version of the IPv6 string."""
1136 return self._explode_shorthand_ip_string(self.ip_ext)
1137
1138 def _set_prefix(self, prefixlen):
1139 """Change the prefix length.
1140
1141 Args:
1142 prefixlen: An integer, the new prefix length.
1143
1144 Raises:
1145 IPv6NetmaskValidationError: If prefixlen is out of bounds.
1146
1147 """
1148 if not 0 <= prefixlen <= 128:
1149 raise IPv6NetmaskValidationError(prefixlen)
1150 self._prefixlen = prefixlen
1151 self.netmask = self._ip_int_from_prefix(self.prefixlen)
1152
1153 def subnet(self, prefixlen_diff=1):
1154 """The subnets which join to make the current subnet.
1155
1156 In the case that self contains only one IP
1157 (self._prefixlen == 128), return a list with just ourself.
1158
1159 Args:
1160 prefixlen_diff: An integer, the amount the prefix length
1161 should be increased by.
1162
1163 Returns:
1164 A list of IPv6 objects.
1165
1166 Raises:
1167 PrefixlenDiffInvalidError: The prefixlen_diff is too small
1168 or too large.
1169
1170 """
1171 # Preserve original functionality (return [self] if
1172 # self.prefixlen == 128).
1173 if self.prefixlen == 128:
1174 return [self]
1175
1176 if prefixlen_diff < 0:
1177 raise PrefixlenDiffInvalidError('Prefix length diff must be > 0')
1178 new_prefixlen = self.prefixlen + prefixlen_diff
1179 if not self._is_valid_netmask(str(new_prefixlen)):
1180 raise PrefixlenDiffInvalidError(
1181 'Prefix length diff %d is invalid for netblock %s' % (
1182 new_prefixlen, str(self)))
1183 first = IPv6(
1184 self._string_from_ip_int(self.network) + '/' +
1185 str(self._prefixlen + prefixlen_diff))
1186 subnets = [first]
1187 current = first
1188 while True:
1189 broadcast = current.broadcast
1190 if current.broadcast == self.broadcast:
1191 break
1192 current = IPv6(self._string_from_ip_int(broadcast + 1) + '/' +
1193 str(new_prefixlen))
1194 subnets.append(current)
1195
1196 return subnets
1197
1198 def supernet(self, prefixlen_diff=1):
1199 """The supernet containing the current network.
1200
1201 Args:
1202 prefixlen_diff: An integer, the amount the prefix length of the
1203 network should be decreased by. For example, given a /96
1204 network and a prefixlen_diff of 3, a supernet with a /93
1205 netmask is returned.
1206
1207 Returns:
1208 An IPv6 object.
1209
1210 Raises:
1211 PrefixlenDiffInvalidError: If
1212 self._prefixlen - prefixlen_diff < 0. I.e., you have a
1213 negative prefix length.
1214
1215 """
1216 if self.prefixlen == 0:
1217 return self
1218 if self.prefixlen - prefixlen_diff < 0:
1219 raise PrefixlenDiffInvalidError(
1220 'current prefixlen is %d, cannot have a prefixlen_diff of %d' %
1221 (self.prefixlen, prefixlen_diff))
1222 return IPv6(self.ip_ext + '/' + str(self.prefixlen - prefixlen_diff))
1223
1224 @property
1225 def is_multicast(self):
1226 """Test if the address is reserved for multicast use.
1227
1228 Returns:
1229 A boolean, True if the address is a multicast address.
1230 See RFC 2373 2.7 for details.
1231
1232 """
1233 return self in IPv6('ff00::/8')
1234
1235 @property
1236 def is_unspecified(self):
1237 """Test if the address is unspecified.
1238
1239 Returns:
1240 A boolean, True if this is the unspecified address as defined in
1241 RFC 2373 2.5.2.
1242
1243 """
1244 return self == IPv6('::')
1245
1246 @property
1247 def is_loopback(self):
1248 """Test if the address is a loopback adddress.
1249
1250 Returns:
1251 A boolean, True if the address is a loopback address as defined in
1252 RFC 2373 2.5.3.
1253
1254 """
1255 return self == IPv6('::1')
1256
1257 @property
1258 def is_link_local(self):
1259 """Test if the address is reserved for link-local.
1260
1261 Returns:
1262 A boolean, True if the address is reserved per RFC 4291.
1263
1264 """
1265 return self in IPv6('fe80::/10')
1266
1267 @property
1268 def is_site_local(self):
1269 """Test if the address is reserved for site-local.
1270
1271 Note that the site-local address space has been deprecated by RFC 3879.
1272 Use is_private to test if this address is in the space of unique local
1273 addresses as defined by RFC 4193.
1274
1275 Returns:
1276 A boolean, True if the address is reserved per RFC 3513 2.5.6.
1277
1278 """
1279 return self in IPv6('fec0::/10')
1280
1281 @property
1282 def is_private(self):
1283 """Test if this address is allocated for private networks.
1284
1285 Returns:
1286 A boolean, True if the address is reserved per RFC 4193.
1287
1288 """
1289 return self in IPv6('fc00::/7')
1290
1291 @property
1292 def version(self):
1293 return self._version
1294
1295 @property
1296 def max_prefixlen(self):
1297 return self._max_prefixlen
1298
1299 @property
1300 def packed(self):
1301 """The binary representation of this address."""
1302 return struct.pack('!QQ', self.ip >> 64, self.ip & (2**64 - 1))
1303
1304 def _is_shorthand_ip(self, ip_str=None):
1305 """Determine if the address is shortened.
1306
1307 Args:
1308 ip_str: A string, the IPv6 address.
1309
1310 Returns:
1311 A boolean, True if the address is shortened.
1312
1313 """
1314 if ip_str.count('::') == 1:
1315 return True
1316 return False
1317
1318 def _explode_shorthand_ip_string(self, ip_str):
1319 """Expand a shortened IPv6 address.
1320
1321 Args:
1322 ip_str: A string, the IPv6 address.
1323
1324 Returns:
1325 A string, the expanded IPv6 address.
1326
1327 """
1328 if self._is_shorthand_ip(ip_str):
1329 new_ip = []
1330 hextet = ip_str.split('::')
1331 sep = len(hextet[0].split(':')) + len(hextet[1].split(':'))
1332 new_ip = hextet[0].split(':')
1333
1334 for _ in xrange(8 - sep):
1335 new_ip.append('0000')
1336 new_ip += hextet[1].split(':')
1337
1338 # Now need to make sure every hextet is 4 lower case characters.
1339 # If a hextet is < 4 characters, we've got missing leading 0's.
1340 ret_ip = []
1341 for hextet in new_ip:
1342 ret_ip.append(('0' * (4 - len(hextet)) + hextet).lower())
1343 return ':'.join(ret_ip)
1344 # We've already got a longhand ip_str.
1345 return ip_str
1346
1347 def _is_valid_ip(self, ip_str=None):
1348 """Ensure we have a valid IPv6 address.
1349
1350 Probably not as exhaustive as it should be.
1351
1352 Args:
1353 ip_str: A string, the IPv6 address.
1354
1355 Returns:
1356 A boolean, True if this is a valid IPv6 address.
1357 1271
1358 """ 1272 """
1359 if not ip_str: 1273 if not ip_str:
1360 ip_str = self.ip_ext 1274 ip_str = str(self.ip)
1361
1362 # We need to have at least one ':'.
1363 if ':' not in ip_str:
1364 return False
1365
1366 # We can only have one '::' shortener.
1367 if ip_str.count('::') > 1:
1368 return False
1369
1370 # '::' should be encompassed by start, digits or end.
1371 if ':::' in ip_str:
1372 return False
1373
1374 # A single colon can neither start nor end an address.
1375 if ((ip_str.startswith(':') and not ip_str.startswith('::')) or
1376 (ip_str.endswith(':') and not ip_str.endswith('::'))):
1377 return False
1378
1379 # If we have no concatenation, we need to have 8 fields with 7 ':'.
1380 if '::' not in ip_str and ip_str.count(':') != 7:
1381 # We might have an IPv4 mapped address.
1382 if ip_str.count('.') != 3:
1383 return False
1384
1385 ip_str = self._explode_shorthand_ip_string(ip_str)
1386
1387 # Now that we have that all squared away, let's check that each of the
1388 # hextets are between 0x0 and 0xFFFF.
1389 for hextet in ip_str.split(':'):
1390 if hextet.count('.') == 3:
1391 # If we have an IPv4 mapped address, the IPv4 portion has to be
1392 # at the end of the IPv6 portion.
1393 if not ip_str.split(':')[-1] == hextet:
1394 return False
1395 try:
1396 IPv4(hextet)
1397 except IPv4IpValidationError:
1398 return False
1399 elif int(hextet, 16) < 0x0 or int(hextet, 16) > 0xFFFF:
1400 return False
1401 return True
1402
1403 def _is_valid_netmask(self, prefixlen):
1404 """Verify that the netmask/prefixlen is valid.
1405
1406 Args:
1407 prefixlen: A string, the netmask in prefix length format.
1408
1409 Returns:
1410 A boolean, True if the prefix represents a valid IPv6
1411 netmask.
1412
1413 """
1414 try:
1415 prefixlen = int(prefixlen)
1416 except ValueError:
1417 return False
1418 return 0 <= prefixlen <= 128
1419
1420 def _ip_int_from_string(self, ip_str=None):
1421 """Turn an IPv6 address into an integer.
1422
1423 Args:
1424 ip_str: A string, the IPv6 address.
1425
1426 Returns:
1427 A long, the IPv6 address.
1428
1429 """
1430 if not ip_str:
1431 ip_str = self.ip_ext
1432 1275
1433 ip_int = 0 1276 ip_int = 0
1434 1277
1435 fields = self._explode_shorthand_ip_string(ip_str).split(':') 1278 fields = self._explode_shorthand_ip_string(ip_str).split(':')
1436 1279
1437 # Do we have an IPv4 mapped (::ffff:a.b.c.d) or compact (::a.b.c.d) 1280 # Do we have an IPv4 mapped (::ffff:a.b.c.d) or compact (::a.b.c.d)
1438 # address? 1281 # ip_str?
1439 if fields[-1].count('.') == 3: 1282 if fields[-1].count('.') == 3:
1440 ipv4_string = fields.pop() 1283 ipv4_string = fields.pop()
1441 ipv4_int = IPv4(ipv4_string).ip 1284 ipv4_int = IPv4(ipv4_string)._ip
1442 octets = [] 1285 octets = []
1443 for _ in xrange(2): 1286 for _ in xrange(2):
1444 octets.append(hex(ipv4_int & 0xFFFF).lstrip('0x').rstrip('L')) 1287 octets.append(hex(ipv4_int & 0xFFFF).lstrip('0x').rstrip('L'))
1445 ipv4_int >>= 16 1288 ipv4_int >>= 16
1446 fields.extend(reversed(octets)) 1289 fields.extend(reversed(octets))
1447 1290
1448 for field in fields: 1291 for field in fields:
1449 ip_int = (ip_int << 16) + int(field, 16) 1292 ip_int = (ip_int << 16) + int(field, 16)
1450 1293
1451 return ip_int 1294 return ip_int
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
1504 ip_int: An integer, the IP address. 1347 ip_int: An integer, the IP address.
1505 1348
1506 Returns: 1349 Returns:
1507 A string, the hexadecimal representation of the address. 1350 A string, the hexadecimal representation of the address.
1508 1351
1509 Raises: 1352 Raises:
1510 ValueError: The address is bigger than 128 bits of all ones. 1353 ValueError: The address is bigger than 128 bits of all ones.
1511 1354
1512 """ 1355 """
1513 if not ip_int and ip_int != 0: 1356 if not ip_int and ip_int != 0:
1514 ip_int = self.ip 1357 ip_int = int(self._ip)
1515 1358
1516 if ip_int > self._ALL_ONES: 1359 if ip_int > self._ALL_ONES:
1517 raise ValueError('IPv6 address is too large') 1360 raise ValueError('IPv6 address is too large')
1518 1361
1519 hex_str = '%032x' % ip_int 1362 hex_str = '%032x' % ip_int
1520 hextets = [] 1363 hextets = []
1521 for x in range(0, 32, 4): 1364 for x in range(0, 32, 4):
1522 hextets.append('%x' % int(hex_str[x:x+4], 16)) 1365 hextets.append('%x' % int(hex_str[x:x+4], 16))
1523 1366
1524 hextets = self._compress_hextets(hextets) 1367 hextets = self._compress_hextets(hextets)
1525 return ':'.join(hextets) 1368 return ':'.join(hextets)
1526 1369
1527 @property 1370 def _explode_shorthand_ip_string(self, ip_str=None):
1528 def netmask_ext(self): 1371 """Expand a shortened IPv6 address.
1529 """IPv6 extended netmask. 1372
1530 1373 Args:
1531 We don't deal with netmasks in IPv6 like we do in IPv4. This is 1374 ip_str: A string, the IPv6 address.
1532 here strictly for IPv4 compatibility. We simply return the 1375
1533 prefix length. 1376 Returns:
1534 1377 A string, the expanded IPv6 address.
1535 Returns: 1378
1536 An integer. 1379 """
1537 1380 if not ip_str: