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

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: 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 = [] 348 i = 0
268 # i = 0 349 addrs = []
269 # ip_bits = addresses[0].max_prefixlen 350 ips = []
270 # # filter out IP addresses, dedup, and sort 351 nets = []
271 # addrs = sorted(set([ip for ip in addresses if ip.prefixlen == ip_bits]), 352 # split IP addresses and networks
272 # key=BaseIP._get_networks_key) 353 for ip in addresses:
273 # nets = [ip for ip in addresses if ip.prefixlen < ip_bits] 354 if isinstance(ip, BaseIP):
274 # 355 ips.append(ip)
275 # while i < len(addrs): 356 elif ip._prefixlen == ip._max_prefixlen:
276 # (first, last) = _find_address_range(addrs[i:]) 357 ips.append(ip.ip)
277 # i = addrs.index(last) + 1 358 else:
278 # _addresses.extend( 359 nets.append(ip)
279 # [IP(ip) for ip in summarize_address_range(first, last)]) 360 # sort and dedup
280 # 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))
368
281 return _collapse_address_list_recursive( 369 return _collapse_address_list_recursive(
282 sorted(addresses, key=BaseIP._get_networks_key)) 370 sorted(addrs + nets, key=BaseNet._get_networks_key))
283 #sorted(_addresses + nets, key=BaseIP._get_networks_key))
284 371
285 # backwards compatibility 372 # backwards compatibility
286 CollapseAddrList = collapse_address_list 373 CollapseAddrList = collapse_address_list
287 374
288 # Test whether this Python implementation supports byte objects that 375 # Test whether this Python implementation supports byte objects that
289 # are not identical to str ones. 376 # are not identical to str ones.
290 # 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
291 # distinguish between packed representations and strings, for example 378 # distinguish between packed representations and strings, for example
292 # 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).
293 try: 380 try:
294 _compat_has_real_bytes = bytes != str 381 _compat_has_real_bytes = bytes != str
295 except NameError: # <Python2.6 382 except NameError: # <Python2.6
296 _compat_has_real_bytes = False 383 _compat_has_real_bytes = False
297 384
298 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):
299 401
300 """A generic IP object. 402 """A generic IP object.
301 403
302 This IP class contains most of the methods which are used by 404 This IP class contains the version independent methods which are
303 the IPv4 and IPv6 classes. 405 used by single IP addresses.
304 406
305 """ 407 """
306 408
307 def __getitem__(self, n): 409 @property
308 if n >= 0: 410 def exploded(self):
309 if self.network + n > self.broadcast: 411 return self._explode_shorthand_ip_string()
310 raise IndexError 412
311 return self._string_from_ip_int(self.network + n) 413 @property
312 else: 414 def compressed(self):
313 n += 1 415 return str(self)
314 if self.broadcast + n < self.network: 416
315 raise IndexError 417 def __init__(self, address):
316 return self._string_from_ip_int(self.broadcast + n) 418 if '/' in str(address):
317 419 raise IPAddressIPValidationError(address)
318 def __lt__(self, other):
319 try:
320 return (self.version < other.version
321 or self.ip < other.ip
322 or self.netmask < other.netmask)
323 except AttributeError:
324 return NotImplemented
325
326 def __gt__(self, other):
327 try:
328 return (self.version > other.version
329 or self.ip > other.ip
330 or self.netmask > other.netmask)
331 except AttributeError:
332 return NotImplemented
333 420
334 def __eq__(self, other): 421 def __eq__(self, other):
335 try: 422 try:
336 return (self.version == other.version 423 return not (self._ip != other._ip
337 and self.ip == other.ip 424 or self._version != other._version)
338 and self.netmask == other.netmask)
339 except AttributeError: 425 except AttributeError:
340 return NotImplemented 426 return NotImplemented
341 427
342 def __ne__(self, other): 428 def __ne__(self, other):
343 eq = self.__eq__(other) 429 eq = self.__eq__(other)
344 if eq is NotImplemented: 430 if eq is NotImplemented:
345 return NotImplemented 431 return NotImplemented
346 return not eq 432 return not eq
347 433
348 def __le__(self, other): 434 def __le__(self, other):
349 gt = self.__gt__(other) 435 gt = self.__gt__(other)
350 if gt is NotImplemented: 436 if gt is NotImplemented:
351 return NotImplemented 437 return NotImplemented
352 return not gt 438 return not gt
353 439
354 def __ge__(self, other): 440 def __ge__(self, other):
355 lt = self.__lt__(other) 441 lt = self.__lt__(other)
356 if lt is NotImplemented: 442 if lt is NotImplemented:
357 return NotImplemented 443 return NotImplemented
358 return not lt 444 return not lt
359 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
360 def __repr__(self): 460 def __repr__(self):
361 return '%s(%r)' % (self.__class__.__name__, str(self)) 461 return '%s(%r)' % (self.__class__.__name__, str(self))
362 462
363 def __index__(self): 463 def __str__(self):
364 return self.ip 464 return '%s' % self._string_from_ip_int(self._ip)
365 465
366 def __int__(self): 466 def __hash__(self):
367 return self.ip 467 return hash(self._ip)
368 468
369 def __hex__(self): 469 @property
370 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))
371 629
372 def address_exclude(self, other): 630 def address_exclude(self, other):
373 """Remove an address from a larger block. 631 """Remove an address from a larger block.
374 632
375 For example: 633 For example:
376 634
377 addr1 = IP('10.1.1.0/24') 635 addr1 = IP('10.1.1.0/24')
378 addr2 = IP('10.1.1.0/26') 636 addr2 = IP('10.1.1.0/26')
379 addr1.address_exclude(addr2) = 637 addr1.address_exclude(addr2) =
380 [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
399 657
400 Raises: 658 Raises:
401 IPTypeError: If self and other are of difffering address 659 IPTypeError: If self and other are of difffering address
402 versions. 660 versions.
403 IPAddressExclusionError: There was some unknown error in the 661 IPAddressExclusionError: There was some unknown error in the
404 address exclusion process. This likely points to a bug 662 address exclusion process. This likely points to a bug
405 elsewhere in this code. 663 elsewhere in this code.
406 ValueError: If other is not completely contained by self. 664 ValueError: If other is not completely contained by self.
407 665
408 """ 666 """
409 if not self.version == other.version: 667 if not self._version == other._version:
410 raise IPTypeError("%s and %s aren't of the same version" % ( 668 raise IPTypeError("%s and %s aren't of the same version" % (
411 str(self), str(other))) 669 str(self), str(other)))
412 670
413 if other not in self: 671 if other not in self:
414 raise ValueError('%s not contained in %s' % (str(other), 672 raise ValueError('%s not contained in %s' % (str(other),
415 str(self))) 673 str(self)))
416
417 ret_addrs = [] 674 ret_addrs = []
418 675
419 # Make sure we're comparing the network of other. 676 # Make sure we're comparing the network of other.
420 other = IP(other.network_ext + '/' + str(other.prefixlen)) 677 other = IP('%s/%s' % (str(other.network), str(other.prefixlen)),
678 version=other._version)
421 679
422 s1, s2 = self.subnet() 680 s1, s2 = self.subnet()
423 while s1 != other and s2 != other: 681 while s1 != other and s2 != other:
424 if other in s1: 682 if other in s1:
425 ret_addrs.append(s2) 683 ret_addrs.append(s2)
426 s1, s2 = s1.subnet() 684 s1, s2 = s1.subnet()
427 elif other in s2: 685 elif other in s2:
428 ret_addrs.append(s1) 686 ret_addrs.append(s1)
429 s1, s2 = s2.subnet() 687 s1, s2 = s2.subnet()
430 else: 688 else:
431 # If we got here, there's a bug somewhere. 689 # If we got here, there's a bug somewhere.
432 raise IPAddressExclusionError('Error performing exclusion: ' 690 raise IPAddressExclusionError('Error performing exclusion: '
433 's1: %s s2: %s other: %s' % 691 's1: %s s2: %s other: %s' %
434 (str(s1), str(s2), str(other))) 692 (str(s1), str(s2), str(other)))
435 if s1 == other: 693 if s1 == other:
436 ret_addrs.append(s2) 694 ret_addrs.append(s2)
437 elif s2 == other: 695 elif s2 == other:
438 ret_addrs.append(s1) 696 ret_addrs.append(s1)
439 else: 697 else:
440 # If we got here, there's a bug somewhere. 698 # If we got here, there's a bug somewhere.
441 raise IPAddressExclusionError('Error performing exclusion: ' 699 raise IPAddressExclusionError('Error performing exclusion: '
442 's1: %s s2: %s other: %s' % 700 's1: %s s2: %s other: %s' %
443 (str(s1), str(s2), str(other))) 701 (str(s1), str(s2), str(other)))
444 702
445 return sorted(ret_addrs, key=BaseIP._get_networks_key) 703 return sorted(ret_addrs, key=BaseNet._get_networks_key)
446 704
447 def compare_networks(self, other): 705 def compare_networks(self, other):
448 """Compare two IP objects. 706 """Compare two IP objects.
449 707
450 This is only concerned about the comparison of the integer 708 This is only concerned about the comparison of the integer
451 representation of the network addresses. This means that the 709 representation of the network addresses. This means that the
452 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
453 to compare host bits, you can easily enough do a 711 to compare host bits, you can easily enough do a
454 'HostA.ip < HostB.ip' 712 'HostA._ip < HostB._ip'
455 713
456 Args: 714 Args:
457 other: An IP object. 715 other: An IP object.
458 716
459 Returns: 717 Returns:
460 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:
461 719
462 -1 if self < other: 720 -1 if self < other:
463 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')
464 IPv6('1080::200C:417A') < IPv6('1080::200B:417B') 722 IPv6('1080::200C:417A') < IPv6('1080::200B:417B')
465 0 if self == other 723 0 if self == other
466 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')
467 IPv6('1080::200C:417A/96') == IPv6('1080::200C:417B/96') 725 IPv6('1080::200C:417A/96') == IPv6('1080::200C:417B/96')
468 1 if self > other 726 1 if self > other
469 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')
470 IPv6('1080::1:200C:417A/112') > 728 IPv6('1080::1:200C:417A/112') >
471 IPv6('1080::0:200C:417A/112') 729 IPv6('1080::0:200C:417A/112')
472 730
473 If the IP versions of self and other are different, returns: 731 If the IP versions of self and other are different, returns:
474 732
475 -1 if self.version < other.version 733 -1 if self._version < other._version
476 eg: IPv4('10.0.0.1/24') < IPv6('::1/128') 734 eg: IPv4('10.0.0.1/24') < IPv6('::1/128')
477 1 if self.version > other.version 735 1 if self._version > other._version
478 eg: IPv6('::1/128') > IPv4('255.255.255.0/24') 736 eg: IPv6('::1/128') > IPv4('255.255.255.0/24')
479 737
480 """ 738 """
481 if self.version < other.version: 739 if self._version < other._version:
482 return -1 740 return -1
483 if self.version > other.version: 741 if self._version > other._version:
484 return 1 742 return 1
485 # self.version == other.version below here: 743 # self._version == other._version below here:
486 if self.network < other.network: 744 if self.network < other.network:
487 return -1 745 return -1
488 if self.network > other.network: 746 if self.network > other.network:
489 return 1 747 return 1
490 # self.network == other.network below here: 748 # self.network == other.network below here:
491 if self.netmask < other.netmask: 749 if self.netmask < other.netmask:
492 return -1 750 return -1
493 if self.netmask > other.netmask: 751 if self.netmask > other.netmask:
494 return 1 752 return 1
495 # self.network == other.network and self.netmask == other.netmask 753 # self.network == other.network and self.netmask == other.netmask
496 return 0 754 return 0
497 755
498 def _get_networks_key(self): 756 def _get_networks_key(self):
499 """Network-only key function. 757 """Network-only key function.
500 758
501 Returns an object that identifies this address' network and 759 Returns an object that identifies this address' network and
502 netmask. This function is a suitable "key" argument for sorted() 760 netmask. This function is a suitable "key" argument for sorted()
503 and list.sort(). 761 and list.sort().
504 762
505 """ 763 """
506 return (self.version, self.network, self.netmask) 764 return (self._version, self.network, self.netmask)
507
508 prefixlen = property(
509 fget=lambda self: self._prefixlen,
510 fset=lambda self, prefixlen: self._set_prefix(prefixlen))
511
512 def __str__(self):
513 return '%s/%s' % (self._string_from_ip_int(self.ip),
514 str(self.prefixlen))
515
516 def __hash__(self):
517 return hash(self.ip ^ self.netmask)
518
519 def __contains__(self, other):
520 return self.network <= other.ip and self.broadcast >= other.broadcast
521
522 @property
523 def ip_ext(self):
524 """Dotted decimal or colon string version of the IP address."""
525 return self._string_from_ip_int(self.ip)
526
527 @property
528 def ip_ext_full(self):
529 """Canonical string version of the IP address."""
530 return self.ip_ext
531
532 @property
533 def broadcast(self):
534 """Integer representation of the broadcast address."""
535 return self.ip | self.hostmask
536
537 @property
538 def broadcast_ext(self):
539 """Dotted decimal or colon string version of the broadcast."""
540 return self._string_from_ip_int(self.broadcast)
541
542 @property
543 def hostmask(self):
544 """Integer representation of the hostmask."""
545 return self.netmask ^ self._ALL_ONES
546
547 @property
548 def hostmask_ext(self):
549 """Dotted decimal or colon string version of the hostmask."""
550 return self._string_from_ip_int(self.hostmask)
551
552 @property
553 def network(self):
554 """Integer representation of the network."""
555 return self.ip & self.netmask
556
557 @property
558 def network_ext(self):
559 """Dotted decimal or colon string version of the network."""
560 return self._string_from_ip_int(self.network)
561
562 @property
563 def netmask_ext(self):
564 """Dotted decimal or colon string version of the netmask."""
565 return self._string_from_ip_int(self.netmask)
566
567 @property
568 def numhosts(self):
569 """Number of hosts in the current subnet."""
570 return self.broadcast - self.network + 1
571
572 @property
573 def version(self):
574 raise NotImplementedError('BaseIP has no version')
575 765
576 def _ip_int_from_prefix(self, prefixlen=None): 766 def _ip_int_from_prefix(self, prefixlen=None):
577 """Turn the prefix length netmask into a int for comparison. 767 """Turn the prefix length netmask into a int for comparison.
578 768
579 Args: 769 Args:
580 prefixlen: An integer, the prefix length. 770 prefixlen: An integer, the prefix length.
581 771
582 Returns: 772 Returns:
583 An integer. 773 An integer.
584 774
585 """ 775 """
586 if not prefixlen and prefixlen != 0: 776 if not prefixlen and prefixlen != 0:
587 prefixlen = self.prefixlen 777 prefixlen = self._prefixlen
588 return self._ALL_ONES ^ (self._ALL_ONES >> prefixlen) 778 return self._ALL_ONES ^ (self._ALL_ONES >> prefixlen)
589 779
590 def _prefix_from_ip_int(self, ip_int, mask=32): 780 def _prefix_from_ip_int(self, ip_int, mask=32):
591 """Return prefix length from the decimal netmask. 781 """Return prefix length from the decimal netmask.
592 782
593 Args: 783 Args:
594 ip_int: An integer, the IP address. 784 ip_int: An integer, the IP address.
595 mask: The netmask. Defaults to 32. 785 mask: The netmask. Defaults to 32.
596 786
597 Returns: 787 Returns:
(...skipping 12 matching lines...) Expand all
610 """Turn a prefix length into a dotted decimal string. 800 """Turn a prefix length into a dotted decimal string.
611 801
612 Args: 802 Args:
613 prefixlen: An integer, the netmask prefix length. 803 prefixlen: An integer, the netmask prefix length.
614 804
615 Returns: 805 Returns:
616 A string, the dotted decimal netmask string. 806 A string, the dotted decimal netmask string.
617 807
618 """ 808 """
619 if not prefixlen: 809 if not prefixlen:
620 prefixlen = self.prefixlen 810 prefixlen = self._prefixlen
621 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))
622 812
623 # backwards compatibility 813 # backwards compatibility
624 AddressExclude = address_exclude 814 AddressExclude = address_exclude
625 CompareNetworks = compare_networks 815 CompareNetworks = compare_networks
626 Contains = __contains__ 816 Contains = __contains__
627 def set_prefix(self, prefixlen): self.prefixlen = prefixlen 817 def set_prefix(self, prefixlen): self.prefixlen = prefixlen
628 SetPrefix = set_prefix 818 SetPrefix = set_prefix
629 def get_prefix(self): return self.prefixlen 819 def get_prefix(self): return self.prefixlen
630 820
631 821
632 class IPv4(BaseIP): 822 class BaseV4(object):
633 823
634 """This class represents and manipulates 32-bit IPv4 addresses. 824 """Base IPv4 object.
635 825
636 Attributes: [examples for IPv4('1.2.3.4/27')] 826 The following methods are used by IPv4 objects in both single IP
637 .ip: 16909060 827 addresses and networks.
638 .ip_ext: '1.2.3.4'
639 .ip_ext_full: '1.2.3.4'
640 .network: 16909056L
641 .network_ext: '1.2.3.0'
642 .hostmask: 31L (0x1F)
643 .hostmask_ext: '0.0.0.31'
644 .broadcast: 16909087L (0x102031F)
645 .broadcast_ext: '1.2.3.31'
646 .netmask: 4294967040L (0xFFFFFFE0)
647 .netmask_ext: '255.255.255.224'
648 .prefixlen: 27
649 828
650 """ 829 """
651 830
652 # 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.
653 _ALL_ONES = (2**32) - 1 832 _ALL_ONES = (2**32) - 1
654 833
655 def __init__(self, ipaddr): 834 def __init__(self, address):
656 """Instantiate a new IPv4 object. 835 self._version = 4
657 836 self._max_prefixlen = 32
658 Args: 837
659 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].
660 '192.168.1.1/32' 984 '192.168.1.1/32'
661 '192.168.1.1/255.255.255.255' 985 '192.168.1.1/255.255.255.255'
662 '192.168.1.1/0.0.0.255' 986 '192.168.1.1/0.0.0.255'
663 '192.168.1.1' 987 '192.168.1.1'
664 '192.168.1.0-192.168.1.0'
665 are all functionally the same in IPv4. That is to say, 988 are all functionally the same in IPv4. That is to say,
666 failing to provide a subnetmask will create an object with 989 failing to provide a subnetmask will create an object with
667 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
668 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
669 other netmasks can be expressed both as host- and 992 other netmasks can be expressed both as host- and
670 net-masks. (255.0.0.0 == 0.255.255.255) 993 net-masks. (255.0.0.0 == 0.255.255.255)
671 994
672 Additionally, an integer can be passed, so 995 Additionally, an integer can be passed, so
673 IPv4('192.168.1.1') == IPv4(3232235777). 996 IPv4Network('192.168.1.1') == IPv4Network(3232235777).
674 or, more generally 997 or, more generally
675 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')
676 1000
677 Raises: 1001 Raises:
678 IPv4IpValidationError: If ipaddr isn't a valid IPv4 address. 1002 IPv4IpValidationError: If ipaddr isn't a valid IPv4 address.
679 IPv4NetmaskValidationError: If the netmask isn't valid for 1003 IPv4NetmaskValidationError: If the netmask isn't valid for
680 an IPv4 address. 1004 an IPv4 address.
681 IPRangeError: If range of IP addresses is not valid. 1005
682 1006 """
683 """ 1007 BaseNet.__init__(self, address)
684 BaseIP.__init__(self) 1008 BaseV4.__init__(self, address)
685 self._version = 4
686 self._max_prefixlen = 32
687 1009
688 # Efficient constructor from integer. 1010 # Efficient constructor from integer.
689 if isinstance(ipaddr, int) or isinstance(ipaddr, long): 1011 if isinstance(address, int) or isinstance(address, long):
690 self.ip = ipaddr 1012 self._ip = address
1013 self.ip = IPv4Address(self._ip)
691 self._prefixlen = 32 1014 self._prefixlen = 32
692 self.netmask = self._ALL_ONES 1015 self.netmask = IPv4Address(self._ALL_ONES)
693 if ipaddr < 0 or ipaddr > self._ALL_ONES: 1016 if address < 0 or address > self._ALL_ONES:
694 raise IPv4IpValidationError(ipaddr) 1017 raise IPv4IpValidationError(address)
695 return 1018 return
696 1019
697 # Constructing from a packed address 1020 # Constructing from a packed address
698 if _compat_has_real_bytes: 1021 if _compat_has_real_bytes:
699 if isinstance(ipaddr, bytes) and len(ipaddr) == 4: 1022 if isinstance(address, bytes) and len(address) == 4:
700 self.ip = struct.unpack('!I', ipaddr)[0] 1023 self._ip = struct.unpack('!I', address)[0]
1024 self.ip = IPv4Address(self._ip)
701 self._prefixlen = 32 1025 self._prefixlen = 32
702 self.netmask = self._ALL_ONES 1026 self.netmask = IPv4Address(self._ALL_ONES)
703 return 1027 return
704
705 # Construct network from a range e.g. 1.1.1.0-1.1.1.255
706 addr = str(ipaddr).split('-')
707
708 if len(addr) > 2:
709 raise IPv4IpValidationError(ipaddr)
710
711 if len(addr) == 2:
712 if not self._is_valid_ip(addr[0]):
713 raise IPv4IpValidationError(addr[0])
714
715 if not self._is_valid_ip(addr[1]):
716 raise IPv4IpValidationError(addr[1])
717
718 self.ip = self._ip_int_from_string(addr[0])
719
720 last = self._ip_int_from_string(addr[1])
721 if last < self.ip:
722 raise IPRangeError("last address should be greater than "
723 "first.")
724 bits = _highest_one_bit(last - self.ip)
725 self._prefixlen = self.max_prefixlen - bits
726 self.netmask = self._ip_int_from_prefix(self._prefixlen)
727 if self.broadcast != last:
728 raise IPRangeError("range %s is not on a network byte "
729 "boundary." % ipaddr)
730 return
731 1028
732 # Assume input argument to be string or any object representation 1029 # Assume input argument to be string or any object representation
733 # which converts into a formatted IP prefix string. 1030 # which converts into a formatted IP prefix string.
734 addr = str(ipaddr).split('/') 1031 addr = str(address).split('/')
735 1032
736 if len(addr) > 2: 1033 if len(addr) > 2:
737 raise IPv4IpValidationError(ipaddr) 1034 raise IPv4IpValidationError(address)
738 1035
739 if not self._is_valid_ip(addr[0]): 1036 if not self._is_valid_ip(addr[0]):
740 raise IPv4IpValidationError(addr[0]) 1037 raise IPv4IpValidationError(addr[0])
741 1038
742 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)
743 1041
744 if len(addr) == 2: 1042 if len(addr) == 2:
745 mask = addr[1].split('.') 1043 mask = addr[1].split('.')
746 if len(mask) == 4: 1044 if len(mask) == 4:
747 # We have dotted decimal netmask. 1045 # We have dotted decimal netmask.
748 if not self._is_valid_netmask(addr[1]): 1046 if not self._is_valid_netmask(addr[1]):
749 raise IPv4NetmaskValidationError(addr[1]) 1047 raise IPv4NetmaskValidationError(addr[1])
750 if self._is_hostmask(addr[1]): 1048 if self._is_hostmask(addr[1]):
751 self.netmask = ( 1049 self.netmask = IPv4Address(
752 self._ip_int_from_string(addr[1]) ^ self._ALL_ONES) 1050 self._ip_int_from_string(addr[1]) ^ self._ALL_ONES)
753 else: 1051 else:
754 self.netmask = self._ip_int_from_string(addr[1]) 1052 self.netmask = IPv4Address(self._ip_int_from_string(
755 self._prefixlen = self._prefix_from_ip_int(self.netmask) 1053 addr[1]))
1054
1055 self._prefixlen = self._prefix_from_ip_int(int(self.netmask))
756 else: 1056 else:
757 # We have a netmask in prefix length form. 1057 # We have a netmask in prefix length form.
758 if not self._is_valid_netmask(addr[1]): 1058 if not self._is_valid_netmask(addr[1]):
759 raise IPv4NetmaskValidationError(addr[1]) 1059 raise IPv4NetmaskValidationError(addr[1])
760 self._prefixlen = int(addr[1]) 1060 self._prefixlen = int(addr[1])
761 self.netmask = self._ip_int_from_prefix(self._prefixlen) 1061 self.netmask = IPv4Address(self._ip_int_from_prefix(
1062 self._prefixlen))
762 else: 1063 else:
763 self._prefixlen = 32 1064 self._prefixlen = 32
764 self.netmask = self._ip_int_from_prefix(self._prefixlen) 1065 self.netmask = IPv4Address(self._ip_int_from_prefix(
1066 self._prefixlen))
1067
765 1068
766 def _set_prefix(self, prefixlen): 1069 def _set_prefix(self, prefixlen):
767 """Change the prefix length. 1070 """Change the prefix length of an IPv4 network object.
768 1071
769 Args: 1072 Args:
770 prefixlen: An integer, the new prefix length. 1073 prefixlen: An integer, the new prefix length.
771 1074
772 Raises: 1075 Raises:
773 IPv4NetmaskValidationError: If prefixlen is out of bounds. 1076 IPv4NetmaskValidationError: If prefixlen is out of bounds.
774 1077
775 """ 1078 """
776 if not 0 <= prefixlen <= 32: 1079 if not 0 <= prefixlen <= 32:
777 raise IPv4NetmaskValidationError(prefixlen) 1080 raise IPv4NetmaskValidationError(prefixlen)
778 self._prefixlen = prefixlen 1081 self._prefixlen = prefixlen
779 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
780 1087
781 def subnet(self, prefixlen_diff=1): 1088 def subnet(self, prefixlen_diff=1):
782 """The subnets which join to make the current subnet. 1089 """The subnets which join to make the current subnet.
783 1090
784 In the case that self contains only one IP 1091 In the case that self contains only one IP
785 (self._prefixlen == 32), return a list with just ourself. 1092 (self._prefixlen == 32), return a list with just ourself.
786 1093
787 Args: 1094 Args:
788 prefixlen_diff: An integer, the amount the prefix length 1095 prefixlen_diff: An integer, the amount the prefix length
789 should be increased by. Given a /24 network and a 1096 should be increased by. Given a /24 network and a
790 prefixlen_diff of 3, for example, 8 subnets of size /27 1097 prefixlen_diff of 3, for example, 8 subnets of size /27
791 will be returned. The default value of 1 splits the 1098 will be returned. The default value of 1 splits the
792 current network into two halves. 1099 current network into two halves.
793 1100
794 Returns: 1101 Returns:
795 A list of IPv4 objects. 1102 A list of IPv4 network objects.
796 1103
797 Raises: 1104 Raises:
798 PrefixlenDiffInvalidError: The prefixlen_diff is too small 1105 PrefixlenDiffInvalidError: The prefixlen_diff is too small
799 or too large. 1106 or too large.
800 1107
801 """ 1108 """
802 if self._prefixlen == 32: 1109 if self._prefixlen == 32:
803 return [self] 1110 return [self]
804 1111
805 if prefixlen_diff < 0: 1112 if prefixlen_diff < 0:
806 raise PrefixlenDiffInvalidError('prefix length diff must be > 0') 1113 raise PrefixlenDiffInvalidError('prefix length diff must be > 0')
807 new_prefixlen = self.prefixlen + prefixlen_diff 1114 new_prefixlen = self._prefixlen + prefixlen_diff
808 1115
809 if not self._is_valid_netmask(str(new_prefixlen)): 1116 if not self._is_valid_netmask(str(new_prefixlen)):
810 raise PrefixlenDiffInvalidError( 1117 raise PrefixlenDiffInvalidError(
811 'prefix length diff %d is invalid for netblock %s' % ( 1118 'prefix length diff %d is invalid for netblock %s' % (
812 new_prefixlen, str(self))) 1119 new_prefixlen, str(self)))
813 1120
814 first = IPv4( 1121 first = IPv4('%s/%s' % (str(self.network),
815 self._string_from_ip_int(self.network) + '/' + 1122 str(self._prefixlen + prefixlen_diff)))
816 str(self._prefixlen + prefixlen_diff))
817 subnets = [first] 1123 subnets = [first]
818 current = first 1124 current = first
819 while True: 1125 while True:
820 broadcast = current.broadcast 1126 broadcast = current.broadcast
821 if broadcast == self.broadcast: 1127 if broadcast == self.broadcast:
822 break 1128 break
823 current = IPv4(self._string_from_ip_int(broadcast + 1) + '/' + 1129 current = IPv4('%d/%s' % (int(broadcast) + 1, str(new_prefixlen)))
824 str(new_prefixlen))
825 subnets.append(current) 1130 subnets.append(current)
826 1131
827 return subnets 1132 return subnets
828 1133
829 def supernet(self, prefixlen_diff=1): 1134 def supernet(self, prefixlen_diff=1):
830 """The supernet containing the current network. 1135 """The supernet containing the current network.
831 1136
832 Args: 1137 Args:
833 prefixlen_diff: An integer, the amount the prefix length of 1138 prefixlen_diff: An integer, the amount the prefix length of
834 the network should be decreased by. For example, given a 1139 the network should be decreased by. For example, given a
835 /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
836 /21 netmask is returned. 1141 /21 netmask is returned.
837 1142
838 Returns: 1143 Returns:
839 An IPv4 object. 1144 An IPv4 network object.
840 1145
841 Raises: 1146 Raises:
842 PrefixlenDiffInvalidError: If 1147 PrefixlenDiffInvalidError: If
843 self.prefixlen - prefixlen_diff < 0. I.e., you have a 1148 self.prefixlen - prefixlen_diff < 0. I.e., you have a
844 negative prefix length. 1149 negative prefix length.
845 1150
846 """ 1151 """
847 if self.prefixlen == 0: 1152 if self._prefixlen == 0:
848 return self 1153 return self
849 if self.prefixlen - prefixlen_diff < 0: 1154 if self.prefixlen - prefixlen_diff < 0:
850 raise PrefixlenDiffInvalidError( 1155 raise PrefixlenDiffInvalidError(
851 'current prefixlen is %d, cannot have a prefixlen_diff of %d' % 1156 'current prefixlen is %d, cannot have a prefixlen_diff of %d' %
852 (self.prefixlen, prefixlen_diff)) 1157 (self.prefixlen, prefixlen_diff))
853 return IPv4(self.ip_ext + '/' + str(self.prefixlen - prefixlen_diff)) 1158 return IPv4('%s/%s' % (str(self.network),
1159 str(self.prefixlen - prefixlen_diff)))
854 1160
855 @property 1161 @property
856 def is_private(self): 1162 def is_private(self):
857 """Test if this address is allocated for private networks. 1163 """Test if this address is allocated for private networks.
858 1164
859 Returns: 1165 Returns:
860 A boolean, True if the address is reserved per RFC 1918. 1166 A boolean, True if the address is reserved per RFC 1918.
861 1167
862 """ 1168 """
863 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
887 1193
888 @property 1194 @property
889 def is_link_local(self): 1195 def is_link_local(self):
890 """Test if the address is reserved for link-local. 1196 """Test if the address is reserved for link-local.
891 1197
892 Returns: 1198 Returns:
893 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.
894 1200
895 """ 1201 """
896 return self in IPv4('169.254.0.0/16') 1202 return self in IPv4('169.254.0.0/16')
897
898 @property
899 def version(self):
900 return self._version
901
902 @property
903 def max_prefixlen(self):
904 return self._max_prefixlen
905
906 @property
907 def packed(self):
908 """The binary representation of this address."""
909 return struct.pack('!I', self.ip)
910 1203
911 def _is_hostmask(self, ip_str): 1204 def _is_hostmask(self, ip_str):
912 """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).
913 1206
914 Args: 1207 Args:
915 ip_str: A string, the potential hostmask. 1208 ip_str: A string, the potential hostmask.
916 1209
917 Returns: 1210 Returns:
918 A boolean, True if the IP string is a hostmask. 1211 A boolean, True if the IP string is a hostmask.
919 1212
920 """ 1213 """
921 parts = [int(x) for x in ip_str.split('.')] 1214 parts = [int(x) for x in ip_str.split('.')]
922 if parts[0] < parts[-1]: 1215 if parts[0] < parts[-1]:
923 return True 1216 return True
924 return False 1217 return False
925
926 def _ip_int_from_string(self, ip_str):
927 """Turn the given IP string into an integer for comparison.
928
929 Args:
930 ip_str: A string, the IP address.
931
932 Returns:
933 The IP address as an integer.
934
935 """
936 packed_ip = 0
937 for oc in ip_str.split('.'):
938 packed_ip = (packed_ip << 8) | int(oc)
939 return packed_ip
940
941 def _string_from_ip_int(self, ip_int):
942 """Turns a 32-bit integer into dotted decimal notation.
943
944 Args:
945 ip_int: An integer, the IP address.
946
947 Returns:
948 The IP address as a string in dotted decimal notation.
949
950 """
951 octets = []
952 for _ in xrange(4):
953 octets.insert(0, str(ip_int & 0xFF))
954 ip_int >>= 8
955 return '.'.join(octets)
956
957 def _is_valid_ip(self, ip_str):
958 """Validate the dotted decimal notation IP/netmask string.
959
960 Args:
961 ip_str: A string, the IP address.
962
963 Returns:
964 A boolean, True if the string is a valid dotted decimal IP
965 string.
966
967 """
968 octets = ip_str.split('.')
969 if len(octets) == 1:
970 # We have an integer rather than a dotted decimal IP.
971 try:
972 return int(ip_str) >= 0 and int(ip_str) <= self._ALL_ONES
973 except ValueError:
974 return False
975
976 if len(octets) != 4:
977 return False
978
979 for octet in octets:
980 try:
981 if not 0 <= int(octet) <= 255:
982 return False
983 except ValueError:
984 return False
985 return True
986 1218
987 def _is_valid_netmask(self, netmask): 1219 def _is_valid_netmask(self, netmask):
988 """Verify that the netmask is valid. 1220 """Verify that the netmask is valid.
989 1221
990 Args: 1222 Args:
991 netmask: A string, either a prefix or dotted decimal 1223 netmask: A string, either a prefix or dotted decimal
992 netmask. 1224 netmask.
993 1225
994 Returns: 1226 Returns:
995 A boolean, True if the prefix represents a valid IPv4 1227 A boolean, True if the prefix represents a valid IPv4
996 netmask. 1228 netmask.
997 1229
998 """ 1230 """
999 if len(netmask.split('.')) == 4: 1231 if len(netmask.split('.')) == 4:
1000 return self._is_valid_ip(netmask) 1232 return self._is_valid_ip(netmask)
1001 try: 1233 try:
1002 netmask = int(netmask) 1234 netmask = int(netmask)
1003 except ValueError: 1235 except ValueError:
1004 return False 1236 return False
1005 return 0 <= netmask <= 32 1237 return 0 <= netmask <= 32
1006 1238
1007 # backwards compatibility 1239 # backwards compatibility
1008 Subnet = subnet 1240 Subnet = subnet
1009 Supernet = supernet 1241 Supernet = supernet
1010 IsRFC1918 = lambda self: self.is_private 1242 IsRFC1918 = lambda self: self.is_private
1011 IsMulticast = lambda self: self.is_multicast 1243 IsMulticast = lambda self: self.is_multicast
1012 IsLoopback = lambda self: self.is_loopback 1244 IsLoopback = lambda self: self.is_loopback
1013 IsLinkLocal = lambda self: self.is_link_local 1245 IsLinkLocal = lambda self: self.is_link_local
1014 1246
1015 class IPv6(BaseIP): 1247
1016 1248 class BaseV6(object):
1017 """This class respresents and manipulates 128-bit IPv6 addresses. 1249
1018 1250 """Base IPv6 object.
1019 Attributes: [examples for IPv6('2001:658:22A:CAFE:200::1/64')] 1251
1020 .ip: 42540616829182469433547762482097946625L 1252 The following methods are used by IPv6 objects in both single IP
1021 .ip_ext: '2001:658:22a:cafe:200::1' 1253 addresses and networks.
1022 .ip_ext_full: '2001:0658:022a:cafe:0200:0000:0000:0001'
1023 .network: 42540616829182469433403647294022090752L
1024 .network_ext: '2001:658:22a:cafe::'
1025 .hostmask: 18446744073709551615L
1026 .hostmask_ext: '::ffff:ffff:ffff:ffff'
1027 .broadcast: 42540616829182469451850391367731642367L
1028 .broadcast_ext: '2001:658:22a:cafe:ffff:ffff:ffff:ffff'
1029 .netmask: 340282366920938463444927863358058659840L
1030 .netmask_ext: 64
1031 .prefixlen: 64
1032 1254
1033 """ 1255 """
1034 1256
1035 _ALL_ONES = (2**128) - 1 1257 _ALL_ONES = (2**128) - 1
1036 1258
1037 def __init__(self, ipaddr): 1259 def __init__(self, address):
1038 """Instantiate a new IPv6 object.
1039
1040 Args:
1041 ipaddr: A string or integer representing the IP or the IP
1042 and prefix/netmask.
1043 '2001:4860::/128'
1044 '2001:4860:0000:0000:0000:0000:0000:0000/128'
1045 '2001:4860::'
1046 are all functionally the same in IPv6. That is to say,
1047 failing to provide a subnetmask will create an object with
1048 a mask of /128.
1049
1050 Additionally, an integer can be passed, so
1051 IPv6('2001:4860::') ==
1052 IPv6(42541956101370907050197289607612071936L).
1053 or, more generally
1054 IPv6(IPv6('2001:4860::').ip) == IPv6('2001:4860::')
1055
1056 Raises:
1057 IPv6IpValidationError: If ipaddr isn't a valid IPv6 address.
1058 IPv6NetmaskValidationError: If the netmask isn't valid for
1059 an IPv6 address.
1060 IPRangeError: If range of IP addresses is not valid.
1061
1062 """
1063 BaseIP.__init__(self)
1064 self._version = 6 1260 self._version = 6
1065 self._max_prefixlen = 128 1261 self._max_prefixlen = 128
1066 1262
1067 # Efficient constructor from integer. 1263 def _ip_int_from_string(self, ip_str=None):
1068 if isinstance(ipaddr, long) or isinstance(ipaddr, int): 1264 """Turn an IPv6 ip_str into an integer.
1069 self.ip = ipaddr 1265
1070 self._prefixlen = 128 1266 Args:
1071 self.netmask = self._ALL_ONES 1267 ip_str: A string, the IPv6 ip_str.
1072 if ipaddr < 0 or ipaddr > self._ALL_ONES: 1268
1073 raise IPv6IpValidationError(ipaddr) 1269 Returns:
1074 return 1270 A long, the IPv6 ip_str.
1075
1076 # Constructing from a packed address
1077 if _compat_has_real_bytes:
1078 if isinstance(ipaddr, bytes) and len(ipaddr) == 16:
1079 tmp = struct.unpack('!QQ', ipaddr)
1080 self.ip = (tmp[0] << 64) | tmp[1]
1081 self._prefixlen = 128
1082 self.netmask = self._ALL_ONES
1083 return
1084
1085 addr_str = str(ipaddr)
1086 if not addr_str:
1087 raise IPv6IpValidationError('')
1088
1089 # Construct network from a range e.g. ::-::15
1090 addr = addr_str.split('-')
1091
1092 if len(addr) > 2:
1093 raise IPv6IpValidationError(ipaddr)
1094
1095 if len(addr) == 2:
1096 if not self._is_valid_ip(addr[0]):
1097 raise IPv6IpValidationError(addr[0])
1098
1099 if not self._is_valid_ip(addr[1]):
1100 raise IPv6IpValidationError(addr[1])
1101
1102 self.ip = self._ip_int_from_string(addr[0])
1103
1104 last = self._ip_int_from_string(addr[1])
1105 if last < self.ip:
1106 raise IPRangeError("last address should be greater than "
1107 "first.")
1108 bits = _highest_one_bit(last - self.ip)
1109 self._prefixlen = self.max_prefixlen - bits
1110 self.netmask = self._ip_int_from_prefix(self._prefixlen)
1111 if self._ip_int_from_string(IPv6(self)[-1]) != last:
1112 raise IPRangeError("range %s is not on a network byte "
1113 "boundary." % ipaddr)
1114 return
1115
1116 # Assume input argument to be string or any object representation
1117 # which converts into a formatted IP prefix string.
1118 addr = addr_str.split('/')
1119 if len(addr) > 1:
1120 if self._is_valid_netmask(addr[1]):
1121 self._prefixlen = int(addr[1])
1122 else:
1123 raise IPv6NetmaskValidationError(addr[1])
1124 else:
1125 self._prefixlen = 128
1126
1127 self.netmask = self._ip_int_from_prefix(self._prefixlen)
1128
1129 if not self._is_valid_ip(addr[0]):
1130 raise IPv6IpValidationError(addr[0])
1131
1132 self.ip = self._ip_int_from_string(addr[0])
1133
1134 @property
1135 def ip_ext_full(self):
1136 """Returns the expanded version of the IPv6 string."""
1137 return self._explode_shorthand_ip_string(self.ip_ext)
1138
1139 def _set_prefix(self, prefixlen):
1140 """Change the prefix length.
1141
1142 Args:
1143 prefixlen: An integer, the new prefix length.
1144
1145 Raises:
1146 IPv6NetmaskValidationError: If prefixlen is out of bounds.
1147
1148 """
1149 if not 0 <= prefixlen <= 128:
1150 raise IPv6NetmaskValidationError(prefixlen)
1151 self._prefixlen = prefixlen
1152 self.netmask = self._ip_int_from_prefix(self.prefixlen)
1153
1154 def subnet(self, prefixlen_diff=1):
1155 """The subnets which join to make the current subnet.
1156
1157 In the case that self contains only one IP
1158 (self._prefixlen == 128), return a list with just ourself.
1159
1160 Args:
1161 prefixlen_diff: An integer, the amount the prefix length
1162 should be increased by.
1163
1164 Returns:
1165 A list of IPv6 objects.
1166
1167 Raises:
1168 PrefixlenDiffInvalidError: The prefixlen_diff is too small
1169 or too large.
1170
1171 """
1172 # Preserve original functionality (return [self] if
1173 # self.prefixlen == 128).
1174 if self.prefixlen == 128:
1175 return [self]
1176
1177 if prefixlen_diff < 0:
1178 raise PrefixlenDiffInvalidError('Prefix length diff must be > 0')
1179 new_prefixlen = self.prefixlen + prefixlen_diff
1180 if not self._is_valid_netmask(str(new_prefixlen)):
1181 raise PrefixlenDiffInvalidError(
1182 'Prefix length diff %d is invalid for netblock %s' % (
1183 new_prefixlen, str(self)))
1184 first = IPv6(
1185 self._string_from_ip_int(self.network) + '/' +
1186 str(self._prefixlen + prefixlen_diff))
1187 subnets = [first]
1188 current = first
1189 while True:
1190 broadcast = current.broadcast
1191 if current.broadcast == self.broadcast:
1192 break
1193 current = IPv6(self._string_from_ip_int(broadcast + 1) + '/' +
1194 str(new_prefixlen))
1195 subnets.append(current)
1196
1197 return subnets
1198
1199 def supernet(self, prefixlen_diff=1):
1200 """The supernet containing the current network.
1201
1202 Args:
1203 prefixlen_diff: An integer, the amount the prefix length of the
1204 network should be decreased by. For example, given a /96
1205 network and a prefixlen_diff of 3, a supernet with a /93
1206 netmask is returned.
1207
1208 Returns:
1209 An IPv6 object.
1210
1211 Raises:
1212 PrefixlenDiffInvalidError: If
1213 self._prefixlen - prefixlen_diff < 0. I.e., you have a
1214 negative prefix length.
1215
1216 """
1217 if self.prefixlen == 0:
1218 return self
1219 if self.prefixlen - prefixlen_diff < 0:
1220 raise PrefixlenDiffInvalidError(
1221 'current prefixlen is %d, cannot have a prefixlen_diff of %d' %
1222 (self.prefixlen, prefixlen_diff))
1223 return IPv6(self.ip_ext + '/' + str(self.prefixlen - prefixlen_diff))
1224
1225 @property
1226 def is_multicast(self):
1227 """Test if the address is reserved for multicast use.
1228
1229 Returns:
1230 A boolean, True if the address is a multicast address.
1231 See RFC 2373 2.7 for details.
1232
1233 """
1234 return self in IPv6('ff00::/8')
1235
1236 @property
1237 def is_unspecified(self):
1238 """Test if the address is unspecified.
1239
1240 Returns:
1241 A boolean, True if this is the unspecified address as defined in
1242 RFC 2373 2.5.2.
1243
1244 """
1245 return self == IPv6('::')
1246
1247 @property
1248 def is_loopback(self):
1249 """Test if the address is a loopback adddress.
1250
1251 Returns:
1252 A boolean, True if the address is a loopback address as defined in
1253 RFC 2373 2.5.3.
1254
1255 """
1256 return self == IPv6('::1')
1257
1258 @property
1259 def is_link_local(self):
1260 """Test if the address is reserved for link-local.
1261
1262 Returns:
1263 A boolean, True if the address is reserved per RFC 4291.
1264
1265 """
1266 return self in IPv6('fe80::/10')
1267
1268 @property
1269 def is_site_local(self):
1270 """Test if the address is reserved for site-local.
1271
1272 Note that the site-local address space has been deprecated by RFC 3879.
1273 Use is_private to test if this address is in the space of unique local
1274 addresses as defined by RFC 4193.
1275
1276 Returns:
1277 A boolean, True if the address is reserved per RFC 3513 2.5.6.
1278
1279 """
1280 return self in IPv6('fec0::/10')
1281
1282 @property
1283 def is_private(self):
1284 """Test if this address is allocated for private networks.
1285
1286 Returns:
1287 A boolean, True if the address is reserved per RFC 4193.
1288
1289 """
1290 return self in IPv6('fc00::/7')
1291
1292 @property
1293 def version(self):
1294 return self._version
1295
1296 @property
1297 def max_prefixlen(self):
1298 return self._max_prefixlen
1299
1300 @property
1301 def packed(self):
1302 """The binary representation of this address."""
1303 return struct.pack('!QQ', self.ip >> 64, self.ip & (2**64 - 1))
1304
1305 def _is_shorthand_ip(self, ip_str=None):
1306 """Determine if the address is shortened.
1307
1308 Args:
1309 ip_str: A string, the IPv6 address.
1310
1311 Returns:
1312 A boolean, True if the address is shortened.
1313
1314 """
1315 if ip_str.count('::') == 1:
1316 return True
1317 return False
1318
1319 def _explode_shorthand_ip_string(self, ip_str):
1320 """Expand a shortened IPv6 address.
1321
1322 Args:
1323 ip_str: A string, the IPv6 address.
1324
1325 Returns:
1326 A string, the expanded IPv6 address.
1327
1328 """
1329 if self._is_shorthand_ip(ip_str):
1330 new_ip = []
1331 hextet = ip_str.split('::')
1332 sep = len(hextet[0].split(':')) + len(hextet[1].split(':'))
1333 new_ip = hextet[0].split(':')
1334
1335 for _ in xrange(8 - sep):
1336 new_ip.append('0000')
1337 new_ip += hextet[1].split(':')
1338
1339 # Now need to make sure every hextet is 4 lower case characters.
1340 # If a hextet is < 4 characters, we've got missing leading 0's.
1341 ret_ip = []
1342 for hextet in new_ip:
1343 ret_ip.append(('0' * (4 - len(hextet)) + hextet).lower())
1344 return ':'.join(ret_ip)
1345 # We've already got a longhand ip_str.
1346 return ip_str
1347
1348 def _is_valid_ip(self, ip_str=None):
1349 """Ensure we have a valid IPv6 address.
1350
1351 Probably not as exhaustive as it should be.
1352
1353 Args:
1354 ip_str: A string, the IPv6 address.
1355
1356 Returns:
1357 A boolean, True if this is a valid IPv6 address.
1358 1271
1359 """ 1272 """
1360 if not ip_str: 1273 if not ip_str:
1361 ip_str = self.ip_ext 1274 ip_str = str(self.ip)
1362
1363 # We need to have at least one ':'.
1364 if ':' not in ip_str:
1365 return False
1366
1367 # We can only have one '::' shortener.
1368 if ip_str.count('::') > 1:
1369 return False
1370
1371 # '::' should be encompassed by start, digits or end.
1372 if ':::' in ip_str:
1373 return False
1374
1375 # A single colon can neither start nor end an address.
1376 if ((ip_str.startswith(':') and not ip_str.startswith('::')) or
1377 (ip_str.endswith(':') and not ip_str.endswith('::'))):
1378 return False
1379
1380 # If we have no concatenation, we need to have 8 fields with 7 ':'.
1381 if '::' not in ip_str and ip_str.count(':') != 7:
1382 # We might have an IPv4 mapped address.
1383 if ip_str.count('.') != 3:
1384 return False
1385
1386 ip_str = self._explode_shorthand_ip_string(ip_str)
1387
1388 # Now that we have that all squared away, let's check that each of the
1389 # hextets are between 0x0 and 0xFFFF.
1390 for hextet in ip_str.split(':'):
1391 if hextet.count('.') == 3:
1392 # If we have an IPv4 mapped address, the IPv4 portion has to be
1393 # at the end of the IPv6 portion.
1394 if not ip_str.split(':')[-1] == hextet:
1395 return False
1396 try:
1397 IPv4(hextet)
1398 except IPv4IpValidationError:
1399 return False
1400 elif int(hextet, 16) < 0x0 or int(hextet, 16) > 0xFFFF:
1401 return False
1402 return True
1403
1404 def _is_valid_netmask(self, prefixlen):
1405 """Verify that the netmask/prefixlen is valid.
1406
1407 Args:
1408 prefixlen: A string, the netmask in prefix length format.
1409
1410 Returns:
1411 A boolean, True if the prefix represents a valid IPv6
1412 netmask.
1413
1414 """
1415 try:
1416 prefixlen = int(prefixlen)
1417 except ValueError:
1418 return False
1419 return 0 <= prefixlen <= 128
1420
1421 def _ip_int_from_string(self, ip_str=None):
1422 """Turn an IPv6 address into an integer.
1423
1424 Args:
1425 ip_str: A string, the IPv6 address.
1426
1427 Returns:
1428 A long, the IPv6 address.
1429
1430 """
1431 if not ip_str:
1432 ip_str = self.ip_ext
1433 1275
1434 ip_int = 0 1276 ip_int = 0
1435 1277
1436 fields = self._explode_shorthand_ip_string(ip_str).split(':') 1278 fields = self._explode_shorthand_ip_string(ip_str).split(':')
1437 1279
1438 # 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)
1439 # address? 1281 # ip_str?
1440 if fields[-1].count('.') == 3: 1282 if fields[-1].count('.') == 3:
1441 ipv4_string = fields.pop() 1283 ipv4_string = fields.pop()
1442 ipv4_int = IPv4(ipv4_string).ip 1284 ipv4_int = IPv4(ipv4_string)._ip
1443 octets = [] 1285 octets = []
1444 for _ in xrange(2): 1286 for _ in xrange(2):
1445 octets.append(hex(ipv4_int & 0xFFFF).lstrip('0x').rstrip('L')) 1287 octets.append(hex(ipv4_int & 0xFFFF).lstrip('0x').rstrip('L'))
1446 ipv4_int >>= 16 1288 ipv4_int >>= 16
1447 fields.extend(reversed(octets)) 1289 fields.extend(reversed(octets))
1448 1290
1449 for field in fields: 1291 for field in fields:
1450 ip_int = (ip_int << 16) + int(field, 16) 1292 ip_int = (ip_int << 16) + int(field, 16)
1451 1293
1452 return ip_int 1294 return ip_int
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
1505 ip_int: An integer, the IP address. 1347 ip_int: An integer, the IP address.
1506 1348
1507 Returns: 1349 Returns:
1508 A string, the hexadecimal representation of the address. 1350 A string, the hexadecimal representation of the address.
1509 1351
1510 Raises: 1352 Raises:
1511 ValueError: The address is bigger than 128 bits of all ones. 1353 ValueError: The address is bigger than 128 bits of all ones.
1512 1354
1513 """ 1355 """
1514 if not ip_int and ip_int != 0: 1356 if not ip_int and ip_int != 0:
1515 ip_int = self.ip 1357 ip_int = int(self._ip)
1516 1358
1517 if ip_int > self._ALL_ONES: 1359 if ip_int > self._ALL_ONES:
1518 raise ValueError('IPv6 address is too large') 1360 raise ValueError('IPv6 address is too large')
1519 1361
1520 hex_str = '%032x' % ip_int 1362 hex_str = '%032x' % ip_int
1521 hextets = [] 1363 hextets = []
1522 for x in range(0, 32, 4): 1364 for x in range(0, 32, 4):
1523 hextets.append('%x' % int(hex_str[x:x+4], 16)) 1365 hextets.append('%x' % int(hex_str[x:x+4], 16))
1524 1366
1525 hextets = self._compress_hextets(hextets) 1367 hextets = self._compress_hextets(hextets)
1526 return ':'.join(hextets) 1368 return ':'.join(hextets)
1527 1369
1528 @property 1370 def _explode_shorthand_ip_string(self, ip_str=None):
1529 def netmask_ext(self): 1371 """Expand a shortened IPv6 address.
1530 """IPv6 extended netmask. 1372
1531 1373 Args:
1532 We don't deal with netmasks in IPv6 like we do in IPv4. This is 1374 ip_str: A string, the IPv6 address.
1533 here strictly for IPv4 compatibility. We simply return the 1375
1534 prefix length. 1376 Returns:
1535 1377 A string, the expanded IPv6 address.
1536 Returns: 1378
1537 An integer. 1379 """