はじめに
無線LANルータを買い換えました.BUFFALO Air Station NFINITI HighPower Giga 11n/g/b対応 無線LANアクセスポイント WZR-HP-G300NHです.
つなぎ替えて設定して*1,LANも無線も快適になった…
と思いきやトラブル発生.ノートPC (Windows Vista)から,LAN内のサーバに接続できません.
それまでは,自宅からでも外からでも,DynDNSで設定しているドメイン名で,アクセスできたのですが.
主な用途はSSH.Subversionでアップデートもコミットもできなくなってしまいました.シェルでsshコマンドを実行するのも,しばらく待たされたあと,「Connection timed out」と言ってきます.
外には出られるので,名前解決ができればよさそうです.しかし,くだんのルータには,ホスト名とIPアドレスの登録ができそうになく,かといって,ノートPCで自宅使用時のDNSサーバをLAN内のにするのも手間です.sshコマンドだけなら,~/.ssh/configに書き加えることで対処できますが,Subversionの svn+ssh:// のあとのホスト名を,ローカルなIPアドレスに変更するというのは,やりたくありません.
無線LANルータのこの問題,軽く調査すると,やむにやまれず : Air Stationに変えたらLAN側自社サービスにアクセスできなくなったを発見しました.2年前の記事ですが,今も変更なしの可能性があります.
解決策は3つくらいありそう。
やむにやまれず : Air Stationに変えたらLAN側自社サービスにアクセスできなくなった
- 上のリンクにも書かれているけど、WAN側にあるHTTP Proxyを使う
- hostsを書く
- LAN側に上記hosts相当のDNSを立てる
これを読んで,そうだWindowsにもたしかhostsファイルがあるはずだから,それを書き換えることにしよう,と決めました.
Windowsのhostsはどこ?
まずはWindows環境でのhostsファイルの所在を調査.ほどなく,見つかりました.
hostsファイルが存在する位置はOSによって違います。興味がある方はエクスプローラを使って探してみて下さい。
ただし、システムファイルなのでむやみやたらにいじっては駄目です。Windows XPの場合→「C:\WINDOWS\system32\drivers\etc」
Windows 2000の場合→「C:\WINNT\system32\drivers\etc」
Windows 95/98/MEの場合→「C:\Windows」場合によってはhostsのあとに拡張子が付いたもの、例えば「hosts.ini」などが見つかる場合がありますが、ここで言うhostsファイルは拡張子が無いものです。
higaitaisaku.com
Windows VistaもXPと同じ…まあ英字の大小はMeadowで開いたときのものに変更しておきますか…「c:\Windows\System32\drivers\etc\hosts」でした.
こういうのもありました.
2) レジストリの、 次の値はどうなっていますか。
http://sakaguch.com/pastbbs/0034/B0017364.html#No17392
キー: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
名前: DataBasePath
実際に参照されるのは、 ここで指定されたパスにある hosts ファイルです。
標準では、 「%SystemRoot%\System32\drivers\etc」 という REG_EXPAND_SZ 値になっています。
あまり書き替えの必要が生じない値ですので、 書き替えられているようであれば、 ウィルス感染も視野に入れて疑ったほうが良いのかもしれません。
まあ今は,レジストリまで見に行かなくてもいいでしょう.
もう一つ.
有効・無効が切り替えられ*2,hostsファイルの変更監視にも対応.
対応OSにVistaや7の名前が入っていないのが気がかりです.デスクトップのVistaマシンにインストールしてみたところ,問題なく動作しました.起動直後は真っ白ですが,メニューの「ファイル(F)>現在のhostsファイルを開く(C)」を選べば,表示されました.
ともあれこれはこれとして,自分の勉強のため,プログラムを作りましょう.
JScriptを採用,そして苦労
ではプログラミング.ファイルの書き換えならRubyといきたいところですが,CygwinやRubyを入れていないようなノートPCでも実行できるようにしようと検討し,JScriptを採用しました.
JavaScriptと同じ感覚で書け,Windows Script Host (WSH)の機能を使えば,ローカルファイルの読み書きや,ダイアログボックスの表示も可能です*3.
実はもう一つ,JScriptを採用した理由があります.ファイルを書き換えるスクリプトファイルを,見つけたのでした.
そのプログラムをコピーさせてもらい,インデントとスペーシングは自分の好みに変更した上で,作りたい機能になるよう,コードに手を加えました.
考えたことを箇条書きで:
- “IPアドレスとホスト名の対応”を「追加するjsファイル」と「削除するjsファイル」を作る.
- 「追加するjsファイル」を実行したとき
- 「追加するjsファイル」を実行したとき
- hostsファイルに複数の“IPアドレスとホスト名の対応”はないものとする.
- hostsファイルのそれ以外の(挿入・削除したいホスト名文字列を含まない)行は,そのままとする.
- hostsファイルは小さいこともあり,処理の簡単化のため2パスで行う.すなわちまずhostsファイルを読み出して,出力する内容を文字列として保持し,ファイルを閉じる.書き換える必要があれば,hostsファイルを書き込み用に開き,流し込む.
それでコーディングですが,“IPアドレスとホスト名の対応”があるとかないとか,コメント付きだとかを,検出する方法のところで,苦労しました.しばらくInStrというのを試していたのですが,常にエラーです.どうやらこれはJScriptではなくVBScriptの関数なのだと気づいて,正規表現マッチングに切り替えると,まあできるようになりました.
しかし考えてみれば,探す対象(ホスト名)は固定文字列なので,正規表現に頼ることなく,もっと手軽な方法があるだろうと再度探すと,文字列に対するindexOfメソッドを見つけました.RubyのString#indexとほぼ同じですが,文字列が見つからなかったときの戻り値が-1である(Rubyはnil)点だけ要注意です.
完成したスクリプトファイル
/* -*- coding: shift_jis-dos -*- */ /* addhost.js : IPアドレスとホスト名の規則を追加 */ // 書き変えたい内容 //var file_hosts = "hosts"; //var file_to = "hosts_to"; var file_hosts = "c:\\Windows\\System32\\drivers\\etc\\hosts"; var file_to = file_hosts; var str_host = "sokonoke.sokonoke.asokonoke"; var str_ipaddr = "192.168.aaa.iii"; var str_line = str_ipaddr + " " + str_host; // ファイル存在チェック var fso = WScript.CreateObject("Scripting.FileSystemObject"); if (!fso.FileExists(file_hosts)) { WScript.Echo("ファイルが存在しません。"); WScript.Quit(); } // 読み込み var content = ""; var found = 0; // 0:存在しない,1:存在する,2:コメントされていた var txt_r = fso.OpenTextFile(file_hosts, 1); while (!txt_r.AtEndOfStream) { var str = txt_r.ReadLine(); if (str.indexOf(str_host) >= 0) { if (str.indexOf("#") == 0) { WScript.Echo(str_host + ":\r\nコメントされていました。\r\nコメントを取り除きます。"); content += str_line + "\r\n"; found = 2; } else { WScript.Echo(str_host + ":\r\n見つかりました。\r\n修正しません。"); content += str + "\r\n"; found = 1; } } else { content += str + "\r\n"; } } txt_r.Close(); if (found == 0) { WScript.Echo(str_host + ":\r\n見つかりませんでした。\r\n規則を追加します。"); content += str_line + "\r\n"; } // 書き出し if (found != 1 || file_from != file_to) { var txt_w = fso.CreateTextFile(file_to); txt_w.Write(content); txt_w.Close(); WScript.Echo(file_to + ":\r\n置換終了"); }
/* -*- coding: shift_jis-dos -*- */ /* delhost.js : IPアドレスとホスト名の規則を削除 */ // 書き変えたい内容 //var file_hosts = "hosts"; //var file_to = "hosts_to"; var file_hosts = "c:\\Windows\\System32\\drivers\\etc\\hosts"; var file_to = file_hosts; var str_host = "sokonoke.sokonoke.asokonoke"; var str_ipaddr = "192.168.aaa.iii"; var str_line = str_ipaddr + " " + str_host; // ファイル存在チェック var fso = WScript.CreateObject("Scripting.FileSystemObject"); if (!fso.FileExists(file_hosts)) { WScript.Echo("ファイルが存在しません。"); WScript.Quit(); } // 読み込み var content = ""; var found = 0; // 0:存在しない,1:存在する,2:コメントされていた var txt_r = fso.OpenTextFile(file_hosts, 1); while (!txt_r.AtEndOfStream) { var str = txt_r.ReadLine(); if (str.indexOf(str_host) >= 0) { if (str.indexOf("#") == 0) { WScript.Echo(str_host + ":\r\nコメントされていました。\r\n修正しません。"); content += str + "\r\n"; found = 2; } else { WScript.Echo(str_host + ":\r\n見つかりました。コメントにします。"); content += "#" + str + "\r\n"; found = 1; } } else { content += str + "\r\n"; } } txt_w.Close(); if (found == 0) { WScript.Echo(str_host + ":\r\n見つかりませんでした。\r\n修正しません。"); } // 書き出し if (found == 1 || file_hosts != file_to) { var txt_w = fso.CreateTextFile(file_to); txt_w.Write(content); txt_r.Close(); WScript.Echo(file_to + "\r\n置換終了"); }
結果
ノートPCにコピーして,変数str_host,str_ipaddrの値をまともなものにし,addhost.jsをダブルクリックすれば*4,hostsが書き換えられ,sshで無事に入れるようになりました.delhost.jsをダブルクリックすれば,sshで入れなくなりました.
また,書き換える必要がないときには,たしかに書き込みを行っていないことも,確認しました.
*1:小さなトラブルを解決したのでメモ:サーバ設定ページには認証がかかっていて,出荷時設定のユーザ名は(内緒),パスワードは空っぽなのですが,Fireboxで入力する打ち込む際には,(内緒),Tab,Tab,Enterではだめで,(内緒)のあと即Enterとすれば,入ることができました.
*2:無効でも規則が削除されるわけではないのですね.
*3:JScriptとWSH他との関係を手早く知るには,http://www.atmarkit.co.jp/fwin2k/tutor/cformwsh01/cformwsh01_01.html
*4:なお,書き換え対象のhostsファイルは,システムファイルなので,管理者の権限が必要です.