nettoolkit 0.0.3__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/__init__.py +49 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/__pycache__/__init__.cpython-38.pyc +0 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/__pycache__/addressing.cpython-38.pyc +0 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/__pycache__/gpl.cpython-38.pyc +0 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/__pycache__/hierarchy.cpython-38.pyc +0 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/__pycache__/hierarchy_rules.cpython-38.pyc +0 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/__pycache__/jset.cpython-38.pyc +0 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/addressing.py +920 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/gpl.py +1207 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/hierarchy.py +558 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/hierarchy_rules.py +229 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/jset.py +109 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit-0.0.3-py3.8.egg-info/PKG-INFO +41 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit-0.0.3-py3.8.egg-info/SOURCES.txt +12 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit-0.0.3-py3.8.egg-info/dependency_links.txt +1 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit-0.0.3-py3.8.egg-info/top_level.txt +1 -0
Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/addressing.py
ADDED
|
@@ -0,0 +1,920 @@
|
|
|
1
|
+
|
|
2
|
+
from .gpl import STR, LST
|
|
3
|
+
|
|
4
|
+
# from errors import incorrectinput
|
|
5
|
+
incorrectinput = 'INCORRECT SUBNET OR SUBNET MASK DETECTED NULL RETURNED'
|
|
6
|
+
|
|
7
|
+
# ----------------------------------------------------------------------------
|
|
8
|
+
# Module Functions
|
|
9
|
+
# ----------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
def bin_mask(mask):
|
|
12
|
+
mask = int(mask)
|
|
13
|
+
decmask = mask*str(1) + (32-mask)*str(0)
|
|
14
|
+
o1 = str(int(decmask[ 0: 8] , 2))
|
|
15
|
+
o2 = str(int(decmask[ 8: 16], 2))
|
|
16
|
+
o3 = str(int(decmask[16: 24], 2))
|
|
17
|
+
o4 = str(int(decmask[24: 32], 2))
|
|
18
|
+
return o1+'.'+o2+'.'+o3+'.'+o4
|
|
19
|
+
def invalid_subnet(subnet): return f"Not a VALID Subnet {subnet}"
|
|
20
|
+
def to_dec_mask(dotted_mask): return bin2decmask(binsubnet(dotted_mask))
|
|
21
|
+
def bin2dec(binnet): return int(binnet, 2)
|
|
22
|
+
def bin2decmask(binmask): return binmask.count('1')
|
|
23
|
+
def binsubnet(subnet):
|
|
24
|
+
"""convert subnet to binary:0's and 1's """
|
|
25
|
+
try:
|
|
26
|
+
if STR.found(subnet, "."): version, split_by, bit_per_oct = 4, ".", 8
|
|
27
|
+
if STR.found(subnet, ":"): version, split_by, bit_per_oct = 6, ":", 16
|
|
28
|
+
s = ''
|
|
29
|
+
octs = subnet.split("/")[0].split(split_by)
|
|
30
|
+
for o in octs:
|
|
31
|
+
if version == 4:
|
|
32
|
+
bo = str(bin(int(o)))[2:]
|
|
33
|
+
elif version == 6:
|
|
34
|
+
bo = str(bin(int(o, bit_per_oct)))[2:]
|
|
35
|
+
lbo = len(bo)
|
|
36
|
+
pzero = '0'*(bit_per_oct - lbo)
|
|
37
|
+
s = s + pzero + bo
|
|
38
|
+
return s
|
|
39
|
+
except:
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def addressing(subnet):
|
|
44
|
+
'''main function proiving ip-subnet object for various functions on it
|
|
45
|
+
--> ipsubnet object
|
|
46
|
+
|
|
47
|
+
:param: subnet: either ipv4 or ipv6 subnet with /mask
|
|
48
|
+
:param type: str
|
|
49
|
+
|
|
50
|
+
:param decmask: decimal mask notation only in case of IPv4 (optional)
|
|
51
|
+
:param type: str
|
|
52
|
+
'''
|
|
53
|
+
v_obj = Validation(subnet)
|
|
54
|
+
if v_obj.validated: return v_obj.ip_obj
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def get_summaries(*net_list):
|
|
58
|
+
'''summarize the provided network prefixes
|
|
59
|
+
--> list of sorted summary netwoks
|
|
60
|
+
|
|
61
|
+
:param: *net_list: network prefixes (variable arguments)
|
|
62
|
+
:param type: str/list/tuple/set
|
|
63
|
+
|
|
64
|
+
'''
|
|
65
|
+
if not isinstance(net_list, (list, tuple, set)): return None
|
|
66
|
+
s = Summary(*net_list)
|
|
67
|
+
s.calculate()
|
|
68
|
+
summaries = s.prefixes
|
|
69
|
+
i = 0
|
|
70
|
+
while True:
|
|
71
|
+
i += 1
|
|
72
|
+
if i >= MAX_RECURSION_DEPTH: break
|
|
73
|
+
ss = Summary(*summaries)
|
|
74
|
+
ss.calculate()
|
|
75
|
+
if summaries == ss.prefixes: break
|
|
76
|
+
summaries = ss.prefixes
|
|
77
|
+
return sorted(summaries)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def isSplittedRoute(line):
|
|
81
|
+
""" 1: No single line,
|
|
82
|
+
0 : Yes splitted line [line1]
|
|
83
|
+
-1: Yes splitted line [line2]
|
|
84
|
+
"""
|
|
85
|
+
if found(line, ','):
|
|
86
|
+
return 1 if len(line.split()) > 5 else -1
|
|
87
|
+
else:
|
|
88
|
+
return 0
|
|
89
|
+
|
|
90
|
+
def isSubset(pfx, supernet):
|
|
91
|
+
if not isinstance(pfx, (str, IPv4)):
|
|
92
|
+
raise Exception("INPUTERROR")
|
|
93
|
+
if not isinstance(supernet, (str, IPv4)):
|
|
94
|
+
raise Exception("INPUTERROR")
|
|
95
|
+
if isinstance(supernet, str): supernet = addressing(supernet)
|
|
96
|
+
if isinstance(pfx, str): pfx = addressing(pfx)
|
|
97
|
+
if supernet.mask <= pfx.mask:
|
|
98
|
+
supernet_bin = binsubnet(supernet.subnet)
|
|
99
|
+
pfx_bin = binsubnet(pfx.subnet)
|
|
100
|
+
if supernet_bin[0:supernet.mask] == pfx_bin[0:supernet.mask]:
|
|
101
|
+
return True
|
|
102
|
+
return False
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
# ----------------------------------------------------------------------------
|
|
106
|
+
# Validation Class - doing subnet validation and version detection
|
|
107
|
+
# ----------------------------------------------------------------------------
|
|
108
|
+
class Validation():
|
|
109
|
+
'''ip-subnet validation class
|
|
110
|
+
:param subnet: ipv4 or ipv6 subnet with "/" mask
|
|
111
|
+
:param type: str
|
|
112
|
+
|
|
113
|
+
'''
|
|
114
|
+
|
|
115
|
+
def __init__(self, subnet):
|
|
116
|
+
'''ip-subnet validation class
|
|
117
|
+
:param subnet: ipv4 or ipv6 subnet with "/" mask
|
|
118
|
+
:param type: str
|
|
119
|
+
|
|
120
|
+
'''
|
|
121
|
+
self.mask = None
|
|
122
|
+
self.subnet = subnet
|
|
123
|
+
self.version = self._version()
|
|
124
|
+
self.validated = False
|
|
125
|
+
self._check_ip_object()
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _version(self):
|
|
129
|
+
if STR.found(self.subnet, ":"):
|
|
130
|
+
return 6
|
|
131
|
+
elif STR.found(self.subnet, "."):
|
|
132
|
+
return 4
|
|
133
|
+
else:
|
|
134
|
+
return 0
|
|
135
|
+
|
|
136
|
+
def _check_ip_object(self):
|
|
137
|
+
object_map = {4: IPv4, 6: IPv6}
|
|
138
|
+
func_map = {4: self.check_v4_input, 6: self.check_v6_input}
|
|
139
|
+
if self.version in object_map:
|
|
140
|
+
self.validated = func_map[self.version]()
|
|
141
|
+
if not self.validated: return None
|
|
142
|
+
self.ip_obj = object_map[self.version](self.subnet)
|
|
143
|
+
self.validated = self.ip_obj + 0 == self.ip_obj.NetworkIP(False)
|
|
144
|
+
if not self.validated: return None
|
|
145
|
+
else:
|
|
146
|
+
raise Exception(invalid_subnet(self.subnet))
|
|
147
|
+
|
|
148
|
+
def check_v4_input(self):
|
|
149
|
+
'''Property to validate provided v4 subnet
|
|
150
|
+
'''
|
|
151
|
+
# ~~~~~~~~~ Mask Check ~~~~~~~~~
|
|
152
|
+
try:
|
|
153
|
+
self.mask = self.subnet.split("/")[1]
|
|
154
|
+
except:
|
|
155
|
+
self.mask = 32
|
|
156
|
+
self.subnet = self.subnet + "/32"
|
|
157
|
+
try:
|
|
158
|
+
self.mask = int(self.mask)
|
|
159
|
+
if not all([self.mask>=0, self.mask<=32]):
|
|
160
|
+
raise Exception(f"Invalid mask length {self.mask}")
|
|
161
|
+
except:
|
|
162
|
+
raise Exception(f"Incorrect Mask {self.mask}")
|
|
163
|
+
|
|
164
|
+
# ~~~~~~~~~ Subnet Check ~~~~~~~~~
|
|
165
|
+
try:
|
|
166
|
+
octs = self.subnet.split("/")[0].split(".")
|
|
167
|
+
if len(octs) != 4:
|
|
168
|
+
raise Exception(f"Invalid Subnet Length {len(octs)}")
|
|
169
|
+
for i in range(4):
|
|
170
|
+
if not all([int(octs[i])>=0, int(octs[i])<=255 ]):
|
|
171
|
+
raise Exception(f"Invalid Subnet Octet {i}")
|
|
172
|
+
return True
|
|
173
|
+
except:
|
|
174
|
+
raise Exception(f"Unidentified Subnet: {self.subnet}")
|
|
175
|
+
|
|
176
|
+
def check_v6_input(self):
|
|
177
|
+
'''Property to validate provided v6 subnet
|
|
178
|
+
'''
|
|
179
|
+
try:
|
|
180
|
+
# ~~~~~~~~~ Mask Check ~~~~~~~~~
|
|
181
|
+
self.mask = self.subnet.split("/")[1]
|
|
182
|
+
except:
|
|
183
|
+
self.mask = 128
|
|
184
|
+
self.subnet = self.subnet + "/128"
|
|
185
|
+
try:
|
|
186
|
+
self.mask = int(self.mask)
|
|
187
|
+
if not all([self.mask>=0, self.mask<=128]):
|
|
188
|
+
raise Exception(f"Invalid mask length {self.mask}")
|
|
189
|
+
|
|
190
|
+
# ~~~~~~~~~ Subnet ~~~~~~~~~
|
|
191
|
+
sip = self.subnet.split("/")[0].split("::")
|
|
192
|
+
|
|
193
|
+
# ~~~~~~~~~ Check Subnet squeezers ~~~~~~~~~
|
|
194
|
+
if len(sip) > 2:
|
|
195
|
+
raise Exception("Invalid Subnet, Squeezers detected > 1")
|
|
196
|
+
|
|
197
|
+
# ~~~~~~~~~ Subnet Length ~~~~~~~~~
|
|
198
|
+
lsip = sip[0].split(":")
|
|
199
|
+
try:
|
|
200
|
+
rsip = sip[1].split(":")
|
|
201
|
+
except:
|
|
202
|
+
rsip = []
|
|
203
|
+
if len(lsip)+len(rsip) > 8:
|
|
204
|
+
raise Exception(f"Invalid Subnet Length {len(lsip)+len(rsip)}")
|
|
205
|
+
|
|
206
|
+
# ~~~~~~~~~ Validate Hextates ~~~~~~~~~
|
|
207
|
+
for hxt in lsip+rsip:
|
|
208
|
+
try:
|
|
209
|
+
if hxt != '' :
|
|
210
|
+
hex(int(hxt, 16))
|
|
211
|
+
except:
|
|
212
|
+
raise Exception(f"Invalid Hextate {hxt}")
|
|
213
|
+
|
|
214
|
+
# ~~~~~~~~~ All Good ~~~~~~~~~
|
|
215
|
+
return True
|
|
216
|
+
|
|
217
|
+
except:
|
|
218
|
+
raise Exception("Unidentified Subnet")
|
|
219
|
+
|
|
220
|
+
# --------------------------------------------------------------------------------------------------
|
|
221
|
+
# Parent IP class defining default methods for v4 and v6 objects
|
|
222
|
+
# --------------------------------------------------------------------------------------------------
|
|
223
|
+
|
|
224
|
+
class IP():
|
|
225
|
+
def __init__(self, subnet):
|
|
226
|
+
self.subnet = subnet
|
|
227
|
+
self.mask = int(self.subnet.split("/")[1])
|
|
228
|
+
self.net = self.subnet.split("/")[0]
|
|
229
|
+
def __hash__(self):
|
|
230
|
+
try:
|
|
231
|
+
return bin2dec(binsubnet(self.NetworkIP()))
|
|
232
|
+
except:
|
|
233
|
+
raise Exception(f"UnhashableInput: {self.subnet}")
|
|
234
|
+
def __str__(self): return self.subnet
|
|
235
|
+
def __repr__(self): return self.subnet
|
|
236
|
+
def __len__(self):
|
|
237
|
+
if self.version == 4:
|
|
238
|
+
return bin2dec(binsubnet(self.broadcast_address())) - bin2dec(binsubnet(self.subnet_zero())) + 1
|
|
239
|
+
if self.version == 6:
|
|
240
|
+
raise Exception("Excessive Integer Value Assignment not possible. "
|
|
241
|
+
"Use IPv6.len() method to get the length of object"
|
|
242
|
+
)
|
|
243
|
+
def __gt__(self, ip): return bin2dec(binsubnet(self.NetworkIP())) - bin2dec(binsubnet(ip.broadcast_address())) > 0
|
|
244
|
+
def __lt__(self, ip): return bin2dec(binsubnet(self.NetworkIP())) - bin2dec(binsubnet(ip.broadcast_address())) < 0
|
|
245
|
+
def __eq__(self, ip): return bin2dec(binsubnet(self.NetworkIP())) - bin2dec(binsubnet(ip.broadcast_address())) == 0
|
|
246
|
+
def __add__(self, n):
|
|
247
|
+
'''add n-ip's to given subnet and return udpated subnet'''
|
|
248
|
+
if isinstance(n, int):
|
|
249
|
+
return self.n_thIP(n, False, "_")
|
|
250
|
+
elif isinstance(n, IPv4):
|
|
251
|
+
summary = get_summaries(self, n)
|
|
252
|
+
if len(summary) == 1:
|
|
253
|
+
return get_summaries(self, n)[0]
|
|
254
|
+
else:
|
|
255
|
+
raise Exception(
|
|
256
|
+
"Inconsistant subnets cannot be added "
|
|
257
|
+
"and >2 instances of IPv4/IPv6 Object add not allowed. please check inputs or "
|
|
258
|
+
"Use 'get_summaries' function instead"
|
|
259
|
+
)
|
|
260
|
+
def __sub__(self, n): return self.n_thIP(-1*n, False, "_")
|
|
261
|
+
def __truediv__(self, n): return self._sub_subnets(n)
|
|
262
|
+
def __iter__(self): return self._subnetips()
|
|
263
|
+
def __getitem__(self, n):
|
|
264
|
+
try:
|
|
265
|
+
return self.n_thIP(n, False)
|
|
266
|
+
except:
|
|
267
|
+
l = []
|
|
268
|
+
for x in self._subnetips(n.start, n.stop):
|
|
269
|
+
l.append(x)
|
|
270
|
+
return tuple(l)
|
|
271
|
+
|
|
272
|
+
# get n-number of subnets of given super-net
|
|
273
|
+
def _sub_subnets(self, n):
|
|
274
|
+
_iplst = []
|
|
275
|
+
for i1, x1 in enumerate(range(self.bit_length)):
|
|
276
|
+
p = 2**x1
|
|
277
|
+
if p >= n: break
|
|
278
|
+
_nsm = self.mask + i1
|
|
279
|
+
_nip = int(binsubnet(self.subnet_zero()), 2)
|
|
280
|
+
_bcip = int(binsubnet(self.broadcast_address()), 2)
|
|
281
|
+
_iis = (_bcip - _nip + 1) // p
|
|
282
|
+
for i2, x2 in enumerate(range(_nip, _bcip, _iis)):
|
|
283
|
+
_iplst.append(self.n_thIP(i2*_iis)+ "/" + str(_nsm))
|
|
284
|
+
return tuple(_iplst)
|
|
285
|
+
|
|
286
|
+
# yields IP Address(es) of the provided subnet
|
|
287
|
+
def _subnetips(self, begin=0, end=0):
|
|
288
|
+
_nip = int(binsubnet(self.subnet_zero()), 2)
|
|
289
|
+
if end == 0:
|
|
290
|
+
_bcip = int(binsubnet(self.broadcast_address()), 2)
|
|
291
|
+
else:
|
|
292
|
+
_bcip = _nip + (end-begin)
|
|
293
|
+
for i2, x2 in enumerate(range(_nip, _bcip)):
|
|
294
|
+
if begin>0: i2 = i2+begin
|
|
295
|
+
yield self.n_thIP(i2)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
# ----------------------------------------------------------------------------
|
|
300
|
+
# IP Subnet (IPv6) class
|
|
301
|
+
# ----------------------------------------------------------------------------
|
|
302
|
+
|
|
303
|
+
class IPv6(IP):
|
|
304
|
+
'''Defines IPv6 object and its various operations'''
|
|
305
|
+
|
|
306
|
+
version = 6
|
|
307
|
+
bit_length = 128
|
|
308
|
+
|
|
309
|
+
# Object Initializer
|
|
310
|
+
def __init__(self, subnet=''):
|
|
311
|
+
super().__init__(subnet)
|
|
312
|
+
self._network_ip()
|
|
313
|
+
self.__actualv6subnet = False # breaked subnet expanded
|
|
314
|
+
self._network_address_bool = False # Subnet zero available/not
|
|
315
|
+
|
|
316
|
+
def len(self): return bin2dec(binsubnet(self.broadcast_address())) - bin2dec(binsubnet(self.subnet_zero())) + 1
|
|
317
|
+
|
|
318
|
+
# ------------------------------------------------------------------------
|
|
319
|
+
# Private Methods
|
|
320
|
+
# ------------------------------------------------------------------------
|
|
321
|
+
|
|
322
|
+
# update Subnet to actual length / expand zeros
|
|
323
|
+
def _to_actualsize(self):
|
|
324
|
+
try:
|
|
325
|
+
if not self.__actualv6subnet:
|
|
326
|
+
p = ''
|
|
327
|
+
sip = self.subnet.split("/")[0].split("::")
|
|
328
|
+
if len(sip) == 2:
|
|
329
|
+
# ~~~~~~ No padding, inserting zeros in middle ~~~~~~~
|
|
330
|
+
for x in range(1, 9):
|
|
331
|
+
p = STR.string_concate(p, self._get_hext(hexTnum=x), conj=':')
|
|
332
|
+
self.subnet = p
|
|
333
|
+
else :
|
|
334
|
+
# ~~~~~~~ pad leading zeros ~~~~~~~
|
|
335
|
+
lsip = sip[0].split(":")
|
|
336
|
+
for x in range(8-len(lsip), 0, -1):
|
|
337
|
+
p = STR.string_concate(p, '0', conj=":")
|
|
338
|
+
if p != '':
|
|
339
|
+
self.subnet = p + ':' + self.subnet
|
|
340
|
+
self.__actualv6subnet = True
|
|
341
|
+
except:
|
|
342
|
+
return False
|
|
343
|
+
|
|
344
|
+
# IP Portion of Input
|
|
345
|
+
def _network_ip(self):
|
|
346
|
+
try:
|
|
347
|
+
self.network = self.subnet.split("/")[0]
|
|
348
|
+
return self.network
|
|
349
|
+
except:
|
|
350
|
+
raise Exception(f"NoValidIPv6SubnetDetected: {self.subnet}")
|
|
351
|
+
return None
|
|
352
|
+
|
|
353
|
+
# Padding subnet with ":0" or ":ffff"
|
|
354
|
+
@staticmethod
|
|
355
|
+
def _pad(padwhat='0', counts=0):
|
|
356
|
+
s = ''
|
|
357
|
+
for x in range(counts):
|
|
358
|
+
s = s + ":" + padwhat
|
|
359
|
+
return s
|
|
360
|
+
|
|
361
|
+
# Return a specific Hextate (hexTnum) from IPV6 address
|
|
362
|
+
def _get_hext(self, hexTnum, s=''):
|
|
363
|
+
if s == '':
|
|
364
|
+
s = self.subnet.split("/")[0]
|
|
365
|
+
try:
|
|
366
|
+
if s != '' and all([hexTnum>0, hexTnum<=8]):
|
|
367
|
+
sip = s.split("/")[0].split("::")
|
|
368
|
+
lsip = sip[0].split(":")
|
|
369
|
+
if hexTnum <= len(lsip):
|
|
370
|
+
return lsip[hexTnum-1]
|
|
371
|
+
else:
|
|
372
|
+
rsip = sip[1].split(":")
|
|
373
|
+
if rsip[0] == '': rsip = []
|
|
374
|
+
if 8-hexTnum < len(rsip):
|
|
375
|
+
return rsip[(9-hexTnum)*-1]
|
|
376
|
+
else:
|
|
377
|
+
return '0'
|
|
378
|
+
else:
|
|
379
|
+
raise Exception(incorrectinput)
|
|
380
|
+
return None
|
|
381
|
+
except:
|
|
382
|
+
raise Exception(incorrectinput)
|
|
383
|
+
return None
|
|
384
|
+
|
|
385
|
+
# Return Number of Network Hextates (hxts) from IPV6 address
|
|
386
|
+
def _get_hextates(self, hxts=1, s=''):
|
|
387
|
+
ox = ''
|
|
388
|
+
for o in range(1, hxts+1):
|
|
389
|
+
ox = STR.string_concate(ox, self._get_hext(o, s=s), conj=':')
|
|
390
|
+
return ox+":"
|
|
391
|
+
|
|
392
|
+
# NETWORK / BC Address Calculation : addtype = 'NET' , 'BC'
|
|
393
|
+
def _endpoint(self, addtype='NET'):
|
|
394
|
+
self._to_actualsize()
|
|
395
|
+
if self.mask != '' and self.mask<128: # Non host-only subnets
|
|
396
|
+
x = 0 if addtype == 'NET' else -1
|
|
397
|
+
padIP = '0' if addtype == 'NET' else 'ffff'
|
|
398
|
+
(asilast, avs) = ([], [])
|
|
399
|
+
fixedOctets = self.mask//16
|
|
400
|
+
|
|
401
|
+
## get full list of available subnets in selected Hexate.
|
|
402
|
+
while x < 65536:
|
|
403
|
+
asilast.append(x)
|
|
404
|
+
x = x + (2**(16-(self.mask-((fixedOctets)*16))))
|
|
405
|
+
|
|
406
|
+
## check avlbl subnet and choose less then given one.
|
|
407
|
+
for netx in asilast:
|
|
408
|
+
avs.append(self._get_hextates(fixedOctets)
|
|
409
|
+
+ str(hex(netx))[2:])
|
|
410
|
+
if addtype =='BC':
|
|
411
|
+
last_subnet = avs[-1]
|
|
412
|
+
if int(self._get_hext(fixedOctets+1), 16) < netx:
|
|
413
|
+
break
|
|
414
|
+
if addtype =='NET':
|
|
415
|
+
last_subnet = avs[-1]
|
|
416
|
+
|
|
417
|
+
## Return subnet by padding zeros.
|
|
418
|
+
self.fixedOctets = fixedOctets
|
|
419
|
+
return last_subnet+self._pad(padIP, 7-fixedOctets)
|
|
420
|
+
|
|
421
|
+
else: # host-only subnet
|
|
422
|
+
return self.network
|
|
423
|
+
|
|
424
|
+
def _add_ip_to_network_address(self, num=0, _=''):
|
|
425
|
+
'''-->Adds num of IP to Network IP and return address'''
|
|
426
|
+
self._network_address
|
|
427
|
+
s = self._subnet_zero
|
|
428
|
+
if _ != '':
|
|
429
|
+
s = self.subnet
|
|
430
|
+
_7o = self._get_hextates(7, s)
|
|
431
|
+
_8o = int(self._get_hext(8, s)) + num
|
|
432
|
+
return _7o + str(hex(_8o)[2:])
|
|
433
|
+
|
|
434
|
+
@property
|
|
435
|
+
def _broadcast_address(self): return self._endpoint(addtype='BC')
|
|
436
|
+
@property
|
|
437
|
+
def _network_address(self):
|
|
438
|
+
'''-->Returns only NETWORK ADDRESS for given subnet'''
|
|
439
|
+
if not self._network_address_bool:
|
|
440
|
+
self._subnet_zero = self._endpoint(addtype='NET')
|
|
441
|
+
self._network_address_bool = True
|
|
442
|
+
return self._subnet_zero
|
|
443
|
+
NetworkAddress = _network_address
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
# ------------------------------------------------------------------------
|
|
447
|
+
# Public Methods
|
|
448
|
+
# ------------------------------------------------------------------------
|
|
449
|
+
|
|
450
|
+
# Return a specific Hextate (hexTnum) from IPV6 address
|
|
451
|
+
def get_hext(self, hexTnum): return self._get_hext(hexTnum)
|
|
452
|
+
getHext = get_hext
|
|
453
|
+
|
|
454
|
+
def subnet_zero(self, withMask=True):
|
|
455
|
+
'''--> Network Address with/without mask for given subnet
|
|
456
|
+
'''
|
|
457
|
+
if withMask :
|
|
458
|
+
return self._network_address + "/" + str(self.mask)
|
|
459
|
+
else:
|
|
460
|
+
return self._network_address
|
|
461
|
+
NetworkIP = subnet_zero
|
|
462
|
+
|
|
463
|
+
def broadcast_address(self, withMask=True):
|
|
464
|
+
'''--> Broadcast Address with/without mask for given subnet
|
|
465
|
+
'''
|
|
466
|
+
if withMask :
|
|
467
|
+
return self._broadcast_address + "/" + str(self.mask)
|
|
468
|
+
else:
|
|
469
|
+
return self._broadcast_address
|
|
470
|
+
BroadcastIP = broadcast_address
|
|
471
|
+
|
|
472
|
+
def n_thIP(self, n=0, withMask=False, _=''):
|
|
473
|
+
'''--> n-th IP with/without mask from given subnet
|
|
474
|
+
'''
|
|
475
|
+
ip = self._add_ip_to_network_address(n, _)
|
|
476
|
+
mask = self.decimalMask
|
|
477
|
+
return ip+"/"+mask if withMask else ip
|
|
478
|
+
|
|
479
|
+
@property
|
|
480
|
+
def decimalMask(self):
|
|
481
|
+
'''--> decimal mask of given subnet'''
|
|
482
|
+
return str(self.mask)
|
|
483
|
+
decmask = decimalMask
|
|
484
|
+
|
|
485
|
+
## - NA - for IPv6 ##
|
|
486
|
+
@property
|
|
487
|
+
def binmask(self): return None
|
|
488
|
+
@property
|
|
489
|
+
def invmask(self): return None
|
|
490
|
+
def ipdecmask(self, n=0): return self.n_thIP(n, True)
|
|
491
|
+
def ipbinmask(self, n=0): return None
|
|
492
|
+
def ipinvmask(self, n=0): return None
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
# ----------------------------------------------------------------------------
|
|
496
|
+
# IPv4 Subnet (IPv4) class
|
|
497
|
+
# ----------------------------------------------------------------------------
|
|
498
|
+
class IPv4(IP):
|
|
499
|
+
'''Defines IPv4 object and its various operations
|
|
500
|
+
::hashable object::
|
|
501
|
+
|
|
502
|
+
'''
|
|
503
|
+
|
|
504
|
+
version = 4
|
|
505
|
+
bit_length = 32
|
|
506
|
+
|
|
507
|
+
# ------------------------------------------------------------------------
|
|
508
|
+
# Private methods / Properties
|
|
509
|
+
# ------------------------------------------------------------------------
|
|
510
|
+
|
|
511
|
+
# binary mask return property
|
|
512
|
+
@property
|
|
513
|
+
def _binmask(self):
|
|
514
|
+
try:
|
|
515
|
+
pone ='1'*self.mask
|
|
516
|
+
pzero = '0'*(32-self.mask)
|
|
517
|
+
return pone+pzero
|
|
518
|
+
except:
|
|
519
|
+
pass
|
|
520
|
+
|
|
521
|
+
# Inverse mask return property
|
|
522
|
+
@property
|
|
523
|
+
def _invmask(self):
|
|
524
|
+
try:
|
|
525
|
+
pone ='0'*self.mask
|
|
526
|
+
pzero = '1'*(32-self.mask)
|
|
527
|
+
return pone+pzero
|
|
528
|
+
except:
|
|
529
|
+
pass
|
|
530
|
+
|
|
531
|
+
@staticmethod
|
|
532
|
+
def _pad_zeros(bins):
|
|
533
|
+
return '0'*(34 - len(str(bins)))+bins[2:]
|
|
534
|
+
@staticmethod
|
|
535
|
+
def _octets_bin2dec(binnet):
|
|
536
|
+
return [bin2dec(binnet[x:x+8]) for x in range(0, 32, 8) ]
|
|
537
|
+
def _bin_and(self, binone, bintwo):
|
|
538
|
+
return self._pad_zeros(bin(int(binone.encode('ascii'), 2) & int(bintwo.encode('ascii'), 2) ))
|
|
539
|
+
def _bin_or(self, binone, bintwo):
|
|
540
|
+
return self._pad_zeros(bin(int(binone.encode('ascii'), 2) | int(bintwo.encode('ascii'), 2) ))
|
|
541
|
+
|
|
542
|
+
# ------------------------------------------------------------------------
|
|
543
|
+
# Available Methods & Public properties of class
|
|
544
|
+
# ------------------------------------------------------------------------
|
|
545
|
+
|
|
546
|
+
def subnet_zero(self, withMask=True):
|
|
547
|
+
'''Network IP Address of subnet from provided IP/Subnet'''
|
|
548
|
+
try:
|
|
549
|
+
s = binsubnet(self.subnet)
|
|
550
|
+
bm = self._binmask
|
|
551
|
+
net = LST.list_to_octet(self._octets_bin2dec(self._bin_and(s, bm )))
|
|
552
|
+
if withMask :
|
|
553
|
+
return net + "/" + str(self.mask)
|
|
554
|
+
else:
|
|
555
|
+
return net
|
|
556
|
+
except:
|
|
557
|
+
pass
|
|
558
|
+
NetworkIP = subnet_zero
|
|
559
|
+
|
|
560
|
+
def broadcast_address(self, withMask=False):
|
|
561
|
+
'''Broadcast IP Address of subnet from provided IP/Subnet'''
|
|
562
|
+
try:
|
|
563
|
+
s = binsubnet(self.subnet)
|
|
564
|
+
im = self._invmask
|
|
565
|
+
bc = LST.list_to_octet(self._octets_bin2dec(self._bin_or(s, im )))
|
|
566
|
+
if withMask :
|
|
567
|
+
return bc + "/" + str(self.mask)
|
|
568
|
+
else:
|
|
569
|
+
return bc
|
|
570
|
+
except:
|
|
571
|
+
pass
|
|
572
|
+
BroadcastIP = broadcast_address
|
|
573
|
+
|
|
574
|
+
def n_thIP(self, n=0, withMask=False, _='', summary_calc=False):
|
|
575
|
+
'''n-th IP Address of subnet from provided IP/Subnet'''
|
|
576
|
+
s = binsubnet(self.subnet)
|
|
577
|
+
if _ == '':
|
|
578
|
+
bm = self._binmask
|
|
579
|
+
addedbin = self._pad_zeros(bin(int(self._bin_and(s, bm), 2)+n))
|
|
580
|
+
else:
|
|
581
|
+
addedbin = self._pad_zeros(bin(int(s.encode('ascii'), 2 )+n))
|
|
582
|
+
|
|
583
|
+
if (any([addedbin > binsubnet(self.broadcast_address()),
|
|
584
|
+
addedbin < binsubnet(self.NetworkIP())]) and
|
|
585
|
+
not summary_calc
|
|
586
|
+
):
|
|
587
|
+
raise Exception("Address Out of Range")
|
|
588
|
+
|
|
589
|
+
else:
|
|
590
|
+
ip = LST.list_to_octet(self._octets_bin2dec(addedbin))
|
|
591
|
+
if withMask :
|
|
592
|
+
return ip + "/" + str(self.mask)
|
|
593
|
+
else:
|
|
594
|
+
return ip
|
|
595
|
+
|
|
596
|
+
@property
|
|
597
|
+
def decmask(self):
|
|
598
|
+
'''Decimal Mask from provided IP/Subnet - Numeric/Integer'''
|
|
599
|
+
return self.mask
|
|
600
|
+
decimalMask = decmask
|
|
601
|
+
|
|
602
|
+
@property
|
|
603
|
+
def binmask(self):
|
|
604
|
+
'''Binary Mask from provided IP/Subnet'''
|
|
605
|
+
return LST.list_to_octet(self._octets_bin2dec(self._binmask))
|
|
606
|
+
|
|
607
|
+
@property
|
|
608
|
+
def invmask(self):
|
|
609
|
+
'''Inverse Mask from provided IP/Subnet'''
|
|
610
|
+
return LST.list_to_octet(self._octets_bin2dec(self._invmask))
|
|
611
|
+
|
|
612
|
+
def ipdecmask(self, n=0):
|
|
613
|
+
'''IP with Decimal Mask for provided IP/Subnet,
|
|
614
|
+
n ==>
|
|
615
|
+
n-th ip of subnet will appear in output if provided,
|
|
616
|
+
subnet0 ip will appear in output if not provided
|
|
617
|
+
default: n = 0, for Network IP
|
|
618
|
+
'''
|
|
619
|
+
try:
|
|
620
|
+
return self[n] + "/" + str(self.mask)
|
|
621
|
+
except:
|
|
622
|
+
raise Exception(f'Invalid Input : detected')
|
|
623
|
+
|
|
624
|
+
def ipbinmask(self, n=0):
|
|
625
|
+
'''IP with Binary Mask for provided IP/Subnet,
|
|
626
|
+
n ==>
|
|
627
|
+
n-th ip of subnet will appear in output if provided,
|
|
628
|
+
same input subnet/ip will appear in output if not provided
|
|
629
|
+
set - n = 0, for Network IP
|
|
630
|
+
'''
|
|
631
|
+
try:
|
|
632
|
+
return self[n] + " " + self.binmask
|
|
633
|
+
except:
|
|
634
|
+
raise Exception(f'Invalid Input : detected')
|
|
635
|
+
|
|
636
|
+
def ipinvmask(self, n=0):
|
|
637
|
+
'''IP with Inverse Mask for provided IP/Subnet,
|
|
638
|
+
n ==>
|
|
639
|
+
n-th ip of subnet will appear in output if provided,
|
|
640
|
+
same input subnet/ip will appear in output if not provided
|
|
641
|
+
set - n = 0, for Network IP
|
|
642
|
+
'''
|
|
643
|
+
try:
|
|
644
|
+
return self[n] + " " + self.invmask
|
|
645
|
+
except:
|
|
646
|
+
raise Exception(f'Invalid Input : detected')
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
# ------------------------------------------------------------------------------
|
|
651
|
+
# Routes Class
|
|
652
|
+
# ------------------------------------------------------------------------------
|
|
653
|
+
class Routes(object):
|
|
654
|
+
''' Routing Table
|
|
655
|
+
--> Routes object with all routes in dictionary
|
|
656
|
+
|
|
657
|
+
:param hostname: device hostname
|
|
658
|
+
:param type: str
|
|
659
|
+
|
|
660
|
+
:param route_list: output of cisco sh route command in list format
|
|
661
|
+
:param type: list
|
|
662
|
+
|
|
663
|
+
:param route_file: feed text file of sh route output directly instead
|
|
664
|
+
:param type: io/text file
|
|
665
|
+
|
|
666
|
+
Properties
|
|
667
|
+
----------
|
|
668
|
+
routes: dictionary of route: routename
|
|
669
|
+
|
|
670
|
+
See also
|
|
671
|
+
---------
|
|
672
|
+
get_prefix_desc: --> Prefix Description / str
|
|
673
|
+
inTable --> checks is provided prefix in routes / bool
|
|
674
|
+
outerPrefix --> outer prefix / str
|
|
675
|
+
'''
|
|
676
|
+
# object initializer
|
|
677
|
+
def __init__(self, hostname, route_list=None, route_file=None):
|
|
678
|
+
if route_file != None: route_list = text_to_List(route_file)
|
|
679
|
+
self.__parse(route_list, hostname)
|
|
680
|
+
|
|
681
|
+
def __getitem__(self, key):
|
|
682
|
+
return self.routes[key]
|
|
683
|
+
|
|
684
|
+
def __iter__(self):
|
|
685
|
+
for k, v in self.routes.items():
|
|
686
|
+
yield (k, v)
|
|
687
|
+
|
|
688
|
+
@property
|
|
689
|
+
def reversed_table(self):
|
|
690
|
+
for k, v in reversed(self.routes.items()):
|
|
691
|
+
yield (k, v)
|
|
692
|
+
|
|
693
|
+
@property
|
|
694
|
+
def routes(self):
|
|
695
|
+
"""--> routes with its name"""
|
|
696
|
+
return self._op_items
|
|
697
|
+
|
|
698
|
+
def get_prefix_desc(self, prefix):
|
|
699
|
+
'''Returns prefix description if available or returns for default route
|
|
700
|
+
--> str
|
|
701
|
+
|
|
702
|
+
:param prefix: ip prefix to search in output
|
|
703
|
+
:param type: str
|
|
704
|
+
'''
|
|
705
|
+
pfxlst = []
|
|
706
|
+
if isinstance(prefix, str):
|
|
707
|
+
x = self.__check_in_table(addressing(prefix))[1]
|
|
708
|
+
try:
|
|
709
|
+
pfxlst.append(self[x])
|
|
710
|
+
return pfxlst[0]
|
|
711
|
+
except:
|
|
712
|
+
print("prefixesNotinAnySubnet: Error")
|
|
713
|
+
return None
|
|
714
|
+
elif isinstance(prefix, IPv4):
|
|
715
|
+
x = self.__check_in_table(prefix.subnet)
|
|
716
|
+
pfxlst.append(self[x])
|
|
717
|
+
elif isinstance(prefix, (list, tuple, set)):
|
|
718
|
+
for p in prefix:
|
|
719
|
+
px = self.get_prefix_desc(p)
|
|
720
|
+
if px:
|
|
721
|
+
pfxlst.append(px)
|
|
722
|
+
else:
|
|
723
|
+
raise Exception("INPUTERROR")
|
|
724
|
+
if len(set(pfxlst)) == 1:
|
|
725
|
+
return pfxlst[0]
|
|
726
|
+
else:
|
|
727
|
+
print("prefixesNotinSamesubnet: Error")
|
|
728
|
+
|
|
729
|
+
def inTable(self, prefix):
|
|
730
|
+
'''check if prefix is in routes table, return for Def.Route otherwise
|
|
731
|
+
--> bool
|
|
732
|
+
'''
|
|
733
|
+
return self.__check_in_table(prefix)[0]
|
|
734
|
+
|
|
735
|
+
def outerPrefix(self, prefix):
|
|
736
|
+
'''check and return parent subnet of prefix in routes table, Def.Route else
|
|
737
|
+
--> str
|
|
738
|
+
'''
|
|
739
|
+
return self.__check_in_table(prefix)[1]
|
|
740
|
+
|
|
741
|
+
######################### LOCAL FUNCTIONS #########################
|
|
742
|
+
|
|
743
|
+
# Helper for inTable and outerPrefix
|
|
744
|
+
def __check_in_table(self, prefix):
|
|
745
|
+
if not isinstance(prefix, (str, IPv4)):
|
|
746
|
+
raise Exception("INPUTERROR")
|
|
747
|
+
for k, v in self.reversed_table:
|
|
748
|
+
if k == '0.0.0.0/0': continue
|
|
749
|
+
if isSubset(prefix, k):
|
|
750
|
+
return (True, k)
|
|
751
|
+
break
|
|
752
|
+
return (False, '0.0.0.0/0')
|
|
753
|
+
|
|
754
|
+
# set routes in dictionary/ parser
|
|
755
|
+
def __parse(self, route_list, hostname):
|
|
756
|
+
headers = (
|
|
757
|
+
"L - local", "C - connected", "S - static", "R - RIP", "M - mobile", "B - BGP",
|
|
758
|
+
"D - EIGRP", "EX - EIGRP external", "O - OSPF", "IA - OSPF inter area",
|
|
759
|
+
"N1 - OSPF NSSA external type 1", "N2 - OSPF NSSA external type 2",
|
|
760
|
+
"E1 - OSPF external type 1", "E2 - OSPF external type 2", "V - VPN",
|
|
761
|
+
"i - IS-IS", "su - IS-IS summary", "L1 - IS-IS level-1", "L2 - IS-IS level-2",
|
|
762
|
+
"ia - IS-IS inter area", "* - candidate default", "U - per-user static route",
|
|
763
|
+
"o - ODR", "P - periodic downloaded static route", "+ - replicated route",
|
|
764
|
+
"Gateway of last resort"
|
|
765
|
+
)
|
|
766
|
+
op_items = OrderedDict()
|
|
767
|
+
for line in route_list:
|
|
768
|
+
if blank_line(line): continue
|
|
769
|
+
if hostname_line(line, hostname): continue
|
|
770
|
+
if find_any(line, headers): continue
|
|
771
|
+
if isSplittedRoute(line) == 0:
|
|
772
|
+
spl = line.strip()
|
|
773
|
+
continue
|
|
774
|
+
if isSplittedRoute(line) == -1:
|
|
775
|
+
line = spl + ' ' + line
|
|
776
|
+
spl = line.split(",")
|
|
777
|
+
if line.find('0.0.0.0 0.0.0.0') > -1:
|
|
778
|
+
op_items['0.0.0.0/0'] = replace_dual_and_split(spl[1])[-1].strip()
|
|
779
|
+
continue
|
|
780
|
+
route = replace_dual_and_split(spl[0])[1]
|
|
781
|
+
try:
|
|
782
|
+
routeMask = binsubnet(replace_dual_and_split(spl[0])[2]).count('1')
|
|
783
|
+
except:
|
|
784
|
+
print(spl)
|
|
785
|
+
routeDesc = replace_dual_and_split(spl[-1])[-1]
|
|
786
|
+
op_items[route + '/' + str(routeMask)] = routeDesc.strip()
|
|
787
|
+
self._op_items = op_items
|
|
788
|
+
|
|
789
|
+
|
|
790
|
+
# ----------------------------------------------------------------------------
|
|
791
|
+
# Prefixes summarization class
|
|
792
|
+
# ----------------------------------------------------------------------------
|
|
793
|
+
|
|
794
|
+
MAX_RECURSION_DEPTH = 100
|
|
795
|
+
class Summary(IPv4):
|
|
796
|
+
'''Defines Summary of prefixes
|
|
797
|
+
|
|
798
|
+
'''
|
|
799
|
+
|
|
800
|
+
def __init__(self, *args):
|
|
801
|
+
self.networks = set()
|
|
802
|
+
for arg in args:
|
|
803
|
+
if isinstance(arg, str):
|
|
804
|
+
if arg.strip():
|
|
805
|
+
arg=IPv4(arg)
|
|
806
|
+
self.networks.add(arg)
|
|
807
|
+
self.summaries = []
|
|
808
|
+
self.networks = sorted(self.networks)
|
|
809
|
+
self._validate_and_update_networks()
|
|
810
|
+
|
|
811
|
+
@property
|
|
812
|
+
def prefixes(self):
|
|
813
|
+
for pfx in self.summaries:
|
|
814
|
+
if isinstance(pfx, str): pfx = IPv4(pfx)
|
|
815
|
+
return set(self.summaries)
|
|
816
|
+
|
|
817
|
+
def _validate_and_update_networks(self):
|
|
818
|
+
for network in self.networks:
|
|
819
|
+
if not Validation(str(network)).validated:
|
|
820
|
+
print(f"InvalidSubnetDetected-Removed: {network}")
|
|
821
|
+
self.networks.remove(network)
|
|
822
|
+
|
|
823
|
+
# kick
|
|
824
|
+
def calculate(self):
|
|
825
|
+
prev_network = None
|
|
826
|
+
for network in self.networks:
|
|
827
|
+
_sumy = self.summary(prev_network, network)
|
|
828
|
+
prev_network = _sumy if _sumy is not None else network
|
|
829
|
+
if _sumy is not None:
|
|
830
|
+
if isinstance(prev_network, str):
|
|
831
|
+
_sumy = IPv4(_sumy)
|
|
832
|
+
prev_network = IPv4(prev_network)
|
|
833
|
+
self.summaries.append(_sumy)
|
|
834
|
+
else:
|
|
835
|
+
self.summaries.append(network)
|
|
836
|
+
continue
|
|
837
|
+
|
|
838
|
+
def summary(self, s1, s2):
|
|
839
|
+
if s2 is None: return s1
|
|
840
|
+
if s1 is None: return s2
|
|
841
|
+
if self._are_equal(s1, s2): return s1
|
|
842
|
+
big_subnet = self._is_any_subset(s1, s2)
|
|
843
|
+
if big_subnet: return big_subnet
|
|
844
|
+
self._sequnce_it(s1, s2)
|
|
845
|
+
self._local_vars()
|
|
846
|
+
if not self._contigious() or not self._immidiate(): return None
|
|
847
|
+
summary_ip = self.first.NetworkIP(False)+"/"+str(self.mask)
|
|
848
|
+
return summary_ip if Validation(summary_ip).validated else None
|
|
849
|
+
|
|
850
|
+
def _sequnce_it(self, s1, s2):
|
|
851
|
+
if int(binsubnet(s1.NetworkIP()), 2 ) > int(binsubnet(s2.NetworkIP()), 2 ):
|
|
852
|
+
(first, second) = (s2, s1)
|
|
853
|
+
else:
|
|
854
|
+
(first, second) = (s1, s2)
|
|
855
|
+
self.first, self.second = first, second
|
|
856
|
+
|
|
857
|
+
def _local_vars(self):
|
|
858
|
+
# ---------- set local vars ------------------
|
|
859
|
+
self.first_len = len(self.first)
|
|
860
|
+
self.second_len = len(self.second)
|
|
861
|
+
self.total = 2*self.first_len if self.first_len >= self.second_len else 2*self.second_len
|
|
862
|
+
self.mask = 32 - len(bin(self.total-1)[2:]) # tantative summary mask
|
|
863
|
+
# --------------------------------------------
|
|
864
|
+
|
|
865
|
+
def _are_equal(self, s1, s2): return s1.mask == s2.mask and s1.NetworkIP() == s2.NetworkIP()
|
|
866
|
+
|
|
867
|
+
def _is_any_subset(self, s1, s2):
|
|
868
|
+
(big_subnet, small_subnet) = (s2, s1) if s1.mask > s2.mask else (s1, s2)
|
|
869
|
+
is_part = False
|
|
870
|
+
for power in range(1, 33):
|
|
871
|
+
no_of_subnets = (2**power)
|
|
872
|
+
try:
|
|
873
|
+
portions = big_subnet/no_of_subnets
|
|
874
|
+
except ValueError:
|
|
875
|
+
break
|
|
876
|
+
if small_subnet.NetworkIP() in portions:
|
|
877
|
+
is_part = True
|
|
878
|
+
break
|
|
879
|
+
return big_subnet if is_part else None
|
|
880
|
+
|
|
881
|
+
def _contigious(self):
|
|
882
|
+
# condition 1 - next ip of subnet 1 should be network ip of subnet 2 / Verfications
|
|
883
|
+
return self.first.n_thIP(self.first_len, summary_calc=True) == self.second.NetworkIP(False)
|
|
884
|
+
|
|
885
|
+
def _immidiate(self):
|
|
886
|
+
# condition 2 - length subnet 1 + lenght subnet 2 == bc ip of subnet 2
|
|
887
|
+
return self.first.n_thIP(self.total-1, summary_calc=True) == self.second.broadcast_address()
|
|
888
|
+
|
|
889
|
+
|
|
890
|
+
|
|
891
|
+
# ----------------------------------------------------------------------------
|
|
892
|
+
# Main Function
|
|
893
|
+
# ----------------------------------------------------------------------------
|
|
894
|
+
if __name__ == '__main__':
|
|
895
|
+
pass
|
|
896
|
+
# END
|
|
897
|
+
# ----------------------------------------------------------------------------
|
|
898
|
+
|
|
899
|
+
# # EXAMPLE on SUMMARIZATION
|
|
900
|
+
|
|
901
|
+
# s1 = IPv4("10.10.0.0/24")
|
|
902
|
+
# s2 = IPv4("10.10.1.0/24")
|
|
903
|
+
# s3 = IPv4("10.10.2.0/24")
|
|
904
|
+
# s4 = IPv4("10.10.3.0/24")
|
|
905
|
+
|
|
906
|
+
# # Method1 -- provide > 2 subnets as below using below func.
|
|
907
|
+
# # Return list of sorted individual/summary networks if non-summarizable
|
|
908
|
+
# print (get_summaries(s1 , s3, s2))
|
|
909
|
+
|
|
910
|
+
# # Method2 -- two subnets can be summarized directly using + operator if can be summarized
|
|
911
|
+
# # raise error if non-summarizable
|
|
912
|
+
# print (s2 + s1)
|
|
913
|
+
|
|
914
|
+
# # Method2 -- two subnets can be summarized using summary method as below.
|
|
915
|
+
# # Return None if non-summarizable
|
|
916
|
+
# s = Summary()
|
|
917
|
+
# print (s.summary(s1, s2))
|
|
918
|
+
|
|
919
|
+
|
|
920
|
+
# ----------------------------------------------------------------------------
|