CIDR表記で示されたIPアドレスの範囲に含まれるかどうかを簡単に確認したい場合、シェルコマンドだけでやろうとすると難しかったので、Rubyのワンライナーを使った。
$ target_ip=`dig +short example.co.jp`
$ ruby -r 'ipaddr' -e 'p IPAddr.new("xxx.xxx.xxx.0/24").include?("ARGV[0]")' $target_ip
true
IPAddr.new
はCIDR表記を受け取ることができる。CIDR表記なのでプレフィックス表記(/24)でもサブネットマスク表記(/255.255.255.0)でも問題ない。(引用元:class IPAddr)
0 から IPAddr::IN6MASK までの数値を受け取ります。 また、'address', 'address/prefixlen', 'address/mask' の形式も受け付けます。 プリフィックス長やマスクが指定されると、 マスクされた IPAddr オブジェクトを返します。
IPアドレス範囲をto_range
でRangeに変換して、その中に引数で渡したIPアドレスが含まれているかどうかを確認することもできる(IPAddr.new("xxx.xxx.xxx.0/24").to_range.include?("ARGV[0]")
)のだが、IPAddrクラスにはinclude?
メソッドがあり、そのままIPアドレスが自身の範囲に入っているか確認してくれる。to_range
は範囲内のIPアドレスを一覧として表示するときなどには使えるが、今回の場合は直接include?
を使用した方がいい。
確認したいIPアドレス範囲が複数個ある場合でも、ヒアドキュメントを組み合わせてワンライナーで書いてみる。ヒアドキュメントをパイプで渡して、標準入力を各行からなる配列として読む。各行に対してIPAddrクラスを使って引数で渡したIPアドレスが含まれているかどうかを確認している。
cat <<'EOS' | ruby -r 'ipaddr' -e 'p STDIN.readlines.any?{|c| IPAddr.new(c).include?(ARGV[0])}' $target_ip
xxx.xxx.xxx.0/24
yyy.yyy.yyy.0/26
EOS
先ほどからRubyワンライナー部分ではp
でtrue/falseを表示しているだけだが、シェルスクリプトに上記を組み込む場合は、exit
を代わりに使用して、シェルで終了ステータスを確認するとRubyとシェルの連携が簡単になる。trueであれば0が終了ステータスになり、falseであれば1が終了ステータスになる。
#!/bin/bash
target_ip=`dig +short example.co.jp`
cat <<'EOS' | ruby -r 'ipaddr' -e 'exit STDIN.readlines.any?{|c| IPAddr.new(c).include?(ARGV[0])}' $target_ip
xxx.xxx.xxx.0/24
yyy.yyy.yyy.0/26
EOS
# IPアドレスがCIDR表記で示された範囲に含まれていたら
test $? -eq 0 && echo "$target_ip is included."