paloma blog

NWエンジニアやってます。主に自宅環境のお遊びを書きます。Pythonもちょっと。タイトルは好きなカクテルから。

pythonで出力した通信要件を加工する

7月に入りました。2018年も折り返しです。
今年は本プログの記事を週一ペースで50本上げることが目標なのですが、ちょっと足りてないですね。 後半頑張れるか…


前回出力した通信要件をもう少し加工します。

(python3) masashi@PC-ubuntu:~/trafficsorting$ python traffic.py 
<Worksheet "通信一覧">
any 192.168.10.1/24 TCP 80
any 192.168.10.2/24 TCP 80
<Worksheet "通信一覧">
192.168.10.1/24 192.168.20.1/24 TCP 8009
192.168.10.1/24 192.168.20.2/24 TCP 8009
192.168.10.2/24 192.168.20.1/24 TCP 8009
192.168.10.2/24 192.168.20.2/24 TCP 8009
<Worksheet "通信一覧">
192.168.20.1/24 192.168.30.1/24 TCP 1521
192.168.20.2/24 192.168.30.1/24 TCP 1521
<Worksheet "通信一覧">
192.168.40.1/24 192.168.10.1/24 ICMP -
192.168.40.1/24 192.168.10.2/24 ICMP -
<Worksheet "通信一覧">
192.168.40.1/24 192.168.20.1/24 ICMP -
192.168.40.1/24 192.168.20.2/24 ICMP -
<Worksheet "通信一覧">
192.168.40.1/24 192.168.30.2/24 ICMP -
192.168.40.1/24 192.168.30.3/24 ICMP -

こんな感じでわっと出るのですがconfig等に利用したいのでもう少し加工します。

成形

シート名を出すようにしたのですが邪魔なので消します。
pythonだけで完結できたらいいのですが、未熟なものでshellの力を借ります。

(python3) masashi@PC-ubuntu:~/trafficsorting$ python traffic.py | grep -vE "Error|^<"
any 192.168.10.1/24 TCP 80
any 192.168.10.2/24 TCP 80
192.168.10.1/24 192.168.20.1/24 TCP 8009
192.168.10.1/24 192.168.20.2/24 TCP 8009
192.168.10.2/24 192.168.20.1/24 TCP 8009
192.168.10.2/24 192.168.20.2/24 TCP 8009
192.168.20.1/24 192.168.30.1/24 TCP 1521
192.168.20.2/24 192.168.30.1/24 TCP 1521
192.168.40.1/24 192.168.10.1/24 ICMP -
192.168.40.1/24 192.168.10.2/24 ICMP -
192.168.40.1/24 192.168.20.1/24 ICMP -
192.168.40.1/24 192.168.20.2/24 ICMP -
192.168.40.1/24 192.168.30.2/24 ICMP -
192.168.40.1/24 192.168.30.3/24 ICMP -

これで通信だけになりました。
出た結果をファイルにリダイレクトして、さらにネットワークに変換する処理を咬ませます。

ipaddressモジュール

ipaddressというモジュールを使います。

IPv4Interfaceというクラスがあり、
CIDR表記のIPアドレスをネットワークアドレスに変換してくれます。

ルーティング、ACLはネットワーク単位で書くことが多いのでこの変換は大変便利です。

さっきの結果をネットワークアドレスに変換するプログラムです。
文字列はエラー吐いてしまうのでこれもtryでハンドリングします。
(馬鹿の一つ覚えみたいにtry文を使ってしまいます)

いろんな本をちょろちょろ読んでるので、pythonの書き方がバラバラです。
そろそろ統一していかないと。

#!/usr/bin/env python3
import ipaddress

def main():
    with open('pattern.txt') as f:
        for row in f:
            try:
                column = row.strip().split()
                print(ipaddress.IPv4Interface(column[0]).network, ipaddress.IPv4Interface(column[1]).network, column[3])
            except:
                print('Error: ', column[0], column[1], column[3])


main()
  • さっきリダイレクトしたファイルをread
  • 列操作をしやすくするためにスペース区切りにする
  • 1列目、2列目をネットワークアドレスに変換して出力ついでにポート番号も入れておきます。
  • 文字列がある行はErrorの文字をつけて出力

動かしてみる

(python3) masashi@PC-ubuntu:~/trafficsorting$ python subnet.py 
Error:  any 192.168.10.1/24 80
Error:  any 192.168.10.2/24 80
192.168.10.0/24 192.168.20.0/24 8009
192.168.10.0/24 192.168.20.0/24 8009
192.168.10.0/24 192.168.20.0/24 8009
192.168.10.0/24 192.168.20.0/24 8009
192.168.20.0/24 192.168.30.0/24 1521
192.168.20.0/24 192.168.30.0/24 1521
192.168.40.0/24 192.168.10.0/24 -
192.168.40.0/24 192.168.10.0/24 -
192.168.40.0/24 192.168.20.0/24 -
192.168.40.0/24 192.168.20.0/24 -
192.168.40.0/24 192.168.30.0/24 -
192.168.40.0/24 192.168.30.0/24 -

サブネットに変換されましたね。
これだと重複行がでるのでここでもshellの力を借ります。

(python3) masashi@PC-ubuntu:~/trafficsorting$ python subnet.py | sort | uniq
192.168.10.0/24 192.168.20.0/24 8009
192.168.20.0/24 192.168.30.0/24 1521
192.168.40.0/24 192.168.10.0/24 -
192.168.40.0/24 192.168.20.0/24 -
192.168.40.0/24 192.168.30.0/24 -
Error:  any 192.168.10.1/24 80
Error:  any 192.168.10.2/24 80

このようにパターンがシンプルになりました。
サンプルなんで全部24ビットで書いてしまいましたが他のサブネットで書いてもちゃんと出力してくれます。

今回はここまでしか動かしていませんが、sedawkで処理すればそのままconfigに使えそうです。

Error行は処理をまるまるスキップさせたので手で変換しないといけないですが、
any -> 0.0.0.0/0みたいにIPアドレスに変換して綺麗にしてしまいたいですね。

まとめ

pythonファイルが分割していたり途中でshellを挟んだりとエレガントさに欠ける処理ですが、
目視で確認していくよりずっと早く落とし込みができそうです。

通信要件の資料って書く人によってばらつきがあるので、綺麗に出したければ自分で元ファイルを修正する必要がありますが、何とか使いやすい形に持ってくることができました。

このフローは日々の業務で発生するので、メンテして使いやすくしていきたいと思います。
本チャンの資料は上げられませんがコードはgithubにでもあげようかな。

ipaddressモジュール、IPアドレス用の処理がいろいろできそうでネットワークエンジニアとしていろいろ遊んでみたいですが、うまい使い道が思い浮かばないですね。
IPv6変換とかできたら使えるかな?