paloma blog

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

pythonのipaddressモジュールでワイルドカードマスクをワンライナー計算

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ですね。

むすび

という訳でワンライナーワイルドカード計算でした。
bashpythonの併用は反則な気もしますが
なるべく楽する必要がありますのでご容赦ください。

本当はスクリプト作って記事を書こうとしていましたが
ワンライナーを思い付いたので気軽に計算できますね。
(でも長いか...)


本当は長すぎるので改行したかったのですが、
いつもワンライナーでやっているので改行がうまくいかずそのまま載せてしまいました。

改行がうまくいったら再度投稿したいと思います。

参考サイト