今から2年前に、3回にわけて、sedのかんたんな使い方を紹介したことがありました。
過去記事
先日、sedを使うネタが1つ出てきたことがありまして、久々に、またsedの使い方について、少しだけ書いてみようと思います。
sedの「nコマンド」を使った実際の例です。
■ ADSLルータから、グローバルIPアドレスを教えてもらいたい
ADSLで、IPアドレスが動的に割り当てられる場合に(ADSLで接続するたびにIPアドレスが変化するような場合)、インターネット側から家のパソコンにアクセスできるようにしたいときは、
を利用するのは、定番のテクニック。これは、ADSLで接続したときに割り当てられたグローバルIPアドレスに、DNSにて、特定のホスト名(FQDN)を割り振ることで、インターネット側からは、割り振ったホスト名を使ってアクセスできるようにするものです。
IPアドレスが変化してしまっても、ダイナミックDNSで、ホスト名に割り当てられたIPアドレスを更新すれば、ふたたび、いつものホスト名を使って、インターネット側からアクセスできるようになります(更新が隅々まで行き届くまで、ちょっと時間がかかるかもしれませんが)。
ダイナミックDNSでIPアドレスを登録するときに、グローバルIPアドレスを調べなければなりません。グローバルIPアドレスはどうやって調べたらいいでしょうか?いくつか手段はあると思いますが、今回は、ADSLルータに教えてもらうことにしました。
☆
先日、実家で、IP電話を導入したのですが、その際、ADSLルータも交換することになりました。交換後のADSLルータは、「Aterm WD701CV」というものです。
Aterm Support Information | WD701CV | トップページ
http://www.aterm.jp/eaccess/701/
ADSLルータは、たいてい、Webブラウザを使ってルータの管理ができる機能を持っています。WebブラウザでADSLルータにアクセスして、グローバルIPを知ることができます。
今回やりたいのは、
人がWebブラウザを操作することなく、スクリプトを実行するだけで、自動的に、グローバルIPアドレスを取得できるようにしよう
ということです。
wgetコマンドは、httpサーバにアクセスして、HTMLファイルをダウンロードしたりできるコマンドです。スクリプトで自動処理をしたいときに、とっても便利なコマンドです。余談ですが、curlというコマンドもあって、これはフォームのPOSTもできるので、かなりいろんなことが自在に出来ます。
今回やりたいことは、以下のようにして、実現できます。
- wgetでADSLルータにアクセスして、グローバルIPアドレスが表示されている画面のHTMLソースをダウンロード
- ダウンロードしたHTMLファイルを、sedで処理して、IPアドレスを抜き出す
いやぁ、前振りが長かった。長すぎた。
■ むむむ、これは・・・
以前使っていたADSLルータでは、わりと単純なsedの使い方で対応出来たんです。
こんな感じです。
#! /bin/sh
wget --quiet \
--http-user 名前 \
--http-passwd=パスワード \
-O - \
'http://192.168.1.1/cgi-bin/main.cgi?cc_webname=STATUS' | \
sed -n -e '/ADSL IP/s|[^0-9]*\([0-9.]*\).*|\1|p'
これは、HTMLファイルの中で、「ADSL IP」という行を見つけたら、その行から、IPアドレスと思われる部分を、抽出しているだけです。
今回のADSLルータAterm WD701CVは、一筋縄ではいきませんでした。
IPアドレスが記述されている行に、なんの特徴も無かったからです。
該当部分の前後だけ、抜粋してみます。
<TR BGCOLOR=THISTLE>
<TD><LABEL onMouseOver=msgShow(event,11) onMouseOut=msgHide()>WAN側 IPアドレス</LABEL></TD>
<TD>555.666.777.888 </TD>
</TR><TR BGCOLOR=THISTLE>
<TD><LABEL onMouseOver=msgShow(event,14) onMouseOut=msgHide()>WAN側 プライマリDNS</LABEL></TD>
<TD>111.222.333.444 </TD>
</TR>
一応、グローバルIPアドレスの部分は「555.666.777.888」という伏字にしときましたが、「 <TD>555.666.777.888 </TD>」という行によく似た行が、LAN側アドレスや、DNSのアドレスなど、ほかにもいろいろあるので、この行がグローバルIPアドレスだ、と特定しづらいんです。
なんだか厄介な感じがしてきますが、これは、視点をちょっと変えて、sedの「nコマンド」を使うと、うまくいっちゃうんです。
■ まずは、グローバルIPアドレスが表示されているWebページのURLを調べましょうか
とりあえず、wgetでHTMLをダウンロードできるようにしないと、話ははじまりません。グローバルIPアドレスが表示されているWebページのURLを調べましょう。
なぜか、ADSLルータは、HTMLのフレーム機能を使っていることが多いのですが、フレームを使っていると、ブラウザのアドレスバーに表示されているURLと、ブラウザに表示されている内容とが、一致しないことがあります(アドレスバーに表示されていたURLにアクセスしても、別の画面表示になる)。
そういうときは、ショートカットメニューにたいていある「リンク先を新しいウインドウで表示する」というような名前の機能を使うと、本来フレーム内で表示されるはずだった部分が、独立したウインドウで表示されます。
もともとはフレームの中身として表示されていた部分が、独立して表示されます。
そして、アドレスバーにURLも表示されます。
うちの場合、以上のようにして調べたら
http://192.168.1.1/info_main.html
でした。
JavaScriptを使ってたり、フォームを使ってたりすると、上のテクニックは使えないので、ウェブブラウザの何らかの機能の手助けを借りるとか、目視でHTMLソースを解読するとか、パケットキャプチャするとか・・・、ちょっとめんどくさいことをやらないといけないですね。
ADSLルータではまだ見たことないですが、Refererを見てアクセスを制限してたり、cookieを使ってたり、とかなってたりすると、それはそれで厄介になりますが、話が発散してしまうので、やめときます。
■ wgetでダウンロードしてみる
wgetにこんな引数をつけて、ダウンロードできます。行は長くなるので、途中で折り返しています。
/usr/local/bin/wget --quiet
--http-user ユーザー名
--http-passwd パスワード
-O -
'http://192.168.1.1/info_main.html'
「-O -」は、ダウンロードした内容を、ファイルに書き出すのではなく、標準出力へそのまま書き出すためのオプションです。パイプでsedに渡せば、スマートに処理できます。
「--quiet」はログ出力をしないようにします。
その他のオプションは、見たまんま、です。
■ 今回は、sedのnコマンドを覚えよう
sedのnコマンドは、次の行を読み出します。今回はこれを使うと、うまくいくのです。
HTMLをもう一度確認してみます。
<TR BGCOLOR=THISTLE>
<TD><LABEL onMouseOver=msgShow(event,11) onMouseOut=msgHide()>WAN側 IPアドレス</LABEL></TD>
<TD>555.666.777.888 </TD>
</TR>
なお、ウェブブラウザ上では、長い行が自動的に折り返されて表示されているかもしれませんが、<TD><LABEL onMouseOver ~ </LABEL></TD>は、1行になってます。
HTMLファイルの内容を検索してみたら、「msgShow(event,11)」という文字列は、1回だけ出現していました。これは、検索条件に使えそうです。
こんな手順をsedで実行すれば、グローバルIPアドレス抽出ができます。
- 「msgShow(event,11)」という文字列を含む行を見つけたら
- nコマンドで次の行を読み込んで
- IPアドレスを抽出する
sedで正規表現を書く場合、検索パターンにカッコがついてるとエスケープする手間がかかるので、ちょこっと変えて
/event,11.*WAN.*IP/
というパターンでマッチングさせることにしました。
sedスクリプトとしては、以下のようになります。
/event,11.*WAN.*IP/{
n
s|[^0-9]*\([0-9.]*\).*|\1|p
q
}
sは、置換コマンド。おなじみですね。
qは、そこで即座に処理を終了するコマンドです。グローバルIPアドレスを1個見つけたら、もうそれ以上処理を継続してもムダなので、とりあえずつけておきました
■ 完成したシェルスクリプト
こんな感じになりました。
#! /bin/sh
/usr/local/bin/wget --quiet \
--http-user ユーザー名 \
--http-passwd パスワード \
-O - \
'http://192.168.1.1/info_main.html' | \
sed -n -e '/event,11.*WAN.*IP/{
n
s|[^0-9]*\([0-9.]*\).*|\1|p
q
}'
これを実行すると、IPアドレスが標準出力に出力されます。
■ さいごに
sedの「nコマンド」を覚えると、sedでできる範囲がさらに広がりますねぇ。
まだISDNだったころにグローバルIPアドレスを取得する方法として、プロバイダのスペースにアクセスしてきたIPを返すっていうCGIを作ってグローバルIPをアプリに取り込んでました。
返信削除あの頃は色々なものを作ってたなぁ。
Webアプリ作りが楽しかった頃・・・。
今は、何に使うの? ホントに使うの? って言葉で却下されますが、、。
実は使ってます。
返信削除#! /bin/sh
echo "Content-type: text/plain"
echo ""
echo $REMOTE_ADDR