Merge remote-tracking branch 'mdw/mdw/powm-sec'
[secnet] / ipaddrset.py
CommitLineData
6437945a
IJ
1"""IP address set manipulation, built on top of ipaddr.py"""
2
c215a4bc
IJ
3# This file is Free Software. It was originally written for secnet.
4#
6437945a
IJ
5# Copyright 2014 Ian Jackson
6#
c215a4bc
IJ
7# You may redistribute secnet as a whole and/or modify it under the
8# terms of the GNU General Public License as published by the Free
9# Software Foundation; either version 3, or (at your option) any
10# later version.
6437945a 11#
c215a4bc
IJ
12# You may redistribute this file and/or modify it under the terms of
13# the GNU General Public License as published by the Free Software
14# Foundation; either version 2, or (at your option) any later version.
15# Note however that this version of ipaddrset.py uses the Python
16# ipaddr library from Google, which is licenced only under the Apache
17# Licence, version 2.0, which is only compatible with the GNU GPL v3
18# (or perhaps later versions), and not with the GNU GPL v2.
6437945a 19#
c215a4bc 20# This software is distributed in the hope that it will be useful,
6437945a
IJ
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23# GNU General Public License for more details.
24#
25# You should have received a copy of the GNU General Public License
c215a4bc
IJ
26# along with this software; if not, see
27# https://www.gnu.org/licenses/gpl.html.
6437945a
IJ
28
29import ipaddr
30
31_vsns = [6,4]
32
33class IPAddressSet:
34 "A set of IP addresses"
35
36 # constructors
37 def __init__(self,l=[]):
38 "New set contains each ipaddr.IPNetwork in the sequence l"
39 self._v = {}
40 for v in _vsns:
41 self._v[v] = [ ]
42 self.append(l)
43
44 # housekeeping and representation
45 def _compact(self):
46 for v in _vsns:
47 self._v[v] = ipaddr.collapse_address_list(self._v[v])
48 def __repr__(self):
49 return "IPAddressSet(%s)" % self.networks()
50 def str(self,comma=",",none="-"):
51 "Human-readable string with controllable delimiters"
52 if self:
53 return comma.join(map(str, self.networks()))
54 else:
55 return none
56 def __str__(self):
57 return self.str()
58
59 # mutators
60 def append(self,l):
61 "Appends each ipaddr.IPNetwork in the sequence l to self"
62 self._append(l)
63 self._compact()
64
65 def _append(self,l):
66 "Appends each ipaddr.IPNetwork in the sequence l to self"
67 for a in l:
68 self._v[a.version].append(a)
69
70 # enquirers including standard comparisons
71 def __nonzero__(self):
72 for v in _vsns:
73 if self._v[v]:
74 return True
75 return False
76
77 def __eq__(self,other):
78 for v in _vsns:
79 if self._v[v] != other._v[v]:
80 return False
81 return True
82 def __ne__(self,other): return not self.__eq__(other)
83 def __ge__(self,other):
84 """True iff self completely contains IPAddressSet other"""
85 for o in other:
86 if not self._contains_net(o):
87 return False
88 return True
89 def __le__(self,other): return other.__ge__(self)
90 def __gt__(self,other): return self!=other and other.__ge__(self)
91 def __lt__(self,other): return other.__gt__(self)
92
93 def __cmp__(self,other):
94 if self==other: return 0
95 if self>=other: return +1
96 if self<=other: return -1
97 return NotImplemented
98
99 def __iter__(self):
100 "Iterates over minimal list of distinct IPNetworks in this set"
101 for v in _vsns:
102 for i in self._v[v]:
103 yield i
104
105 def networks(self):
106 "Returns miminal list of distinct IPNetworks in this set"
107 return [i for i in self]
108
109 # set operations
110 def intersection(self,other):
111 "Returns the intersection; does not modify self"
112 r = IPAddressSet()
113 for v in _vsns:
114 for i in self._v[v]:
115 for j in other._v[v]:
116 if i.overlaps(j):
117 if i.prefixlen > j.prefixlen:
118 r._append([i])
119 else:
120 r._append([j])
121 return r
122 def union(self,other):
123 "Returns the union; does not modify self"
124 r = IPAddressSet()
125 r._append(self.networks())
126 r._append(other.networks())
127 r._compact()
128 return r
129
130 def _contains_net(self,n):
131 """True iff self completely contains IPNetwork n"""
132 for i in self:
133 if i.overlaps(n) and n.prefixlen >= i.prefixlen:
134 return True
135 return False
136
137 def contains(self,thing):
138 """Returns True iff self completely contains thing.
139 thing may be an IPNetwork or an IPAddressSet"""
140 try:
141 v = [thing.version]
142 except KeyError:
143 v = None
144 if v:
145 return self._contains_net(ipaddr.IPNetwork(thing))
146 else:
147 return self.__ge__(thing)
148
149def complete_set():
150 "Returns a set containing all addresses"
151 s=IPAddressSet()
152 for v in _vsns:
153 a=ipaddr.IPAddress(0,v)
154 n=ipaddr.IPNetwork("%s/0" % a)
155 s.append([n])
156 return s