Repository navigation
Expand file tree
/
Copy pathipruleTest.py
More file actions
460 lines (387 loc) · 13.9 KB
/
Copy pathipruleTest.py
File metadata and controls
460 lines (387 loc) · 13.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
from netaddr import *
from IPy import IP
import itertools
import socket
import re
import json
import sys
import os
PLUGINPATH = "plugins"
class Match(object):
def __init__(self, name, rule=None):
self.name = name
self.rule = rule
def __getattr__(self, name):
try:
return super(Match, self).__getattribute__(name)
except KeyError:
raise AttributeError
def __setattr__(self, key, value):
key = key.replace("-", "_")
super(Match, self).__setattr__(key, value)
class Rule(object):
""" Rules are entries in chains
"""
def __init__(self, chain=None):
self.chain = chain
self._matches = []
self._target = None
self._proto = None
self._src = None
self._dst = None
self._sgroup = -1
self._dgroup = -1
self._isDefault = False
def create_match(self, name):
match = Match(name)
self.add_match(match)
return match
def add_match(self, match):
match.rule = self
self._matches.append(match)
def remove_match(self, match):
self._matches.remove(match)
def _get_target(self):
return self._target
def _set_target(self, target):
self._target = target
target = property(_get_target, _set_target)
def _get_proto(self):
return self._proto
def _set_proto(self, protocol):
self._proto = protocol
protocol = property(_get_proto, _set_proto)
def get_src(self):
return self._src
def set_src(self, src):
self._src = src
src = property(get_src, set_src)
def get_dst(self):
return self._dst
def set_dst(self, dst):
self._dst = dst
dst = property(get_dst, set_dst)
def _get_sgroup(self):
return self._sgroup
def _set_sgroup(self, group):
self._sgroup = group
sgroup = property(_get_sgroup, _set_sgroup)
def _get_dgroup(self):
return self._dgroup
def _set_dgroup(self, dgroup):
self._dgroup = dgroup
dgroup = property(_get_dgroup, _set_dgroup)
class Chain(object):
_cache = dict()
def __new__(cls, table, name):
obj = Chain._cache.get(table.name + "." + name, None)
if not obj:
obj = object.__new__(cls)
obj.__init__(table, name)
Chain._cache[table.name + "." + name] = obj
obj._rules = []
return obj
def __init__(self, table, name):
self.name = name
self.table = table
table.add_chain(self)
#self._rules = []
def append_rule(self, rule):
self._rules.append(rule)
rule.chain = self
def insert_rule(self, rule, position=0):
self._rules.insert(position, rule)
rule.chain = self
def replace_rule(self, rule, position=0):
self._rules[position] = rule
rule.chain = self
def get_rule(self, position=0):
return self._rules[position]
def delete_rule(self, position=-1):
if position < 0:
print "wrong position"
return
del self._rules[position]
class Table(object):
FILTER = "filter"
"""This is the constant for the filter table."""
MANGLE = "mangle"
"""This is the constant for the mangle table."""
RAW = "raw"
"""This is the constant for the raw table."""
NAT = "nat"
"""This is the constant for the nat table."""
ALL = ["filter", "mangle", "raw", "nat"]
_cache = dict()
def __new__(cls, name):
obj = Table._cache.get(name, None)
if not obj:
obj = object.__new__(cls)
obj.__init__(name)
Table._cache[name] = obj
obj.chains = dict()
return obj
def __init__(self, name):
self.name = name
#self.chains = dict()
def add_chain(self, chain):
if chain.name not in self.chains:
self.chains[chain.name] = chain
#else :
# raise ValueError("chain already exist")
def get_chain(self, chain_name):
return self.chains[chain_name]
def delete_chain(self, chain):
if chain.name not in self.chians:
raise ValueError("nothing to delete")
else:
del self.chains[chain.name]
#Stores all the information for a given group in a group config file and provides an abstraction in case
#the format of the group data changes.
class GroupData(object):
def __init__(self,groupFile):
file = open(groupFile)
self.data = json.JSONDecoder().decode(file.read())
file.close()
def isGroup(self,inputGroup):
try:
self.data[inputGroup]
return True
except:
return False
def reload(self,fileName):
file = open(fileName)
self.data = json.JSONDecoder().decode(file.read())
file.close()
def checkRe(self,input,pattern):
if input == pattern and ((pattern[0] != "'") and (pattern[len(pattern) - 1] != "'")) :
return True
elif ((pattern[0] == "'") and (pattern[len(pattern) - 1] == "'")):
rePattern = pattern[1:(len(pattern) - 1)]
if re.match(rePattern,input) != None:
print("RE MATCH")
return True
return False
def isIp(self,inputIp,groupName):
ipList = self.data[groupName]["IPv4"]
for ip in ipList:
if ip:
if self.checkRe(inputIp,ip):
return True
return False
def isFQDN(self,inputIp,groupName):
try:
inputFQDN = socket.getfqdn(str(inputIp))
except:
return False
fqdnList = self.data[groupName]["FQDN"]
if fqdnList:
for fqdn in fqdnList:
if fqdn:
if self.checkRe(inputFQDN,fqdn):
return True
return False
else:
return False
def isSubnet(self,inputIp,groupName):
inputIp = IPAddress(inputIp)
subList = self.data[groupName]["Subnet"]
for subnet in subList:
try:
expandSub = IPNetwork(subnet)
except:
continue
for ip in expandSub:
if ip == inputIp:
return True
return False
class Comparison(object):
def __init__(self, table,groupData):
self.table = table
self.groupData = groupData
self.plugins = {}
try:
self.loadPlugins(self.plugins)
except:
pass
def loadPlugins(self,pluginList):
sys.path.insert(0,PLUGINPATH)
for file in os.listdir(PLUGINPATH):
fname,ext = os.path.splitext(file)
if ext == ".py":
mod = __import__(fname)
pluginList[fname] = mod.Plugin()
sys.path.pop(0)
print "Plugins",pluginList
def portMatch(self, portnum, portRange):
ports = [int(s) for s in portRange]
print "INPUT PORTS",ports
print "COMPARISION PORT",portnum
if len(ports) == 0 or portnum == -1:
print "PORTS MATCHED0"
return True
elif len(ports) == 1:
if portnum == ports[0]:
print "PORTS MATCHED1"
return True
else:
if portnum >= ports[0] and portnum <= ports[1]:
print "PORTS MATCHED"
return True
print "PORTS NOT MATCHED"
return False
#Is the input a valid ip address? If so return false as it can't be a dns hostname.
def isDNS(self,str):
try:
IP(str)
except ValueError:
return True
return False
#Take in an ip and get the right hostname, use this to compare to a hostname that might be in a group list.
def hasHostname(self,ip):
try:
socket.gethostbyaddr(str(ip))
except:
return (False,None)
return (True,(socket.gethostbyaddr(str(ip))[0]))
# ipMatch1 is used to test -s with ip subnet
def ipMatch1(self, ip, cmpIP):
print "IN IPMATCH1"
if cmpIP == None or cmpIP == '0.0.0.0/0.0.0.0':
print "Blank or None cmpIP"
return True
if ip == None:
return False
if self.isDNS(str(cmpIP)):
cmpIP = socket.gethostbyname(str(cmpIP))
if '/' in cmpIP:
ipset = IPSet([cmpIP])
if ip in ipset:
return True
else:
if ip == cmpIP:
print "RETURNING TRUE IPMATCH1"
return True
print "RETURING FALSE IPMATCH1"
return False
#ipMatch2 is used to test ipRange
def ipMatch2(self, ip, ipRange):
if len(ipRange) == 0:
return True
if ip == None:
return False
if len(ipRange) == 2:
iprange = IPRange(ipRange[0], ipRange[1])
if ip in iprange:
return True
elif ip == ipRange[0]:
return True
return False
#Test if two ips are from the same group file
def groupMatch(self,sIp,dIp,sGroup,dGroup):
sGroupMatch = False
dGroupMatch = False
if (self.groupData.isGroup(sGroup) == False) or (self.groupData.isGroup(dGroup) == False):
return False
else:
#Verify the source ip has a match in some group
#self.groupData.__getattribute__('isIp')
if (self.groupData.isIp(sIp,sGroup)):
sGroupMatch = True
elif (self.groupData.isFQDN(sIp,sGroup)):
sGroupMatch = True
elif (self.groupData.isSubnet(sIp,sGroup)):
sGroupMatch = True
#Assume that each plugin vas a verify method for checking if an ip is in a group and use it
else:
for plugin in self.plugins.values():
try:
if plugin.verify(sIp,sGroup):
sGroupMatch = True
except:
print "Error in plugin:",self.plugins.keys()[self.plugins.values().index(plugin)], "when matching source group"
continue
#Verify the destination ip has a match in some group
if (self.groupData.isIp(dIp,dGroup)):
dGroupMatch = True
elif (self.groupData.isFQDN(dIp,dGroup)):
dGroupMatch = True
elif (self.groupData.isSubnet(dIp,dGroup)):
dGroupMatch = True
#Is the destination ip and group verified by a plugin method?
else:
for plugin in self.plugins.values():
try:
if plugin.verify(dIp,dGroup):
dGroupMatch = True
except:
print "Error in plugin:",self.plugins.keys()[self.plugins.values().index(plugin)], "when matching destination group"
continue
if sGroupMatch and dGroupMatch:
return True
else:
return False
def compare(self, proto, tsIp=None, tdIp=None, tsPort=-1, tdPort=-1):
matched_rule = {}
for key in self.table.chains:
print "KEY ",key
chain = self.table.chains[key]
for rule in chain._rules:
dport = []
sport = []
srange = []
drange = []
src = rule.src
dst = rule.dst
sgroup = rule.sgroup
print "SGROUP: ", rule.sgroup
dgroup = rule.dgroup
print "DGROUP: ", rule.dgroup
if proto != rule.protocol:
continue
for match in rule._matches:
if 'dport' in dir(match):
dport = match.dport.split(':')
if 'sport' in dir(match):
sport = match.sport.split(':')
if 'src_range' in dir(match):
srange = match.src_range.split('-')
if 'dst_range' in dir(match):
drange = match.dst_range.split('-')
print "RULE.sGROUP ",rule.sgroup
print "RULE.dGROUP ",rule.dgroup
if rule.sgroup != -1:
print "tsIp=",tsIp
print "tdIp=",tdIp
print "sgroup=",sgroup
print "dgroup=",dgroup
print "sport=",sport
print "dport=",dport
print "tsPort=",tsPort
print "tdPort=",tdPort
print "ruleSource=", src
print "ruleDst=", dst
if (self.groupMatch(tsIp,tdIp,sgroup,dgroup)) and (self.portMatch(tsPort, sport)) and (self.portMatch(tdPort, dport)):
matched_rule['src'] = tsIp
matched_rule['dst'] = tdIp
matched_rule['proto'] = rule.protocol
matched_rule['target'] = rule.target
return matched_rule
elif rule.sgroup == -1:
print "GOT INTO ELSE"
print "tsIp=",tsIp
print "tdIp=",tdIp
print "sgroup=",sgroup
print "dgroup=",dgroup
print "ruleSource=", src
print "ruleDst=", dst
if (self.ipMatch1(tsIp, src)) and (self.ipMatch1(tdIp, dst)) \
and (self.portMatch(tsPort, sport)) and (self.portMatch(tdPort, dport)) \
and (self.ipMatch2(tsIp, srange)) and (self.ipMatch2(tdIp, drange)):
matched_rule['src'] = tsIp
matched_rule['dst'] = tdIp
matched_rule['proto'] = rule.protocol
matched_rule['target'] = rule.target
print "TARGET THING2 " , rule.target
return matched_rule
return matched_rule