Mac OS X で自動的に公衆無線LANへログインするツール (wifi_login) を作った
外出先でもインターネットが使える公衆無線LANサービスは便利なんだけど、認証のためにわざわざWebブラウザを立ち上げてIDとパスワードを入力するのが面倒だったりする。なので、自動ログインするツールを Ruby で作って、 GitHub と RubyGems で公開した。
今のところ、docomoの公衆無線LANのみに対応している。
自動ログインツールを作った動機
Windowsであれば、IEEE802.1Xを設定することで自動ログオンが可能。そう。Windowsならね。
Windows® 7 : ネットワークの設定方法(自動ログイン機能) | サービス・機能 | NTTドコモ
【24】docomo Wi-Fiのエリア内に入ると、自動的に接続・ログインを開始します。
Mac OS XでもIEEE802.1Xを設定すればいい…と思っていたら、10.7 (Lion) 以降では追加のツールをダウンロードしないと設定できなくなっていた。
Macで楽しくお仕事: MacOSX 10.7 (Lion) での 802.1X 認証の設定
MacOSX 10.7 (Lion) での 802.1X 認証の設定は、MacOSX 10.6 (Snow Leopard) の時と大きく異なっており、MacOSX のシステム環境設定では行うことができなくなっています。 設定を行うには、まず「iPhone 構成ユーティリティ」をインストールし、Wi-Fi 構成プロファイルを作成し、その構成プロファイルを MacOSX にインストールします。
Macの設定なのに、「iPhone 構成ユーティリティ」という名前なのはどうしたものか。という訳で、自前でログオンツールを作ることにした。
使い方
gem をダウンロードすると wifi_login
というコマンドが使えるようになる。
基本的には wifi_login install
と pit set docomo
を実行すれば設定完了。詳しい使い方は GitHub のページ を参照。ここでは、ツールを作る上で調べた技術的なことをメモしておく。
自動ログインの仕組み
ログイン画面のHTMLを読んでいて気がついたんだけど、公衆無線LANの自動ログインはIEEE802.1Xだけじゃなく、 WISPr (Wireless Internet Service Provider roaming) という仕組みも使えるらしい。docomoも最近対応している。
au Wi-Fi SPOTにLinuxから接続できるようにしてみた - Dマイナー志向
実は今回のau Wi-Fi SPOTだけでなく、ソフトバンクのモバイルポイントなどもWISPrプロトコルに対応しています。しかしWISPr対応クライアント実装はあまり見つかりません。その理由は、ほとんどのホットスポットはWebブラウザを開くと自動的にユーザ情報入力フォームが開くようになっており、わざわざWISPrクライアントを実装する必要性がないんですね。ねるほどねー。
Docomo Wi-Fi のWISPr対応について - eggshell blue
先日、Docomo Wi-Fi に接続したところ、表記のとおりWISPrプロトコルに対応されていることが確認できました。 これで、国内携帯キャリアが提供する公衆無線LANサービスはすべてWISPrプロトコルに対応したことになります。
WISPr を使えばキャリアに関係なく汎用的に作れそうだったけど、仕組みがよく分からなかったため、泥臭く Mechanize をつかって実装しちゃった。エラー処理を除けばこんなにシンプルに書ける。
url = 'https://wlan.m-zone.jp/wlan/portal.jsp'
agent = Mechanize.new
page = agent.get(url)
form = page.form
form.user = id
form.password = password
page = agent.submit(form)
無線LANへの接続を検知して自動的に起動させたい
ツールから自動的にIDとパスワードを入力できるようになったけど、無線LANに繋ぐたびにわざわざツールを実行していたら面倒なのは変わらない。そこで、 Mac OS X の launchd を使って、無線LANへの接続を検知して自動的にツールを起動するようにした。基本的なアイデアはこちらのページを参考にさせてもらった。
無線APによって自動でhostsを変える方法 - unknownplace.org
/Library/Preferences/SystemConfiguration/com.apple.airport.preferences.plist
を監視しそれが更新されたら/Users/typester/dev/scratch/wifi_switch/switch.pl
を実行する。と言うことが実現できます。 この監視先のファイルは OSX の無線ネットワーク設定なので、これが更新されると言うことは無線通信の状態が変わったときと言うことを意味します。
APの情報は
/System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport -I
と言うコマンドで取得可能なのでそれをパースすればオッケーです。
今回はバックグラウンドでログインするだけなので、LaunchDeamonではなくLaunchAgentとして登録すればよい。ユーザ単位なので、 $HOME/Library/LaunchAgents
にplistファイルを生成する。 rbenv の環境で実行させるためにちょっと悩んだけど、「Macのlaunchdからrbenv環境のRubyスクリプトを起動する」の方法で解決した。
コマンドラインのインタフェースを用意したい
せっかくなので、 LaunchAgent の登録などもコマンドラインで提供したい。ちまちまと書いていくのは面倒だな…と思ってBundlerのソースを読んでいたら、 Thorライブラリ を見つけた。これを使えば簡単にコマンドラインのインタフェースを作れる。本当に便利。
Thor
クラスを継承して、 WifiLogin::CLI
クラスを作る。1メソッドが1つのコマンドに対応する。メソッドの前にdesc
で説明文を書く。
module WifiLogin
class CLI < Thor
desc "ssid", "Show current SSID"
def ssid
say "current SSID: #{WifiLogin.ssid}"
end
desc "login", "Login public wi-fi access point."
def login
success = WifiLogin.login
say 'Login success!', Thor::Shell::Color::GREEN if success
end
end
end
あとは bin/wifi_login
を作って、内部で WifiLogin::CLI.start
と書くだけ。これで help コマンドも生成してくれる。
$ wifi_login help
Tasks:
wifi_login help [TASK] # Describe available tasks or one specific task
wifi_login login # Login public wi-fi access point.
wifi_login ssid # Show current SSID
さらにコマンドラインからファイルのコピーやテンプレートの展開をしたい
Thorが便利なのはコマンドラインインタフェースだけでなく、ファイルのコピー、テンプレートの展開など、よく使われるタスクを簡単に作れるライブラリ(Action)が提供されていること。 rails や bundle gem のアレみたいなの。
Actionを使うには、 Thor::Actions をインクルードする。
module WifiLogin
class CLI < Thor
include Thor::Actions
desc "install", "Install trigger to your Mac OS X System (launchd)."
def install
empty_directory LOG_DIR
template "templates/jp.machu.wifi_login.plist.tt", "#{LAUNCH_AGENT_FILE}"
run "launchctl load #{LAUNCH_AGENT_FILE}"
end
end
empty_directory
: ディレクトリを作成template
: テンプレートを展開してファイルを作成run
: コマンドを実行
たった3行で実現できてしまった。すでにディレクトリやファイルが存在した場合にもエラーにならずにうまいことやってくれる。
$ wifi_login install
exist /Users/machu/Library/Logs/jp.machu.wifi_login
create /Users/machu/Library/LaunchAgents/jp.machu.wifi_login.plist
run launchctl load /Users/machu/Library/LaunchAgents/jp.machu.wifi_login.plist from "."
IDとパスワードを管理する
ログインするためのIDとパスワードは Pit というライブラリで管理することにした。
gemで公開する
作成したライブラリはgemで公開した。gemの作り方はBundlerを使ったGem作成メモ (自分用) - ただのにっき(2012-02-18)を参考に bundle gem
を使うことにした。
ちょっと修正して、 rake install
でローカルにインストールして試す、の繰り返し。キリがいいところで version.rb
のバージョンをあげて rake relase
で公開する。gemの公開だけでなくGitHubへのpushとタグ付けまでやってくれるので便利。
テストを書く
rspec で spec を書いた。「RSpec で TDiary::Plugin のテストを書く」で少し慣れていたので良かった。RSpec Kerry Buckley IPRUG, 4 January 2011のページがとても参考になる。
公開してみて
とりあえず自分が欲しくて作ってみたけど、こうやって gem にまとめるまでの過程を経験できたのは良かった。ちょこちょこ修正していこうと思う。