chiark / gitweb /
bugfix: -fno-strict-aliasing, because tun.c breaks the rules.
[secnet.git] / ipaddr.py
1 # -*- coding: iso-8859-1 -*-
2 # ipaddr.py -- handle IP addresses and set of IP addresses.
3 # Copyright (C) 1996-2000 Cendio Systems AB
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
19 """IP address manipulation.
20
21 This module is useful if you need to manipulate IP addresses or sets
22 of IP addresses.
23
24 The main classes are:
25
26     ipaddr   -- a single IP address.
27     netmask  -- a netmask.
28     network  -- an IP address/netmask combination.  It is often, but
29                 not always, better to use the ip_set class instead.
30     ip_set   -- a set of IP addresses, that may or may not be adjacent.
31
32 So, what can you do with this module?  As a simple example of the kind
33 of things this module can do, this code computes the set of all IP
34 addresses except 127.0.0.0/8 and prints it, expressed as a union of
35 network/netmask pairs.
36
37     import ipaddr
38
39     s = ipaddr.ip_set()
40     s.add_network(ipaddr.network('127.0.0.0', '255.0.0.0',
41                                  ipaddr.DEMAND_FILTER))
42     for nw in s.complement().as_list_of_networks():
43         print nw.ip_str() + '/' + nw.mask.netmask_bits_str
44
45 Errors are reported by raising an exception from the following
46 exception hierarcy:
47
48 Exception       # The standard Python base exception class.
49  |
50  +-- BadType    # Only raised if the programmer makes an error.
51  +-- IpError    # Base class for errors that depend on the data.
52       |
53       +-- SetNotRepresentable
54       +-- BrokenIpAddress
55       |    |
56       |    +-- PartNegative
57       |    +-- PartOverflow
58       |
59       +-- BrokenNetmask
60       |    |
61       |    +-- NeedOneBit
62       |    +-- NeedMoreBits
63       |    +-- NeedLessBits
64       |
65       +-- BrokenNetwork
66             |
67             +-- EmptyIpAddress
68             +-- EmptyNetmask
69             +-- BrokenNetworkAddress
70             +-- NetworkAddressClash
71             +-- BroadcastAddressClash
72   
73 BadType may be raised at any time if the programmer makes an error
74 (such as passing a dictionary to a function that expects a string).
75 SetNotRepresentable may be raised by ip_set.as_str_range().  All other
76 exceptions are raised from the constructors and helper functions only.
77
78 The following constants are present in this module:
79
80     DEMAND_NONE         See class network.
81     DEMAND_FILTER       See class network.
82     DEMAND_NETWORK      See class network.
83     DEMAND_INTERFACE    See class network.
84
85     hostmask            A netmask object with all 32 bits set.
86     complete_network    A network object representing all IP addresses.
87     complete_set        An ip_set object representing all IP addresses.
88     broadcast_network   A network object representing 255.255.255.255.
89     broadcast_set       An ip_set object representing 255.255.255.255.
90     
91 The as_ipaddr function can be used when you have an object that you
92 know are an ipaddr or network, and you want to get the ipaddr part.
93
94 All the other functions in this module are internal helper functions,
95 and they should not be used.
96
97 The internal representation used for IP addresses is currently a long
98 number.  That may change in the future, so where the internal
99 representation is visible, you should do nothing with it except
100 compare it to None.
101
102 This module was developed by Cendio Systems AB for use in the Fuego
103 Firewall.  Bug reports can be sent to Per Cederqvist <ceder@cendio.se>
104 who is currently acting as maintainer for this module.
105
106 Brief history:
107     1997-03-11      Module created, and used internally.
108     2000-03-09 1.0: First non-public beta release outside of Cendio Systems.
109     2000-03-17 1.1: First public release under the GNU GPL license.
110
111 """
112
113
114 import copy
115 import string
116 import types
117
118 # The error messages are marked with a call to this function, so that
119 # they can easily be found and translated.
120 def _(s):
121     return s
122
123 # The exception hierarchy.
124 class IpError(Exception):
125     """Base class for errors that are cause by errors in input data.
126     """
127     def __str__(self):
128         return self.format % self.args
129
130 class SetNotRepresentable(IpError):
131     format = _("The set of IP addresses cannot be represented "
132                "as a single network range")
133
134 class BrokenIpAddress(IpError):
135     format = _("Felaktigt IP-nummer")
136
137 class PartNegative(BrokenIpAddress):
138     format = _("En komponent i IP-numret är negativ")
139
140 class PartOverflow(BrokenIpAddress):
141     format = _("En komponent i IP-numret är större än 255")
142
143 class BrokenNetmask(IpError):
144     format = _("Felaktig nätmask")
145
146 class NeedOneBit(BrokenNetmask):
147     format = _("Minst en bit måste vara ettställd")
148
149 class NeedMoreBits(BrokenNetmask):
150     format = _("Minst %d bitar måste vara ettställda")
151
152 class NeedLessBits(BrokenNetmask):
153     format = _("Högst %d bitar får vara ettställda")
154
155 class BrokenNetwork(IpError):
156     """Base class for errors regarding network objects.
157     """
158
159 class EmptyIpAddress(BrokenNetwork):
160     format = _("IP-nummer ej ifyllt")
161
162 class EmptyNetmask(BrokenNetwork):
163     format = _("Nätmask ej ifylld")
164
165 class BrokenNetworkAddress(BrokenNetwork):
166     format = _("Med denna nätmask är %s ett otillåtet nätverksnummer; "
167                "menar du %s?")
168
169 class NetworkAddressClash(BrokenNetwork):
170     format = _("Med denna nätmask krockar Fuegons adress med nätnumret")
171
172 class BroadcastAddressClash(BrokenNetwork):
173     format = _("Med denna nätmask krockar Fuegons adress "
174                "med broadcastadressen")
175
176 class BadType(Exception):
177     """An object of an unexpected type was passed to a function.
178     """
179     pass
180
181 # These constants are used with netmasks and networks to specify what
182 # the code expects.
183 #
184 #  DEMAND_NONE: netmask 0-32 (inclusive)
185 #  DEMAND_FILTER: netmask 0-32, the host part must be all zeroes
186 #  DEMAND_NETWORK: netmask 1-32, the host part must be all zeroes
187 #  DEMAND_INTERFACE: netmask 1-30, the host part must *not* be all zeroes
188
189 DEMAND_NONE = 1
190 DEMAND_FILTER = 2
191 DEMAND_NETWORK = 3
192 DEMAND_INTERFACE = 4
193
194 def bits_to_intrep(bits):
195     """Convert BITS to the internal representation.
196
197     BITS should be a number in the range 0-32 (inclusive).
198
199     """
200     return pow(2L, 32) - pow(2L, 32-bits)
201
202
203 def intrep_with_bit_set(bit):
204     """Return an internal representation with bit BIT set.
205
206     BIT should be a number in the range 1-32, where bit 1 is the
207     leftmost.  Examples:
208
209       intrep_with_bit_set(1) --> the internal representation of 128.0.0.0
210       intrep_with_bit_set(32) --> the internal representation of 0.0.0.1
211     """
212     assert 0 < bit and bit <= 32
213
214     return pow(2L, 32-bit)
215
216
217 __ONES = {0:0, 128:1, 192:2, 224:3,
218           240:4, 248:5, 252:6, 254:7}
219
220 def tuple_to_bits(mask):
221     """Convert MASK to bits.
222
223     MASK should be a tuple of four integers in the range 0-255 (inclusive).
224
225     Raises BrokenNetmask if MASK is not a valid netmask.
226     """
227
228     if mask == None:
229         return None
230     else:
231         (a, b, c, d) = mask
232
233         if a == 255 and b == 255 and c == 255 and d == 255:
234             return 32
235
236         try:
237             if a == 255 and b == 255 and c == 255:
238                 return 24 + __ONES[d]
239             elif a == 255 and b == 255  and d == 0:
240                 return 16 + __ONES[c]
241             elif a == 255 and c == 0  and d == 0:
242                 return 8 + __ONES[b]
243             elif b == 0 and c == 0  and d == 0:
244                 return __ONES[a]
245         except KeyError:
246             pass
247
248         raise BrokenNetmask()
249
250
251 def intrep_to_dotted_decimal(t):
252     """Convert T to dotted-decimal notation.
253
254     T should be the internal representation used py ipaddr.py.
255     """
256
257     return (str(int(t>>24)) + '.' + str(int((t>>16) & 255))
258             + '.' + str(int((t>>8) & 255)) + '.' + str(int(t & 255)))
259
260
261 def as_ipaddr(nwip):
262     """Return the IP address object of NWIP.
263
264     NWIP may be an ipaddr object, which is returned unchanged,
265     or a network object, in which case the ipaddr part of it is
266     returned.
267     """
268
269     if isinstance(nwip, ipaddr):
270         return nwip
271     elif isinstance(nwip, network):
272         return nwip.ip
273     else:
274         raise BadType('Expected a network or ipaddr object', nwip)
275
276
277 class ipaddr:
278     """Handle IP addresses.
279
280     Sample use:
281
282         ip1 = ipaddr('12.3.5.1')
283         ip2 = ipaddr([12, 3, 5, 1])
284         print ip1.ip_str()
285         >>> '12.3.5.1'
286         print ip1.intrep
287         >>> 201524481L
288         print ip2.ip_str()
289         >>> '12.3.5.1'
290         print ip2.intrep
291         >>> 201524481L
292
293     An ipaddr object can have two states: empty or good.
294     The status can be examined like this:
295
296         if ip.intrep == None:
297             handle_empty(m.user_input())
298         else:
299             handle_good(ip)
300
301     All other members should only be used in the good state.  The
302     value stored in the intrep member should only be compared against
303     None.  The type and value of it is an internal detail that may
304     change in the future.
305
306     """
307
308     def __init__(self, ip):
309         """Create an ipaddr from IP (a string, tuple or list).
310
311         The empty string or None may be given; it is handled as the
312         empty IP number.
313         """
314
315         if type(ip) == types.StringType:
316             self.__user_input = ip
317             ip = string.strip(ip)
318         else:
319             self.__user_input = None
320
321         # The empty IP number?
322
323         if ip == '' or ip == None:
324             self.__ip_str = ''
325             self.intrep = None
326             if ip == None:
327                 self.__user_input = ''
328             return
329
330         if type(ip) == types.StringType:
331
332             # Convert a string.
333
334             try:
335                 [a, b, c, d] = map(string.atoi, string.splitfields(ip, '.'))
336             except:
337                 raise BrokenIpAddress()
338
339             if a < 0 or b < 0 or c < 0 or d < 0:
340                 raise PartNegative()
341
342             if a > 255 or b > 255 or c > 255 or d > 255:
343                 raise PartOverflow()
344
345             self.intrep = (long(a) << 24) + (b << 16) + (c << 8) + d
346
347         else:
348             assert type(ip) == types.LongType
349             self.intrep = ip
350
351         self.__ip_str = None
352
353     def ip_str(self):
354         if self.__ip_str == None:
355             self.__ip_str = intrep_to_dotted_decimal(self.intrep)
356         return self.__ip_str
357
358     def user_input(self):
359         if self.__user_input == None:
360             # This object was constructed from a tuple.  Generate a string.
361             self.__user_input = self.ip_str()
362         return self.__user_input
363
364     def compare(self, other):
365         """Compare this IP address with OTHER.
366
367         Returns -1, 0 or 1 if this IP address is less than, equal to,
368         or greater than OTHER (which should be an ipaddr object).
369         """
370         # FIXME: should we rename this __cmp__?  It needs to handle
371         # other types of the OTHER argument first.
372
373         if self.intrep == other.intrep:
374             return 0
375         if self.intrep < other.intrep:
376             return -1
377         else:
378             return 1
379
380     def __str__(self):
381         if self.intrep is None:
382             return "<ipaddr empty>"
383         else:
384             return "<ipaddr %s>" % self.ip_str()
385
386     def __repr__(self):
387         if self.intrep is None:
388             return "ipaddr.ipaddr('')"
389         else:
390             return "ipaddr.ipaddr('%s')" % self.ip_str()
391
392
393 class netmask:
394     """Handle netmasks.
395
396     Sample use:
397
398         # Four ways to initialize a netmask.
399         nm1 = netmask('255.255.128.0', DEMAND_NONE)
400         nm2 = netmask([255, 255, 128, 0], DEMAND_NONE)
401         nm3 = netmask('17', DEMAND_NONE)
402         nm4 = netmask(17, DEMAND_NONE)
403         print nm1.netmask_str()
404         >>> '255.255.128.0'
405         print nm1.intrep
406         >>> (255, 255, 128, 0)
407         print nm1.netmask_bits
408         >>> 17
409         print nm1.netmask_bits_str
410         >>> '17'
411
412     A netmask can have two states: empty or good.  The state
413     can be examined like this:
414
415         if m.intrep == None:
416             handle_empty(m.user_input())
417         else:
418             handle_good(m)
419
420     All other members should be used only in the good state.
421
422     """
423
424     def __check_range(self, bits, minbits, maxbits):
425         if bits < minbits:
426             if minbits == 1:
427                 raise NeedOneBit()
428             else:
429                 raise NeedMoreBits(minbits)
430         elif bits > maxbits:
431             raise NeedLessBits(maxbits)
432
433
434     def __set_from_bits(self, bits, minbits, maxbits):
435         self.__check_range(bits, minbits, maxbits)
436         self.intrep = bits_to_intrep(bits)
437         self.netmask_bits = bits
438
439
440     def __set_from_tuple(self, tpl, minbits, maxbits):
441         bits = tuple_to_bits(tpl)
442         self.__check_range(bits, minbits, maxbits)
443         self.intrep = bits_to_intrep(bits)
444         self.netmask_bits = bits
445
446     DEMANDS = {DEMAND_NONE:(0,32),
447                DEMAND_FILTER:(0,32),
448                DEMAND_NETWORK:(1,32),
449                DEMAND_INTERFACE:(1,30)}
450
451     def __init__(self, mask, demand):
452         """Create a netmask from MASK (a string, tuple or number) and DEMAND.
453
454         The empty string or None may be given; it is handled as the
455         empty netmask.
456
457         See class network for a description of the DEMAND parameter.
458         """
459
460         (minbits, maxbits) = self.DEMANDS[demand]
461         self.demand = demand
462
463         if type(mask) == types.StringType:
464             self.__user_input = mask
465             mask = string.strip(mask)
466         else:
467             self.__user_input = None
468
469         if mask == '' or mask == None:
470
471             # Handle empty netmasks.
472
473             self.__netmask_str = ''
474             self.intrep = None
475             self.netmask_bits_str = ''
476             self.netmask_bits = None
477             if self.__user_input == None:
478                 self.input = ''
479             return
480
481         # Decode the MASK argument and set self.netmask_bits
482         # and self.intrep.
483
484         if type(mask) == types.StringType:
485
486             # Is this a string containing a single number?
487             try:
488                 bits = string.atoi(mask)
489             except (OverflowError, ValueError):
490                 bits = None
491
492             if bits != None:
493
494                 # This is a string containing a single number.
495
496                 self.__set_from_bits(bits, minbits, maxbits)
497
498             else:
499
500                 # Interpret the netmask as a dotted four-tuple.
501                 try:
502                     [a, b, c, d] = map(string.atoi,
503                                        string.splitfields(mask, '.'))
504                 except:
505                     raise BrokenNetmask()
506
507                 self.__set_from_tuple((a, b, c, d), minbits, maxbits)
508
509         elif type(mask) == types.IntType:
510
511             # This is a number, representing the number of bits in the mask.
512
513             self.__set_from_bits(mask, minbits, maxbits)
514
515         else:
516
517             # This is a tuple or list.
518
519             if len(mask) != 4:
520                 raise BadType('Wrong len of tuple/list')
521
522             (a, b, c, d) = (mask[0], mask[1], mask[2], mask[3])
523
524             self.__set_from_tuple((a, b, c, d), minbits, maxbits)
525
526         self.__netmask_str = None
527         self.netmask_bits_str = repr(self.netmask_bits)
528
529     def netmask_str(self):
530         if self.__netmask_str == None:
531             self.__netmask_str = intrep_to_dotted_decimal(self.intrep)
532         return self.__netmask_str
533
534     def user_input(self):
535         if self.__user_input == None:
536             # This object was constructed from a tuple or an integer.
537             self.__user_input = self.ip_str()
538         return self.__user_input
539
540     def __str__(self):
541         if self.intrep is None:
542             return "<netmask empty>"
543         else:
544             return "<netmask /%d>" % self.netmask_bits
545
546     def __repr__(self):
547         if self.intrep is None:
548             return "ipaddr.netmask('')"
549         else:
550             return "ipaddr.netmask(%d, %d)" % (self.netmask_bits, self.demand)
551
552
553 hostmask = netmask(32, DEMAND_NONE)
554         
555
556 class network:
557     """Designate a network or host.
558
559     The constructor takes three arguments: the IP number part, the
560     netmask part, and a demand parameter.  See class ipaddr and class
561     netmask for a description of the first two arguments.  The demand
562     argument can be one of the following constants:
563
564     DEMAND_NONE
565         No special demands.
566     DEMAND_FILTER
567         The host part must be all zeroes.
568     DEMAND_NETWORK
569         The netmask must be 1-32
570         The host part must be all zeroes.
571     DEMAND_INTERFACE
572         The netmask must be 1-30
573         The host part must *not* be all zeroes (the network address)
574         or all ones (the broadcast address).
575
576     The following members exist and are set by the constructor:
577
578       ip.user_input()           # a caching function
579       ip_str()                  # a caching function
580       ip.intrep
581       mask.user_input()         # a caching function
582       mask.netmask_str()        # a caching function
583       mask.intrep
584       mask.netmask_bits
585       mask.netmask_bits_str
586       network_str()             # a caching function
587       network_intrep
588       broadcast_str()           # a caching function
589       broadcast_intrep
590       host_part_str()           # a caching function
591       host_part_intrep
592
593     """
594
595     def __init__(self, ip, mask, demand):
596         self.ip = ipaddr(ip)
597         self.mask = netmask(mask, demand)
598
599         if self.ip.intrep == None:
600             raise EmptyIpAddress()
601
602         if self.mask.intrep == None:
603             raise EmptyNetmask()
604
605         self._precompute()
606
607     def _precompute(self):
608         self.__lower_str = None
609         self.__upper_str = None
610
611         self.network_intrep = self.ip.intrep & self.mask.intrep
612         self.broadcast_intrep = (self.network_intrep |
613                                 (pow(2L, 32)-1-self.mask.intrep))
614         self.host_part_intrep = self.ip.intrep - self.network_intrep
615
616         self.__network_str = None
617         self.__broadcast_str = None
618         self.__host_part_str = None
619
620         demand = self.mask.demand
621
622         if demand == DEMAND_NONE:
623             pass
624         elif demand == DEMAND_FILTER or demand == DEMAND_NETWORK:
625             if self.host_part_intrep != 0L:
626                 raise BrokenNetworkAddress(self.ip_str(), self.network_str())
627         elif demand == DEMAND_INTERFACE:
628             if self.host_part_intrep == 0L:
629                 raise NetworkAddressClash()
630             elif self.broadcast_intrep == self.ip.intrep:
631                 raise BroadcastAddressClash()
632         else:
633             raise BadType('Bad value for the demand parameter', demand)
634
635     def network_str(self):
636         if self.__network_str == None:
637             self.__network_str = intrep_to_dotted_decimal(self.network_intrep)
638         return self.__network_str
639
640     def broadcast_str(self):
641         if self.__broadcast_str == None:
642             self.__broadcast_str = intrep_to_dotted_decimal(
643                 self.broadcast_intrep)
644         return self.__broadcast_str
645
646     def host_part_str(self):
647         if self.__host_part_str == None:
648             self.__host_part_str = intrep_to_dotted_decimal(
649                 self.host_part_intrep)
650         return self.__host_part_str
651
652     def overlaps(self, other):
653         """Returns true if the network overlaps with OTHER.
654
655         OTHER must be a network object or an ipaddr object.  If it
656         is empty this method will always return false.
657
658         """
659
660         if self.network_intrep == None:
661             return 0
662
663         if isinstance(other, ipaddr):
664
665             if other.intrep == None:
666                 return 0
667
668             return (self.mask.intrep & other.intrep) == self.network_intrep
669         else:
670             if other.network_intrep == None:
671                 return 0
672
673             mask = self.mask.intrep & other.mask.intrep
674             return (mask & self.ip.intrep) == (mask & other.ip.intrep)
675
676     def intersection(self, other):
677         """Return the intersection of the network and OTHER.
678
679         The return value is a network object with DEMAND_FILTER.  If
680         the intersection is empty this method will return None.
681
682         OTHER must be a network object or an ipaddr object.  The
683         intersection will be empty if it is empty.
684         """
685
686         if self.network_intrep == None:
687             return None
688
689         if isinstance(other, ipaddr):
690
691             if other.intrep == None:
692                 return None
693
694             prefix_mask = self.mask.intrep
695             short_net = self.network_intrep
696             long_ip = other.intrep
697             result = network(other.intrep, 32, DEMAND_FILTER)
698         else:
699             if other.network_intrep == None:
700                 return None
701             
702             if self.mask.netmask_bits < other.mask.netmask_bits:
703                 prefix_mask = self.mask.intrep
704                 short_net = self.network_intrep
705                 long_ip = other.network_intrep
706                 result = network(other.network_intrep, other.mask.netmask_bits,
707                                  DEMAND_FILTER)
708             else:
709                 prefix_mask = other.mask.intrep
710                 short_net = other.network_intrep
711                 long_ip = self.network_intrep
712                 result = network(self.network_intrep, self.mask.netmask_bits,
713                                  DEMAND_FILTER)
714
715         if (long_ip & prefix_mask) != (short_net & prefix_mask):
716             return None
717
718         return result
719
720     def is_subset(self, nwip):
721         """Return true if NWIP is a subset of this network.
722
723         NWIP must be a network object or an ipaddr object.
724         """
725
726         if not self.overlaps(nwip):
727             return 0
728
729         if isinstance(nwip, ipaddr):
730             return 1
731
732         return nwip.mask.netmask_bits <= self.mask.netmask_bits
733
734     def is_same_set(self, nwip):
735         """Return true if NWIP contains the same set as this network.
736
737         NWIP must be a network object or an ipaddr object.
738         """
739
740         if isinstance(nwip, ipaddr):
741             return (self.mask.netmask_bits == 32
742                     and self.ip.intrep == nwip.intrep)
743         else:
744             return (self.mask.netmask_bits == nwip.mask.netmask_bits
745                     and self.network_intrep == nwip.network_intrep)
746
747     def subtract(self, nwip):
748         """Create a list of new network objects by subtracting NWIP from self.
749
750         The result consists of networks that together span all
751         IP addresses that are present in self, except those that are
752         present in NWIP.  (The result may be empty or contain several
753         disjoint network objects.)
754
755         Don't use this!  This method is slow.  The ip_set class can do
756         this kind of things in a more efficient way.
757         """
758
759         if not self.overlaps(nwip):
760             # No overlap at all, so NWIP cannot affect the result.
761             return [self]
762
763         if isinstance(nwip, ipaddr):
764             bits = 32
765             intrep = nwip.intrep
766         else:
767             assert isinstance(nwip, network)
768             bits = nwip.mask.netmask_bits
769             intrep = nwip.ip.intrep
770         nets = []
771         while bits > self.mask.netmask_bits:
772             nets.append(network(compute_neighbor(intrep, bits),
773                                 bits, DEMAND_FILTER))
774             bits = bits - 1
775         return nets
776
777     def subtract_nwips(self, nwips):
778         """Create a list of new network objects by subtracting NWIPS.
779
780         The result consists of networks that together span all
781         IP addresses that are present in self, except those that are
782         present in NWIPS.  (The result may be empty or contain
783         several disjoint network objects.)  NWIPS should be a list
784         of network or ipaddr objects.
785
786         Don't use this!  This method is slow.  The ip_set class can do
787         this kind of things in a more efficient way.
788         """
789
790         subtracted = [self]
791         for s in nwips:
792             # precondition<A>: SUBTRACTED is a list of networks
793             tmp = []
794             for nw in subtracted:
795                 tmp = tmp + nw.subtract(s)
796             subtracted = tmp
797             # postcondition: SUBTRACTED is a list of networks that
798             # spans all IP addresses that were present in
799             # precondition<A>, except those that are present in S.
800
801         return subtracted
802
803     def __compute_lower_upper(self):
804         if self.__lower_str != None:
805             return
806         assert self.network_intrep != None and self.broadcast_intrep != None
807
808         self.__lower_str = intrep_to_dotted_decimal(self.network_intrep + 1)
809         self.__upper_str = intrep_to_dotted_decimal(self.broadcast_intrep - 1)
810
811     def lower_host(self):
812         self.__compute_lower_upper()
813         return self.__lower_str
814
815     def upper_host(self):
816         self.__compute_lower_upper()
817         return self.__upper_str
818
819     def __repr__(self):
820         return _("{network %s/%d}") % (self.ip_str(), self.mask.netmask_bits)
821
822     def ip_str(self):
823         return self.ip.ip_str()
824
825
826 class ip_set:
827     def __init__(self, nwip=None):
828         """Create an ip_set.
829
830         If the optional argument NWIP is supplied, the set is
831         initialized to it, otherwise the created set will be empty.
832         NWIP must be a network or ipaddr object.
833         """
834
835         # [[0L, 3L], [5L, 7L]] means 0.0.0.0/29 \ 0.0.0.4/32
836         self.__set = []
837
838         if nwip != None:
839             self.append(nwip)
840
841     def subtract_set(self, other):
842         """Remove all IP-numbers in OTHER from this.
843
844         OTHER should be an ip_set object.
845         """
846
847         self.subtract_list(other.__set)
848
849     def subtract_ips(self, ips):
850         """Remove all IP-numbers in IPS from this.
851
852         IPS should be a list of ipaddr objects.
853         """
854
855         for ip in ips:
856             self.subtract_list([[ip.intrep, ip.intrep]])
857
858     def subtract_list(self, other):
859         # Don't use this method directly, unless you are the test suite.
860         ix = 0
861         iy = 0
862         while ix < len(self.__set) and iy < len(other):
863             if self.__set[ix][1] < other[iy][0]:
864                 # The entire range survived.
865                 ix = ix + 1
866             elif self.__set[ix][0] > other[iy][1]:
867                 # The entire other range is unused, so discard it.
868                 iy = iy + 1
869             elif self.__set[ix][0] >= other[iy][0]:
870                 if self.__set[ix][1] <= other[iy][1]:
871                     # The entire range is subtracted.
872                     del self.__set[ix]
873                 else:
874                     # The start of the range is subtracted, but
875                     # the rest of the range may survive.  (As a matter
876                     # of fact, at least one number *will* survive,
877                     # since there should be a gap between other[iy][1]
878                     # and other[iy+1][0], but we don't use that fact.)
879                     self.__set[ix][0] = other[iy][1] + 1
880                     iy = iy + 1
881             else:
882                 # The first part of the range survives.
883                 end = self.__set[ix][1]
884                 assert self.__set[ix][1] >= other[iy][0]
885                 self.__set[ix][1] = other[iy][0] - 1
886                 ix = ix + 1
887                 if end > other[iy][1]:
888                     # The part that extends past the subtractor may survive.
889                     self.__set[ix:ix] = [[other[iy][1] + 1, end]]
890                 # Retain the subtractor -- it may still kill some
891                 # other range.
892
893     def add_set(self, other):
894         """Add all IP-numbers in OTHER to this.
895
896         OTHER should be an ip_set object.
897         """
898
899         self.add_list(other.__set)
900
901     def add_list(self, other):
902         # Don't use this method directly, unless you are the test suite.
903         ix = 0
904         iy = 0
905         res = []
906         while ix < len(self.__set) or iy < len(other):
907             # Remove the first range
908             if ix < len(self.__set):
909                 if iy < len(other):
910                     if self.__set[ix][0] < other[iy][0]:
911                         rng = self.__set[ix]
912                         ix = ix + 1
913                     else:
914                         rng = other[iy]
915                         iy = iy + 1
916                 else:
917                     rng = self.__set[ix]
918                     ix = ix + 1
919             else:
920                 rng = other[iy]
921                 iy = iy + 1
922
923             # Join this range to the list we already have collected.
924             if len(res) == 0:
925                 # This is the first element.
926                 res.append(rng)
927             elif rng[0] <= res[-1][1] + 1:
928                 # This extends (or is consumed by) the last range.
929                 res[-1][1] = max(res[-1][1], rng[1])
930             else:
931                 # There is a gap between the previous range and this one.
932                 res.append(rng)
933
934         self.__set = res
935
936     def append(self, nwip):
937         """Add NWIP to this.
938
939         NWIP should be a network object or ipaddr object.
940         """
941
942         if isinstance(nwip, network):
943             self.add_network(nwip)
944         else:
945             self.add_ipaddr(nwip)
946
947     def add_network(self, nw):
948         """Add NW to this.
949
950         NW should be a network object.
951         """
952         self.add_list([[nw.network_intrep, nw.broadcast_intrep]])
953
954     def add_range(self, lo_ip, hi_ip):
955         """Add the range of IP numbers specified by LO_IP and HI_IP to this.
956
957         LO_IP and HI_IP should be ipaddr objects.  They specify a
958         range of IP numbers.  Both LO_IP and HI_IP are included in the
959         range.
960         """
961
962         assert lo_ip.intrep != None
963         assert hi_ip.intrep != None
964         assert lo_ip.intrep <= hi_ip.intrep
965         self.add_list([[lo_ip.intrep, hi_ip.intrep]])
966
967     def add_ipaddr(self, ip):
968         """Add IP to this.
969
970         IP should be an ipaddr object.
971         """
972
973         assert ip.intrep != None
974         self.add_list([[ip.intrep, ip.intrep]])
975
976     def complement(self):
977         """Return everything not contained in this ip_set.
978
979         The return value is a new ip_set.  This is not modified.
980         """
981
982         pre = -1L
983         lst = []
984         for [lo, hi] in self.__set:
985             if lo != 0:
986                 lst.append([pre+1, lo-1])
987             pre = hi
988         if pre < pow(2L, 32) - 1:
989             lst.append([pre+1, pow(2L, 32) - 1])
990         res = ip_set()
991         res.add_list(lst)
992         return res
993
994     def intersection(self, other):
995         """Return the intersection of this and OTHER.
996
997         The return value is a new ip_set.  This is not modified.
998         OTHER should be an ip_set, network or ipaddr object.
999         """
1000
1001         res = []
1002         ix = 0
1003         iy = 0
1004         x = copy.deepcopy(self.__set)
1005
1006         if isinstance(other, ip_set):
1007             y = copy.deepcopy(other.__set)
1008         elif isinstance(other, network):
1009             y = [[other.network_intrep, other.broadcast_intrep]]
1010         elif isinstance(other, ipaddr):
1011             y = [[other.intrep, other.intrep]]
1012         else:
1013             raise BadType('expected an ip_set, network or ipaddr argument')
1014
1015         while ix < len(x) and iy < len(y):
1016             if x[ix][1] < y[iy][0]:
1017                 # The first entry on x doesn't overlap with anything on y.
1018                 ix = ix + 1
1019             elif x[ix][0] > y[iy][1]:
1020                 # The first entry on y doesn't overlap with anything on x.
1021                 iy = iy + 1
1022             else:
1023                 # Some overlap exists.
1024
1025                 # Trim away any leading edges.
1026                 if x[ix][0] < y[iy][0]:
1027                     # x starts before y
1028                     x[ix][0] = y[iy][0]
1029                 elif x[ix][0] > y[iy][0]:
1030                     # y starts before x
1031                     y[iy][0] = x[ix][0]
1032
1033                 # The ranges start at the same point (at least after
1034                 # the trimming).
1035                 if x[ix][1] == y[iy][1]:
1036                     # The ranges are equal.
1037                     res.append(x[ix])
1038                     ix = ix + 1
1039                     iy = iy + 1
1040                 elif x[ix][1] < y[iy][1]:
1041                     # x is the smaller range
1042                     res.append(x[ix])
1043                     ix = ix + 1
1044                 else:
1045                     # y is the smaller range
1046                     res.append(y[iy])
1047                     iy = iy + 1
1048
1049         result = ip_set()
1050         result.add_list(res)
1051         return result
1052
1053
1054     def as_list_of_networks(self):
1055         """Return this set as a list of networks.
1056
1057         The returned value is a list of network objects, that are
1058         created with DEMAND_FILTER.  This method may be expensive, so
1059         it should only be used when necessary.
1060         """
1061
1062         bm = []
1063         for [a, b] in self.__set:
1064
1065             lomask = 1L
1066             lobit = 1L
1067             himask = pow(2L, 32)-2
1068             bits = 32
1069             while a <= b:
1070                 if a & lomask != 0L:
1071                     bm.append((bits, a))
1072                     a = a + lobit
1073                 elif b & lomask != lomask:
1074                     bm.append((bits, b & himask))
1075                     b = b - lobit
1076                 else:
1077                     lomask = (lomask << 1) | 1
1078                     lobit = lobit << 1
1079                     himask = himask ^ lobit
1080                     bits = bits - 1
1081                     assert(bits >= 0)
1082         bm.sort()
1083         res = []
1084         for (mask, ip) in bm:
1085             res.append(network(ip, mask, DEMAND_FILTER))
1086         return res
1087
1088     def as_list_of_ranges(self):
1089         """Return the set of IP addresses as a list of ranges.
1090
1091         Each range is a list of two long numbers.  Sample return
1092         value: [[1L, 3L], [0x7f000001L, 0x7f000001L]], meaning
1093         the set 0.0.0.1, 0.0.0.2, 0.0.0.3, 127.0.0.1.
1094         """
1095
1096         # This method is currently very cheap, since this is the
1097         # current internal representation.
1098
1099         return self.__set
1100
1101     def as_str_range(self):
1102         """Return the set as a string, such as "1.2.3.4-1.2.3.8".
1103
1104         The returned value always has the form a.b.c.d-e.f.g.h.
1105         Raises SetNotRepresentable if the set cannot be represented as a
1106         single interval, or if it is the empty set.
1107         """
1108         if len(self.__set) != 1:
1109             raise SetNotRepresentable()
1110         return "%s-%s" % (intrep_to_dotted_decimal(self.__set[0][0]),
1111                           intrep_to_dotted_decimal(self.__set[0][1]))
1112
1113     def contains(self, ip):
1114         """Return true if IP is contained in the set.
1115
1116         IP should be an ipaddr object.  The empty ipaddr is never contained.
1117         """
1118
1119         if ip.intrep == None:
1120             return 0
1121
1122         for [lo, hi] in self.__set:
1123             if lo <= ip.intrep <= hi:
1124                 return 1
1125         return 0
1126
1127     def overlaps(self, nwip):
1128         """Return true if NWIP overlaps the set of IP addresses.
1129
1130         NWIP may be an ipaddr, network or ip_set object.
1131         """
1132
1133         if isinstance(nwip, ipaddr):
1134             return self.contains(nwip)
1135         elif isinstance(nwip, ip_set):
1136             # This could be optimized -- we don't really need
1137             # to compute the intersection.
1138             return not self.intersection(nwip).is_empty()
1139         elif isinstance(nwip, network):
1140             wanted_low = nwip.network_intrep
1141             wanted_high = nwip.broadcast_intrep
1142             if wanted_low == None or wanted_high == None:
1143                 return 0
1144             for [lo, hi] in self.__set:
1145                 if lo > wanted_high:
1146                     # We are past the interresting interval.
1147                     return 0
1148                 if lo >= wanted_low or hi >= wanted_low:
1149                     return 1
1150             return 0
1151         else:
1152             raise BadType('Expected an ipaddr, ip_set or network instance')
1153
1154     def is_empty(self):
1155         """Return true if this ip_set is empty.
1156         """
1157
1158         return len(self.__set) == 0
1159
1160     def any_ip(self):
1161         """Return one of the IP addresses contained in ip_set.
1162
1163         This method may only be called if the set is non-empty.  You
1164         can use the is_empty method to test for emptiness.
1165
1166         This picks an IP address from the set and returns it as an
1167         ipaddr object.  Given the same set of IP addresses, this
1168         method will always return the same IP address, but which IP
1169         address it chooses is explicitly undocumented and may change
1170         if the underlying implementation of ip_set ever changes.
1171         """
1172
1173         assert not self.is_empty()
1174         return ipaddr(self.__set[0][0])
1175
1176     def __str__(self):
1177         res = []
1178         for rng in self.__set:
1179             if rng[0] == rng[1]:
1180                 res.append(intrep_to_dotted_decimal(rng[0]))
1181             else:
1182                 res.append('%s-%s' % (intrep_to_dotted_decimal(rng[0]),
1183                                       intrep_to_dotted_decimal(rng[1])))
1184         return '<ipaddr.ip_set(%s)>' % string.join(res, ', ')
1185
1186 complete_network = network(0L, 0, DEMAND_FILTER)
1187 complete_set = ip_set(complete_network)
1188 broadcast_network = network('255.255.255.255', 32, DEMAND_FILTER)
1189 broadcast_set = ip_set(broadcast_network)
1190
1191 def compute_neighbor(intrep, bits):
1192     xor_mask = intrep_with_bit_set(bits)
1193     and_mask = bits_to_intrep(bits)
1194     return (intrep ^ xor_mask) & and_mask
1195
1196
1197 if __name__ == '__main__':
1198     # Test/demo code.  With no arguments, this will print a page
1199     # of data that can be useful when trying to interpret an
1200     # ipnumber/netmask pair.  With two arguments, it will print some
1201     # information about the IP number and netmask that was entered.
1202
1203     import sys
1204     if len(sys.argv) == 1:
1205         print "Netmasks\n========"
1206         for i in range(0, 17):
1207             if i != 16:
1208                 print '%2d' % i,
1209                 print '%-13s' % netmask(i, DEMAND_NONE).netmask_str(),
1210             else:
1211                 print ' ' * 16,
1212             print i + 16, '%-16s' % netmask(i + 16, DEMAND_NONE).netmask_str()
1213         print _("\n\nIP intervals\n============")
1214         for i in range(9):
1215             for j in range(0, 4):
1216                 print '%2d' % (8*j + i),
1217             print '%3d' % (netmask(i, DEMAND_NONE).intrep >> 24),
1218             x = 0
1219             need_break = 0
1220             if i < 8:
1221                 for j in range(0, 256, pow(2, 8-i)):
1222                     if need_break:
1223                         print
1224                         print ' ' * 15,
1225                         need_break = 0
1226                     print '%3d-%-3d' % (j, j + pow(2, 8-i)-1),
1227                     x = x + 1
1228                     if x % 8 == 0:
1229                         need_break = 1
1230             else:
1231                 print '0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13...',
1232             print
1233         sys.exit(0)
1234
1235     if len(sys.argv) != 3:
1236         sys.stderr.write(_("Usage: python ipaddr.py IP_ADDRESS NETMASK\n"))
1237         sys.exit(1)
1238     nw = network(sys.argv[1], sys.argv[2], DEMAND_NONE)
1239     print nw
1240     print "IP address:       ", nw.ip.ip_str()
1241     print "Netmask:          ", nw.mask.netmask_str(),
1242     print " (/" + nw.mask.netmask_bits_str + ")"
1243     print "Network address:  ", nw.network_str()
1244     print "Broadcast address:", nw.broadcast_str()