grepでIPアドレスっぽい文字列を雑に検索してみた
仮想マシンをマイグレーションしてIPアドレスを変更するだけの簡単なお仕事があったのですが、IPアドレスを変更したことによる影響を調べる必要がありました(IPアドレスによるアクセス制限など)。
当然、そのサーバ上で動いているWebアプリのソースコードを見たことなどないし、中身を把握している人など既に誰もいません。運用屋あるあるです。
とは言え、
- IPアドレスのパターンは決まっている
- IPアドレスが書いてあるとしたら、設定ファイルか、プログラム中か、データベース上
ということを考えると、IPアドレスが埋まっていそうなところをgrepでひたすら調べれば、それとなく手掛りは掴めそうな気がします。ということで、やってみました。
実行したgrepコマンド
とりあえず /var/www/html/ 以下の全ファイルを再帰的に検索するとした時、実行するコマンドは下記のようになります。
grep -R '[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}' /var/www/html/*
-R というオプションを指定すると、検索対象にサブディレクトリが含まれていた時、サブディレクトリの中を再帰的に検索対象にしてくれます。
コマンドラインで指定した正規表現ですが、それぞれの要素の意味は下記のようになります。
- [[:digit:]]
- 数字1文字にマッチ。[0-9]と同じ意味です。
- {n,m}
- 直前の文字のn文字以上m文字以下の並びにマッチします。歴史的理由により、”{” と “}” の前には “\” (バックスラッシュ) が必要になります。
- \.
- 正規表現で “.” (ピリオド) は任意の1文字にマッチするのですが、ピリオドそのものにマッチさせたいので、直前に “\” (バックスラッシュ) を付けて特別な意味を無くしています。
IPアドレスのパターンは(IPv4の場合)
(1〜3桁の数値).(1〜3桁の数値).(1〜3桁の数値).(1〜3桁の数値)
となるので、これを正規表現で表すと
[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}
となるわけです。
データベースの中を検索する
hoge_db というデータベースの、全テーブル全カラムを対象にIPアドレスっぽい文字列を検索する時。pg_dumpやmysqldumpでdumpを取り、grepでパターンマッチさせるのが最も手っ取り早いです。
対象データベースが MySQL の場合:
mysqldump hoge_db | grep '[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}'
対象データベースが PostgreSQL の場合:
pg_dump hoge_db | grep '[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}'
何かしらマッチするものがあった場合は、dumpの中身を注意深く精査します。何も出て来なかった場合は、それ以上深追いする必要はなし。
制限事項
例えば、下記のコマンドを実行してみるとわかるのですが、
echo 10.0.12.3456 | grep '[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}'
IPアドレスとしては明らかに間違っているパターン(最後が4桁の数値)であってもマッチしてしまうことがあります。上記の正規表現の場合、「数字1〜3文字」にマッチするわけですが、「数字4文字」の中には当然「数字3文字」が含まれるため、マッチしてしまうのです。
より厳密にマッチされないといけない場合は、例えば最後の「数字1〜3文字」の後に「数字以外の文字」などを置く必要があるのですが、これを始めると「どの文字は許してどの文字は許すべきではないか」を考えなくてはいけなくなり、面倒です。今回は、明らかにおかしいものは人間の目でチェックすれば良かったので、これ以上深追いはしませんでした。
これ以外にも、「8.9.3.1」のようなバージョン文字列にもマッチしてしまうのですが、これは単純なパターンマッチだけでは判定しようがないので、人間の目でチェックして弾くしかないです。