firewall-cmdで設定済みのセグメントを検出してadd-sourceしたい

dropゾーンにIPアドレスを追加したいんだけど、既に設定済みのセグメントにバッティングしてないかをfirewall-cmdはチェックしてくれないので、例えば、/etc/firewalld/zones/drop.xml

<source address="192.168.0.0/24"/>

というエントリーがあっても、

$ firewalld-cmd --add-source 192.168.0.1/32 --zone=drop

はsuccessしちゃう。別に重複したってええやん、という考え方も無くはないけれど、ルールが無駄に増えれば管理の手間も増えるのでとっとと手を打っておくのがよろしいかな、と。

で、python3-firewallパッケージが良い感じにfirewallモジュールをインストールしてくれてるので、ipaddressモジュールと共に使うと簡単にセグメント内のアドレスかチェックしてルールを突っ込める、と。適当に名前つけてchmod 755しといて、IPアドレスを引数に渡せばOK。IPアドレスを追加後にバックアップを作成してソートもするので、vim等で検索するのもちょっと楽になるかと。

#!/usr/bin/env python3

import sys
import subprocess
import shutil
import datetime
from ipaddress import IPv4Address as ip, IPv4Network as net
from firewall.client import FirewallClient

try:
    fw = FirewallClient()
except FirewallError as msg:
    code = FirewallError.get_code(str(msg))
    cmd.print_and_exit("Error: %s" % msg, code)

ipaddress=sys.argv[1]
existing = False
for nw in fw.getSources('drop'):
    existing |= ip(ipaddress) in net(nw)

if existing == True:
    sys.exit("This IP address is included in existing network segments.")
else:
    res = fw.addSource('drop', "{}/32".format(ipaddress))
    if res == 'drop':
        fw.runtimeToPermanent()

args = ['/usr/bin/firewall-cmd', '--reload']
res = subprocess.call(args)

print('successfully added')

shutil.copy2("/etc/firewalld/zones/drop.xml", "/etc/firewalld/zones/drop.xml.{}".format(datetime.datetime.now().strftime('%Y%m%d-%H%M%S')))

ip_segs = []
# store the sources to list and drop it
for ip_seg in fw.getSources('drop'):
    ip_segs.append(net(ip_seg))
    fw.removeSource('drop', str(ip_seg))

ip_segs.sort()

for ip_seg in ip_segs:
    fw.addSource('drop', str(ip_seg))

fw.runtimeToPermanent()

args = ['/usr/bin/firewall-cmd', '--reload']
res = subprocess.call(args)

print('successfully sorted')