chiark / gitweb /
Keepalive option: Start trying to rekey as soon as peer shuts down
[secnet.git] / ipaddrset.py
1 """IP address set manipulation, built on top of ipaddr.py"""
2
3 # This file is Free Software.  It was originally written for secnet.
4 #
5 # Copyright 2014 Ian Jackson
6 #
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.
11 #
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.
19 #
20 # This software is distributed in the hope that it will be useful,
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
26 # along with this software; if not, see
27 # https://www.gnu.org/licenses/gpl.html.
28
29 import ipaddr
30
31 _vsns = [6,4]
32
33 class 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
149 def 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