12月 282011
bashを使ってネットワークアドレスの設定をするためのスクリプトを書いてたときに、入力されたサブネットマスクが正しいかどうかを検証するコマンドがなかったので自前で作ることにした。まず、入力値がIPv4アドレスとして正しいかどうかの判定は、正規表現を使った例などもあるが、ipcalcコマンドを使った方が楽チン。
#!/bin/bash
read mask
if ! ipcalc -c $mask > /dev/null 2>&1; then
echo "ERROR: Invalid format"
exit 1
fi
同じようにipcalcコマンドを使ってサブネットマスクも検証できないものかと思い、
if ! ipcalc -n 192.168.1.1 $mask > /dev/null 2>&1; then
echo "ERROR: Invalid subnet mask"
exit 1
fi
と試したがまったく意味がなかった。
ipcalcコマンドの具体的な実行結果を挙げよう。
$ ipcalc -n 192.168.1.254 255.255.255.0 > /dev/null 2>&1; echo $? 0 $ ipcalc -n 192.168.1.254 255.255.255.250 > /dev/null 2>&1; echo $? 0 $ ipcalc -n 192.168.1.254 255.255.0.255 > /dev/null 2>&1; echo $? 0
「255.255.255.250」も「255.255.0.255」もサブネットマスクとしては不正な値だが、ipcalcは正常終了してしまう。あまり厳密にチェックしていないんだな。
正規表現でも書ける自信がなかったので力技で書いてみた(冒頭のスクリプトの続き)。
valid=0
filled=0
for n in `echo $mask | sed 's/\./ /g'`; do
case "$n" in
255|254|252|248|240|224|192|128)
[ $filled -eq 0 ] && valid=0
;;
0)
;;
*)
valid=0
;;
esac
[ $valid -eq 0 ] && break
[ $n -ne 255 ] && filled=0
done
if [ $valid -eq 0 ]; then
echo "ERROR: Invalid subnet mask"
exit 1
fi
echo "$mask is valid subnet mask"
サブネットマスクはビット表現したときに、0が出現したビットより下位のビットはすべて0でなければならない(途中のビットが立っているとNG)ので、それを変数filledを使ってチェックするようにしているというワケ。