ipcalc関連でもう一件。
私は今の職場ではCentOSのipcalcを使っていますがRedhat系のipcalcはワイルドカードの出力は出来ません。
丸暗記も大切ですがミスを防ぐにはコンピュータにやってもらうほうがいいですよね。
ここはpythonの出番です。
シェルから呼び出してディストリビューションを問わずワンライナーで計算してもらいましょう。
ipaddressモジュール
その名の通りIPアドレスを計算してくれます。
使ったことありませんがIPv6にも対応しています。
pythonと一緒に標準でインストールされています。
よく使う関数
NW機器用の設計で使うのが多いんじゃないでしょうか。 ルーティング、ACL等ですね。
IPv4Interface関数がネットワークマスク、ワイルドカードマスク計算を賄ってくれます。
masashi@DESKTOP-N095TND:~$ python3 Python 3.6.9 (default, Nov 7 2019, 10:44:02) [GCC 8.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import ipaddress >>> >>> print(ipaddress.IPv4Interface('192.168.1.10/24')) 192.168.1.10/24 >>> print(ipaddress.IPv4Interface('192.168.1.10/24').network) 192.168.1.0/24 >>> print(ipaddress.IPv4Interface('192.168.1.10/24').with_hostmask) 192.168.1.10/0.0.0.255
実行
ワンライナーでやってみます。
環境
今回はwslのubuntu & python3です。
masashi@DESKTOP-N095TND:~$ lsb_release -a ; uname -a ; python3 --version No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 18.04.2 LTS Release: 18.04 Codename: bionic Linux DESKTOP-N095TND 4.4.0-17763-Microsoft #864-Microsoft Thu Nov 07 15:22:00 PST 2019 x86_64 x86_64 x86_64 GNU/Linux Python 3.6.9
IPアドレス、ネットワークマスク、ワイルドカードマスクを出力しましょう。
結果
こんな感じ。
長くてすみませんが、ワンライナーです。
masashi@DESKTOP-N095TND:~$ echo 192.168.1.10/24 | python3 -c "import sys,ipaddress ; IP = ipaddress.IPv4Interface(sys.stdin.read()[:-1]) ; print('H: {}\nN: {}\nW: {}\n---'.format(IP, IP.network, IP.with_hostmask))" H: 192.168.1.10/24 N: 192.168.1.0/24 W: 192.168.1.10/0.0.0.255 ---
一気に確認できるのはいいですね。
解説
sysのインポート
echoで出力した結果を読ませます。
sys.stdin.readを行うためです。
sys.stdin.readのあとの[:-1]
echoの出力ままstdinで入力すると改行コードが付いてくるので末尾を削除するためです。
ipaddress.NetmaskValueError: '24\n' is not a valid netmask
複数のネットワークを計算したい
shellのwhile readで複数の計算も可能です。
python内でループさせたかったのですが
pythonだけだとどうにも上手く出来ませんでした。
IPアドレスはプライベートアドレスの中から適当にサブネットを割り当てました。
ファイルから
ファイル
masashi@DESKTOP-N095TND:~$ cat subnet 10.0.1.10/21 172.16.20.200/25 192.168.1.10/24
masashi@DESKTOP-N095TND:~$ cat subnet | while read line ; do echo $line | python3 -c "import sys,ipaddress ; IP = ipaddress.IPv4Interface(sys.stdin.read()[:-1]) ; print('H: {}\nN: {}\nW: {}\n---'.format(IP, IP.network, IP.with_hostmask))" ; done H: 10.0.1.10/21 N: 10.0.0.0/21 W: 10.0.1.10/0.0.7.255 --- H: 172.16.20.200/25 N: 172.16.20.128/25 W: 172.16.20.200/0.0.0.127 --- H: 192.168.1.10/24 N: 192.168.1.0/24 W: 192.168.1.10/0.0.0.255 ---
ヒアドキュメントから
masashi@DESKTOP-N095TND:~$ while read line ; do echo $line | python3 -c "import sys,ipaddress ; IP = ipaddress.IPv4Interface(sys.stdin.read()[:-1]) ; print('H: {}\nN: {}\nW: {}\n---'.format(IP, IP.network, IP.with_hostmask))" ; done << EOF > 10.0.1.10/21 > 172.16.20.200/25 > 192.168.1.10/24 > EOF H: 10.0.1.10/21 N: 10.0.0.0/21 W: 10.0.1.10/0.0.7.255 --- H: 172.16.20.200/25 N: 172.16.20.128/25 W: 172.16.20.200/0.0.0.127 --- H: 192.168.1.10/24 N: 192.168.1.0/24 W: 192.168.1.10/0.0.0.255 ---
python2系だとこんな感じ
wslにはpython2系がインストールされていなかったのでipaddressモジュール含めインストールしました。
masashi@DESKTOP-N095TND:~$ python --version Python 2.7.17
2系の場合はshell経由で渡すとstr型で受け取ってエラーになります。
unicode型に変換します。
ipaddress.AddressValueError: '192.168.1.10/24' (len 15 != 4) is not permitted as an IPv4 address. Did you pass in a bytes (str in Python 2) instead of a unicode object?
masashi@DESKTOP-N095TND:~$ echo 192.168.1.10/24 | python -c "import sys,ipaddress ; IP = ipaddress.IPv4Interface(unicode(sys.stdin.read()[:-1])) ; print 'H: {}\nN: {}\nW: {}\n---'.format(IP, IP.network, IP.with_hostmask) " H: 192.168.1.10/24 N: 192.168.1.0/24 W: 192.168.1.10/0.0.0.255 ---
2系でもOKですね。
むすび
という訳でワンライナーワイルドカード計算でした。
bashとpythonの併用は反則な気もしますが
なるべく楽する必要がありますのでご容赦ください。
本当はスクリプト作って記事を書こうとしていましたが
ワンライナーを思い付いたので気軽に計算できますね。
(でも長いか...)
本当は長すぎるので改行したかったのですが、
いつもワンライナーでやっているので改行がうまくいかずそのまま載せてしまいました。
改行がうまくいったら再度投稿したいと思います。