Python Firewall Rules Simplifier 防火牆規則簡化器
2022-05-12
使用 Python 設計簡化防火牆設定規則的演算 Script。
說明
測試資料
rules = [
{
"from": ["1.1.1.1"],
"to": ["10.10.10.10"]
},
{
"from": ["2.2.2.2"],
"to": ["11.11.11.11", "12.12.12.12"]
},
{
"from": ["3.3.3.3"],
"to": ["13.13.13.13"]
},
{
"from": ["4.4.4.4"],
"to": ["13.13.13.13"]
},
{
"from": ["5.5.5.5"],
"to": ["15.15.15.15", "16.16.16.16"]
},
{
"from": ["6.6.6.6"],
"to": ["15.15.15.15"]
},
{
"from": ["6.6.6.6"],
"to": ["16.16.16.16"]
},
]
Coding
簡化的原理是將原本可能重複出現、未整合資料,全部打散為一對一關係的規則 (tuple),比較使用 Set 排除掉重複的 tuple。
接著將資料分為一對一、一對多與多對一。其中以多來源 (防火牆允許來源 From) 到單一目標 (防火牆允許目標 To) 為處理優先,處理的結果儲存為 Dictionary 並以變數 oneToMany
保存;
接著處理單一來源 (防火牆允許來源 From) 到多目標 (防火牆允許目標 To),此步驟會將一對一關係的防火牆規則一併處理,處理的結果儲存為 Dictionary 並以變數 manyToOne
保存。
最後要處理的情況是多對多,這種情況會發生在先處理的 oneToMany
當中的防火牆規則,因為 List、Dict 以及 Set 本身都無法計算雜湊值,為了要找出多對多關係,必須判斷是否有不同單一 To,卻有相同 From List 的防火牆規則。
所以土炮設計 listId 作為 list 取 hash value 的方式,最後用兩次迴圈順利處理,並存成 Dictionary 其中 key 就是 From List 的雜湊值,Value 則是另一個 Dictionary,分別記載 From List 以及 To List 以構成多對多關係。保存為變數 manyToMany
在 manyToMany
會包含 oneToMany
的防火牆規則,所以在表列上就不另外處理 oneToMany
😉
ruleSets = set()
for rule in rules:
for _from in rule['from']:
for to in rule['to']:
ruleSets.add((_from, to))
# one TO to many FROM
oneToMany = {}
# many FROM to one TO
manyToOne = {}
# many to many
manyToMany = []
for to in set([r[1] for r in ruleSets]):
fromlist = [r[0] for r in ruleSets if r[1] == to]
if len(fromlist) > 1:
oneToMany[to] = fromlist
else:
singleFrom = fromlist[0]
if singleFrom in manyToOne:
manyToOne[singleFrom].append(to)
else:
manyToOne[singleFrom] = [to]
def listId(lst):
return ','.join([v for v in set(lst)])
manyToMany = {}
for lst in [v for v in oneToMany.values()]:
manyToMany.setdefault(listId(lst), {
"from": lst,
"to": []
})
for to, _from in oneToMany.items():
manyToMany[listId(_from)]['to'].append(to)
# Including one TO to many FROM scenario
for m2m in manyToMany.values():
print('from: \n ', end='')
print('\n '.join(m2m['from']))
print('to: \n ', end='')
print('\n '.join(m2m['to']))
print('-' * 30)
for _from in manyToOne:
print(f'from:\n {_from}')
print('to: \n ', end='')
print('\n '.join(manyToOne[_from]))
print('-' * 30)
計算結果
from:
5.5.5.5
6.6.6.6
to:
16.16.16.16
15.15.15.15
------------------------------
from:
3.3.3.3
4.4.4.4
to:
13.13.13.13
------------------------------
from:
1.1.1.1
to:
10.10.10.10
------------------------------
from:
2.2.2.2
to:
12.12.12.12
11.11.11.11
------------------------------