読者です 読者をやめる 読者になる 読者になる

のらぬこの日常を描く

ノージャンルのお役立ち情報やアニメとゲームの話、ソフトウェア開発に関する話などを中心としたブログです。

切断そして接続

自宅で使ってる無線LANルータはWR-8500N というNECの製品です。

いくつもある製品からこれを選んだ決め手は以下の点でした。

  1. 11n, 11g, 11bを同時に使える。
  2. 1000BASE-Tの有線LAN4ポート搭載
  3. WPAとWEPを使い分けられるマルチSSID機能
  4. ネットでの評判がそれなりに良い

が!

マルチSSID機能が使い物にならない*1

そもそもパケットフィルタの設定がすごくやりずらい

という2点が致命的で、私にとっては割と残念な製品でした。

これならバッファロ~あたりを選んでいた方がよっぽど幸せになれたかもしれない。

まあ、安い買い物でもないし、当面は使い続けますけどね。

さて、この製品も他の製品同様、ISPとの回線接続、回線切断等の操作はWebブラウザからやるわけですが、いちいちWebからやらずとも、Rubyでできないかというのが今日の課題。

f:id:mikenekoDX:20100219001248p:image

上の写真で赤枠で囲まれている「切断」ボタンを押すと回線が切断され「接続」と表示が変わります。

そしてさらに「接続」ボタンを押すと、回線が接続され、表示が「切断」に変わります。

最初は、Web画面の自動操作をスクリプトから行う機能を持つ、Ruby::Mechanize のサンプルとしてブログネタにするつもりだったのですが、htmlソースを見て断念。

ボタン押せば、単にform.submit()するだけだと思っていたら、なんかJAVA Scriptでごちゃごちゃとコーディングされてました。

ソース読むのもめんどくさかったので、ボタンを押した時のパケットをキャプチャーして、その内容を http.post/getでそのまま送り込む方針に転換しました。

Webブラウザでルータの設定画面を表示させ、後はボタンを押すだけの状態にします。

その後、rootになって以下のコマンドを打ち込む。

# tcpdump -A host 192.168.0.1 and port 80
-A はパケット内容をASCII表示するためのオプションです。
リクエストの文字データをそのまま見たいだけなので16進数表示とかは不要なのです。
さらにいえば、ip部分の表示も不要なのですが、そういったことをしてくれるオプションは見つからなかった。

tcpdumpがパケットキャプチャーを開始したら、Webブラウザの切断ボタン、接続ボタンを押します。

これでパケットのログが取れているはずなので、tcpdumpの実行をCTRL+Cで停止させます。

そしてキャプチャー結果から、HTTPリクエスト部分を抜き出します。

切断時のリクエストがこれ。

POST /index.cgi/index_contents_set HTTP/1.1
Host: 192.168.0.1
Authorization: Basic xxxxxxxxxxxxxxxxxxxx=
(一部略)

CONNECT=0&BUTTON_STATUS=%C0%DA%C3%C7&DISABLED_CHECKBOX=

接続時のリクエストがこれ

POST /index.cgi/index_contents_set HTTP/1.1
Host: 192.168.0.1
Authorization: Basic xxxxxxxxxxxxxxxxxxxx=
(一部略)

CONNECT=0&BUTTON_STATUS=%C0%DC%C2%B3&DISABLED_CHECKBOX=

もしかして、接続なのか、切断なのかは、ボタン文字列で判定してますか?*2

かなりダサダサな実装な気が致しますが、それを元に作ったスクリプトがこれ。

require 'net/http'
Net::HTTP.version_1_2
req = Net::HTTP::Post.new( '/index.cgi/index_contents_set' )
req.basic_auth 'admin', '.....' # basic 認証の username / passwordを入れる
req.body=("CONNECT=0&BUTTON_STATUS=%C0%DA%C3%C7&DISABLED_CHECKBOX=")
Net::HTTP.start( '192.168.0.1' ) { |http|
  response = http.request(req)
}
sleep 3
req.body=("CONNECT=1&BUTTON_STATUS=%C0%DC%C2%B3&DISABLED_CHECKBOX=")
Net::HTTP.start( '192.168.0.1' ) { |http|
  response = http.request(req)
}

やってることは

HTTP::Postオブジェクト作成

切断リクエストをpost

3秒まつ

接続リクエストをpost

これだけです。

*1:パケットフィルタが個別に設定できない

*2:BUTTON_STATUS=%C0%DA%C3%C7 ならば切断、BUTTON_STATUS=%C0%DC%C2%B3 ならば接続