UPnP を使って外部からルーターのポートマッピングを変更する仕組みを準備している。 テストは、C++ で書いたコードですでに終了している。 さーて、ということで、ASP.NET 2.0 で実装することにして、コードをC#に書き換えた。

 これで必要な時に、Web にアクセスして必要なポートを開け、外部からVPNをするのだ。(嬉)

 ところが何か様子が変だ。 レスポンスを途中までしか読むことが出来ないのだ。 パケットをキャプチャーしてみると、実際は必要な情報は全部流れて来ている。 下記はそれを一部抜粋したものだ。
0002 : 50 18 0C 00 94 E4 00 00 48 54 54 50 2F 31 2E 31 P.......HTTP/1.1
0003 : 20 32 30 30 20 4F 4B 0D 0A 43 6F 6E 6E 65 63 74  200 OK..Connect
0004 : 69 6F 6E 3A 20 20 63 6C 6F 73 65 0D 0A 53 65 72 ion:  close..Ser
0005 : 76 65 72 3A 20 55 50 6E 50 2F 31 2E 30 20 55 50 ver: UPnP/1.0 UP
0006 : 6E 50 2D 44 65 76 69 63 65 2D 48 6F 73 74 2F 31 nP-Device-Host/1
0007 : 2E 30 0D 0A 43 6F 6E 74 65 6E 74 2D 6C 65 6E 67 .0..Content-leng
0008 : 74 68 3A 20 34 30 32 0D 0A 43 6F 6E 74 65 6E 74 th: 402..Content
0009 : 2D 54 79 70 65 3A 20 74 65 78 74 2F 78 6D 6C 3B -Type: text/xml;
000A : 20 63 68 61 72 73 65 74 3D 22 75 74 66 2D 38 22  charset="utf-8"
000B : 0D 0A 0D 0A                                     ....

Source Address: 192.168.11.59 
Destination Address: 192.168.11.11
Source Port: 1900  Destination Port: 1524
0000 : 45 00 01 BA 5F EB 00 00 40 06 81 BC C0 A8 0B 3B E..._...@......;
0001 : C0 A8 0B 0B 07 6C 05 F4 33 F2 60 0D D6 77 7A 87 .....l..3.`..wz.
0002 : 50 18 0C 00 19 7D 00 00 3C 3F 78 6D 6C 20 76 65 P....}....<
0004 : 53 4F 41 50 2D 45 4E 56 3A 45 6E 76 65 6C 6F 70 SOAP-ENV:Envelop
0005 : 65 20 78 6D 6C 6E 73 3A 53 4F 41 50 2D 45 4E 56 e xmlns:SOAP-ENV
 読み込んでいるコードはこんな感じ
do {
    bytes = stream.Read(data, 0, data.Length);
    if (bytes == 0)
      break;
    ms.Write(data, 0, bytes);
}
while (stream.DataAvailable);
 一番上のキャプチャーデータのように、ストリームが間歇的に途絶えると、 (charset="utf-8" のあたり)
NetworkStreamクラスのDataAvailable は偽(false)を返すようだ...
 この動作を制御する方法があるのかどうかはわからない。 検索してみると、同じように記載してあるサンプルコードが大量に見つかった。(汗)

 ほんと、しょうがないので下記のように書き換える、
do {
    bytes = stream.Read(data, 0, data.Length);
    ms.Write(data, 0, bytes);
}
while ((bytes !== 0);
 これって、このコードって、何か悲しい。 ボクの環境でだけ起こることなのか? 誰も困っていないのだろうか?

 最近ルータのWAN側のアドレス、プロバイダから受け取っているグローバルアドレスが頻繁に変わるようになってきた。 今までは、電源を落とすか、ルータをリセットしない限り、そのままだったのに...

 サーバーの再インストールのついでに二年ほど前に書いたUPnPのプログラムをアドレスの監視のために動かすことにした。 ところが、動きが妙だ。 最近メモリー不良を起こしたVista機で散々苦労したので、また「わけわか」の再来かと一瞬いやーな気になった。

 デバッグをしてみると、ルータが HTTP/1.1 401 Unauthorized エラーを返している、 まれにそのエラーの後に壊れた構造のHTML文書が流れてくる。 ルータが変わったので、何か内部のデータ構造に変更があったのかと、ルータ相手に、手動で各種の .xml 文書を要求し眺めてみる。 serviceType の WANPPPConnection も存在し、GetExternalIPAddress もサポートしているのは確認した。 しかしエラーは止まらない。 ヘッダーに基本認証情報を付け足したり、危険だけれど一時ルーターのパスワードを解除してみたりもした。 問題は変わらない。

 Intel のサイトから、IntelToolsForUPnPTechnologyという,.NET用のライブラリをダウンロードし、その中にある Devise Spy を動かしてみた。 無事にGetExternalIPAddressは動作しているようだ。 では、どんなパケットを飛ばしているか?ということでパケットをキャプチャーしてみた。 それが、残念ながら、じぶんが飛ばしているものと殆ど変わらない。 ヘッダーの項目の順番が違うくらいだ。 単純なSOAPリクエストなので、当然誰が書いてもそんなに違いが出るものではない。

パターン1
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
   <s:Body>
      <u:GetExternalIPAddress xmlns:u="urn:schemas-upnp-org:service:WANPPPConnection:1" />
   </s:Body>
</s:Envelope>
パターン2
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<u:GetExternalIPAddress xmlns:u="urn:schemas-upnp-org:service:WANPPPConnection:1" />
</s:Body>
</s:Envelope>
 パターン1とパターン2の違いは何だろうか? そうインデントがあるか?ないか?の違いだけだ。
XML文書ではインデントは必須ではないと規定されている、インデントした方が人間が見た時に理解しやすいですよ、との解説が多い。

 結論から言うと、このインデントが問題だったようだ。 ボクはプログラムに送りつけるXML構文なので、インデントを入れていなかった。 最初の<s:Body>の頭に一つでも空白を入れれば、ルーターは元気に正しいグローバルアドレスを戻してくる。

 Intel のツールキットでは律儀に空白三文字分のインデントを入れているので動作したわけだ。

 この問題の解決に、他の仕事をやりながらだが、ほぼ12時間を費やした。 どうしても頑固なルーターの挙動に、一時は取替えを決心したほどだ。 しかし、いかにもその解決策はプログラマとして悔しい。 と言っても、半日もかけるのもなぁ...(笑) 今回はルーターのファームウエアのルール違反だね。 メーカー名と型番は言わないこととする。

 おかげで、IntelToolsForUPnPTechnology を発見。 なかなか優れものなようなので、そのうちいじってみよう。 Microsoft の UPnP SDK も?

10/06/2007 11:11 AM

こんにちは、お疲れ様でした、転んでも....良いもの見つかりましたね。
昔、全角の空白で苦労したことが有りますが (笑)

スー

10/06/2007 12:52 PM

ルーターのファームウエア側での処理の方法が想像できません。 改行を 0x0a だけにしてみましたが、動作は変わりませんでした。 パターン2の<s:Body>の左にたった一つだけ空白を入れ、他はそのままでも動作します。
同じメーカーのほかの型番のルータはXMLの規定どおり、インデントがあっても無くても動作します。 まあ、しょうがないね...と言うしかありません。(笑)

本人

 ポートマッピングしたポートで待ちうけるプログラムを走らせ、外からアクセスしてみる。 久しぶりに Air'H を動かした。 結果は見事アクセスできる。

 この状態でルータの設定を見てみると、バーチャルサーバー機能の部分には、UPnPで設定した情報は見えない。 おまけにこのルータのバーチャルサーバーの設定はリセットしないと有効にならない。 UPnPでの設定ではもちろん、リセットはしていない。 それでも有効になるわけだ...

 ポートマッピングを削除してアクセスが拒否されることを確認した。 後は、CGI として外からUPnPを使って設定できるようにプログラムをくみ上げるだけだなぁ。

10/10/2005 9:42 AM

おはようございます。Air'Hと接続している時はUPnPの設定が見えないのですか、むむ 良く理解していないな~。思っていたよりも紅葉が進んでいるんですね、昨日の釣リング北海道で岩内港のサバ釣が放映されていました。
凄い人でした、ホッケ釣は座って、サバは立って釣るんです。

スー

10/10/2005 10:15 AM

 スーさん、おはようございます。 説明が悪かったのかなぁ。 Air'H とは関係がなく、たとえばブラウザからルータの設定を行う画面にUPnPで設定した情報が表れないということです。
 動作としては、ブラウザから設定した時と同じように動きます。しかし、ブラウザから設定した時はルータのリセットが必要になりますが、UPnPで設定した時はリセットしなくても有効になります。
 何せ、ユーザー名、パスワードを設定してあってもそれに関係なくアクセスできてしまうんだから...良いんだか悪いんだか???

本人

 UPnPをいじってみる その5 で設定した、ポートマッピングを削除してみる。 この動作が確認できれば、実際に開けたポートを通して外からアクセスできるかの確認作業になる。 さーて、どうなるかな?



 送ったコマンド
POST /upnp/control3 HTTP/1.0
Content-Type: text/xml
SOAPACTION:"urn:schemas-upnp-org:service:WANIPConnection:1#DeletePortMapping"
Content-Length: 368
Host: 192.168.11.59:80

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
 s:encordingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body><u:DeletePortMapping xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">
<NewRemoteHost></NewRemoteHost>
<NewExternalPort>34567</NewExternalPort>
<NewProtocol>UDP</NewProtocol>
</u:DeletePortMapping>
</s:Body></s:Envelope>
 受け取った文字列
HTTP/1.1 200 OK
CONTENT-LENGTH: 268
CONTENT-TYPE: text/xml; charset="utf-8"
EXT:
Connection: close
SERVER: IGD-HTTP/1.1 UPnP/1.0 UPnP-Device-Host/1.0

<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
 s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<m:DeletePortMappingResponse xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1"/>
</s:Body></s:Envelope>
 なーんと...これもすんなりうまく動作した。 残されたのは外からの接続テストだねぇ。

 いよいよ、ポートを開くコマンドを送ってみることになる。 この安物の(失礼)ルータはきちんと反応してくれるだろうか?
 ドキドキものだ...



 送ったコマンド
POST /upnp/control3 HTTP/1.0
Content-Type: text/xml
SOAPACTION:"urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping"
Content-Length: 590
Host: 192.168.11.59:80

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
 s:encordingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body><u:AddPortMapping xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">
<NewRemoteHost></NewRemoteHost>
<NewExternalPort>34567</NewExternalPort>
<NewProtocol>UDP</NewProtocol>
<NewInternalPort>23456</NewInternalPort>
<NewInternalClient>192.168.11.10</NewInternalClient>
<NewEnabled>1</NewEnabled>
<NewPortMappingDescription>Redpine</NewPortMappingDescription>
<NewLeaseDuration>0</NewLeaseDuration>
</u:AddPortMapping>
</s:Body></s:Envelope>
 受け取った文字列
HTTP/1.1 200 OK
CONTENT-LENGTH: 265
CONTENT-TYPE: text/xml; charset="utf-8"
EXT:
Connection: close
SERVER: IGD-HTTP/1.1 UPnP/1.0 UPnP-Device-Host/1.0

<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
 s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<m:AddPortMappingResponse xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1"/>
</s:Body></s:Envelope>
 実際にアクセスできるかは別問題だけれど、コマンドは正常に処理されたようで HTTP/1.1 200 OK が戻ってきている。

 いよいよ、ルータにWAN側で取得しているIPアドレスを問い合わせるコマンドを送ってみる。 あて先は、/upnp/control3 だ。 これは 前回 http://192.168.11.59/desc.xml から受け取ったXMLファイルの内容の service の controlURLタグの内容。 ポートは 80 である。


 送信したコマンド
POST /upnp/control3 HTTP/1.0
Content-Type: text/xml
SOAPACTION:"urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress"
Content-Length: 240
Host: 192.168.11.59:80

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
 s:encordingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body><u:GetExternalIPAdress xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"/>
</s:Body></s:Envelope>
 受信した文字列
HTTP/1.1 200 OK
CONTENT-LENGTH: 361
CONTENT-TYPE: text/xml; charset="utf-8"
EXT:
Connection: close
SERVER: IGD-HTTP/1.1 UPnP/1.0 UPnP-Device-Host/1.0

<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
 s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body><m:GetExternalIPAddressResponse xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1">
<NewExternalIPAddress>2?1.1?8.8?.6?</NewExternalIPAddress>
</m:GetExternalIPAddressResponse></s:Body></s:Envelope>
 2?1.1?8.8?.6? なんて書いてあるけど実際は正しいIPアドレスが戻ってきている。
 とりあえず成功だ。

07/04/2010 7:53 PM

http://summerville.zaochnica.pp.ua/ сайт знакомств глаза в
http://padilla.zaochnica.pp.ua/ жуковский интим знакомства
http://thorburn.zaochnica.pp.ua/ интим услуги подружек
http://willson.zaochnica.pp.ua/ познакомиться с иностранцем французом
http://guihot.zaochnica.pp.ua/ ищу семейную пару для секса

|katmokaaAT NOSPAMvip dot routedating dot com

07/05/2010 11:35 AM

http://mcmicking.zaochnica.pp.ua/ сайты знакомств италия
http://leach.zaochnica.pp.ua/ знакомства город подольск
http://mccraw.zaochnica.pp.ua/ сибирская подростковая служба знакомств
http://nock.zaochnica.pp.ua/ бритва для интимной стрижки
http://mcniven.zaochnica.pp.ua/ онлайн игры знакомства обои

|eekamokaaAT NOSPAMvip dot routedating dot com

 昨日の、Location:http://192.168.11.59:80/desc.xml を Firefox で読み込んでみる。

 XMLファイルの中身のうち、多分 controlURL タグ内の /upnp/control3 にコマンドを POST で送ってやれば良いはずだ。 さーて、次は...

10/07/2005 3:2 PM

今日は、解体作業無事終了、結構使っていない筋肉が在るのが判る。
年月のたった実証だろう。こんどのルーターにUPnP設定のメニューが無い
全て自動で働いているのだろうか。

スー

10/07/2005 3:51 PM

 スーさん、こんにちは。 少なくてもUPnP機能のON,OFFくらいはありそうですが、特殊なルータでしょうから...なにせ「モデム」と書いてありますからねぇ。

本人

 コマンドを送ってみる。 IPアドレス 239.255.255.250 の ポート 1900 に以下の文字列をマルチキャストするんだそうだ。 ボクのルータの実際のアドレスは、192.168.11.59

 参考URL
Windows XP のユニバーサル プラグ アンド プレイ(UPnP)

 送った文字列
M-SEARCH * HTTP/1.1
MX:3
Host:239.255.255.250:1900
Man:"ssdp:discover"
ST:urn:schemas-upnp-org:device:WANConnectionDevice:1
 ルータから戻ってきたのは下記
ST:urn:schemas-upnp-org:device:WANConnectionDevice:1
USN:uuid:00-0A-79-3B-FA-69-3B0BA8C02::urn:schemas-upnp-org:device:WANConnectionDevice:1
Location:http://192.168.11.59:80/desc.xml
Cache-Control:max-age=1800
Server:IGD-HTTP/1.1 UPnP/1.0 UPnP-Device-Host/1.0
Ext:
 この中で重要なのは、Location:http://192.168.11.59:80/desc.xml の部分。 このXMLファイルの中に必要な情報が入っているはず。 次はこのファイルをダウンロードする。

 懸案だったUPnPをいじってみる。 ボクが使っているルーターは二千円台で買ったものだけれどUPnPに対応しているらしい。 「マイネットワーク」にアイコンが現れるし、パケットをキャプチャーしていると、頻繁にUPnPのパケットが流れている。

 実は夏に起こったルータ反乱の問題はこれが原因ではあったのだ。 OSをインストールしてしばらくの間は、タスクトレイにもUPnPデバイスとしてアイコンが現れるけれど、いつの間にか無くなってしまう。 何者かが隠しているのだろう。 (笑)

10/06/2005 9:37 AM

おはようございます。
このルーターのアイコンって見たこと1度も無いなぁ・・・・。
そういえばスーさんもあるっていって多様な気がするけど。。。。????

EzoTanuki

10/06/2005 12:34 PM

 EzoTanuki さん、こんにちは。 XPのインストール時にUPnPのモジュールが有効化されないケースもあるようです。 それと FireWall が有効な場合例外としてUPnPが通るように設定されていないといけないようですョ。

本人