SSブログ

golangでUPnPのポートフォワーディングをしてみる5−グローバルアドレスを取ってみる。 [プログラミング]

今までルータのXMLが腐っているとかで、UPnPでポートフォワーディングするのが怪しくなってきているわけですが、続けていきますよ一応。まぁブツ切れの検証コードしか作れませんが、環境がまちまちなのでこっちで解決するには面倒臭すぎるというのはありますね。

ポートフォワーディングをしてみる前に、簡単にできそうなグローバルアドレスを取りに行くことをします。これは結構他でもやられているので、それをGolangに落とせばいいという話ですよね。

ともあれ、NECのルーターのUPnP用のポートのサービスが死にやすいということが発覚して、やる前にルーターを再起動しないといけないという体たらくで…。まぁNECのAtermは80番ポートを解放するだけで数日でルーターが死んでインターネットのアクセスができなくなるくらいですから、頑丈さからするとめっちゃ弱いと言わざるを得ません。ソフトの作りも悪いんだろうけど、多分スペックも足りてないんでしょうね。

あまり不満を言っていてもしょうがないので実際やってみますね。今回も事前に調べた体で、ルーターのIPとPOSTを食らわせるURLの一部を用意しておきます。それらを調べるコードは前回のコードでやっていますけど、繋げちゃうとどこがおかしくて動かないかどうかが分からなくなってしまうので、検証コードとしては短いほうがいいと思っています。



先にも言った通り、ルーターのローカルアドレスやらが分かっていないと動きません。具体的には
routerAddr
serviceType
controlURL
をルーターの設定に合わせて書き直さないと動きません。

それと返すXMLが腐っていなければ(同じフォーマットであれば)、問題なくグローバルアドレスが取れるかと思われます。大したことやってない割には苦労していますね。とりあえず苦労した点などは言っておきましょうか。


一番の問題はXMLを受けて解析するところなんですが、一応"encoding/xml"パッケージが解析してくれはします。ただ問題なのが解析の元となるXMLの構造をGolangの構造体で示してあげないといけない、という苦行が待ち構えているわけです。実際送られてきたXMLが下のようなものです。これも複数のルーターで調べたわけではないので、構造が違う可能性はあります。

<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
	<SOAP-ENV:Body>
		<m:GetExternalIPAddressResponse xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1">
			<NewExternalIPAddress>27.95.xxx.xxx
		</m:GetExternalIPAddressResponse>
	</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

これが洗練された方法があるわけでもなく、泥臭く構造体を定義するというクソッタレな仕様になっているわけです。どこかでXMLなんてタヒねばいいのにって書いてあったのですがその通りだと思います。かと言って情報交換するのにきちんと規定されたフォーマットってのは他にはあまりないわけで。

https://text.baldanders.info/golang/unmarshalling-xml/

今回は全体の構造体を定義せずに、そのパスだけを提示してグローバルアドレスだけを取ってきています。なので、正直言って全部の構造体を定義して全部入れ込むということは、今の自分にはできません。というかやりません。だってグローバルアドレスを取りたいだけなので、他の情報はいらないですから。そんなわけで構造体の定義は全体的にはしていません。

type root struct {
    NewExternalIPAddress string `xml:"Body>GetExternalIPAddressResponse>NewExternalIPAddress"`
}


でBody、GetExternalIPAddressResponse、NewExternalIPAddressと階層を示しているんですが、これで示せば他の構造は無視できるんですね。逆にいうとこの方法だと他の情報が取れない。

このやり方にしても、構造体の定義をするにしても、?xmlというタグとEnvelopeというタグは無視されているのはよくわかりません。?xmlは省略するのはわかるとして、次の階層になるEnvelopeというタグに関しては省略してしまうのはどうなのかなと思わなくはありません。でも、GolangのUnmarshal()がそういう仕組みになっているから仕方ありません。そうだからそうとしか言えないです。

とりあえず、これでルーターのグローバルアドレスを取ることはできるはずです。できなかったら変えるべき所を自分の環境に変えられていないか、ルーターの動作が死んでいるかですね。もしかするとルーターの再起動が必要かもしれません。XMLが返ってきているのに、構造体の中に入っていない場合は、XMLの構造がきちんとしていないということだと思います。


次はルータのポートフォワーディングをします。やる手順としては今回と大して違いがないはずです。今回と違う所を重点的に書いておこうと思います。

タグ:Golang
コメント(0) 
共通テーマ:パソコン・インターネット

コメント 0