UPnPとポートマッピング(ポートの開放)
はじめに
インターネットを経由して遠隔地にあるパソコンとパソコンの間で通信をすることができます。パソコンが直接インターネットに接続されているときは比較的簡単に通信をすることができますが、自宅にルーターを設置していてルーターを経由してインターネットに接続しているときは簡単ではありません。この問題をクリアする方法の1つにUPnPによるポートマッピングの設定(ポートの開放)があります。
ルーターがあるとなぜ難しい?
手紙を送るときは宛先の住所が必要ですがインターネットの場合、住所は「IPアドレス」と「ポート番号」で構成されています。IPアドレスにはグローバルアドレスとローカルアドレスの2つの種類があります。グローバルアドレスはインターネットで使用されるIPアドレスで、世界中に同じものが存在しないよう管理されています。ローカルアドレスは企業や家庭内のネットワーク(ローカルエリアネットワーク(LAN))で使用されるIPアドレスで、LAN内で重複しないよう管理されています。LANに接続されているパソコンとインターネットを接続するときは、インターネットとLANの間にルーターと呼ばれる通信機器が設置されます。インターネットに接続された機器にはグローバルアドレスが割り当てられますが、ルータがない場合とある場合のグローバルアドレスの割り当ては下の図のようになります。
ルーターがない場合 (電話回線、ADSLモデムタイプ、モバイルデータカード 等) |
ルーターがある場合 (光、ADSLルータータイプ 等) |
|
|
上の図で PC−A から PC−01 にインターネットを経由してメッセージを送る場合、宛先にはグローバルアドレス( 118.111.224.218 )とポート番号( 50123 )を指定します。ポート番号は 0 〜 65535 の間の数字です。
ルーターがない場合は、送られてきたメッセージは直接 PC−01 に届くので問題はありません。
一方、ルーターがある場合は送られてきたメッセージはルーターまでは届くのですが、ルーターは届いたメッセージをどのパソコンに転送すればよいか分からないので捨ててしまいます(ルーターにパソコンが1台しか接続されてなくてもルーターは捨ててしまいます)。このため、ルーターを設置しているときは送られてきたメッセージを PC−01 は受信できないのです。
ポートマッピング
上記の問題の解決策として宛先の一部であるポート番号を利用する方法があります。具体的には「ポート番号○○○宛てに届いたメッセージはローカルアドレス △.△.△.△ のパソコンに転送する」というルールを設け、このルールをルーターに設定しておけばルーターは届いたメッセージを PC−01 に転送することができます。上の図では「ポート番号 50123 宛てに届いたメッセージはローカルアドレス 192.168.1.10 のパソコンに転送する」となります。
このルールの設定を「ポートマッピング」と言い、「ポートの開放」とも言います。
UPnP(ユニバーサル プラグ アンド プレイ(Universal Plug and Play))
機器と機器が互いに通信し、情報を取得したり設定を行ったりするための規格です。
機器としては次のようなものが想定されています : コンピュータ、通信機器(ルーター等)、プリンタ、オーディオ機器、映像機器 等
UPnPとポートマッピング
ルーターがUPnPに対応していると、パソコンからUPnPを使用してルーターにポートマッピングの設定を行えます。
※ポートマッピングの設定はルーターの管理画面から行うこともできます。ポートマッピングのことを「静的IPマスカレード」と呼ぶルーターもあります。
UPnPを使用したポートマッピングの手順
SSDP(Simple Service Discovery Protocol)プロトコルを使用してルーターを探します。
1)宛先IPアドレス:239.255.255.250 宛先ポート番号:1900 に M-SEARCH メッセージをマルチキャストします。
2)メッセージにセットする ST(Search Target)には検索するサービス名を記述します。サービス名は urn:schemas-upnp-org:service:WANPPPConnection:1 です。サービス名に WANPPPConnection:1 でなく WANIPConnection:1 を指定するルーターもあります。
3)マルチキャストなのでUDPソケットを使用します。
4)マルチキャストに対し応答が返ってくれば、応答の中の Location: の内容を取得します。Location にはUPnPに関する情報(ドキュメント)のアドレス(URL)がセットされています。
ステップ 2 | 検出したUPnP機器(ルーター)からUPnPに関するドキュメントを取得する |
HTTP(HyperText Transfer Protocol)プロトコルを使用してステップ1−4)のドキュメントを取得します。
1)HTTPの GET メソッドを使用します。
2)TCPソケットを使用します。宛先のIPアドレスとポート番号はステップ1−4)の Location にセットされているものを使用します。
3)HTTP応答のメッセージボディ部がドキュメントです。ドキュメントはXMLで記述されています。この中から <serviceType> タグの内容が urn:schemas-upnp-org:service:WANPPPConnection:1 のものを探し、その中から controlURL を取得します。controlURL は <controlURL> タグの内容です。WANPPPConnection:1 が見つからないときは WANIPConnection:1 を探します。
ステップ 3 | ルーターにポートマッピングの設定を要求する |
SOAP(Simple Object Access Protocol)プロトコルを使用して要求します。
1)UPnPで使用するSOAPプロトコルはHTTPプロトコルとあまり違いはありません。
2)HTTPヘッダに SOAPACTION: "urn:schemas-upnp-org:service:WANPPPConnection:1#AddPortMapping"(または "urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping")を記述します。
3)HTTPメッセージボディ部にSOAPメッセージをセットします。SOAPメッセージはXMLです。
4)SOAPメッセージは SOAPエンベロープ(その中は SOAPヘッダ + SOAPボディ)で構成されます。UPnPではSOAPヘッダは省略します。
5)要求内容をSOAPボディ部にXMLで記述します。要求内容の詳細は次の「
UPnPの手順の詳細」を参照して下さい。
6)TCPソケットを使用します。ステップ2−3)で取得した controlURL の中に宛先のIPアドレスとポート番号の記述があるときはその値を使用します。記述がないときはステップ1−4)の Location にセットされているものを使用します。
7)ステップ2−3)で取得した controlURL にSOAPメッセージを送ります( POST メソッドを使用します)。
8)ルーターから応答が返ります。OK/NGは応答のリスポンス行(応答の1行目)にセットされています。
UPnPの手順の詳細
ポートマッピングの設定 (AddPortMapping)
1.ルーターを探す
1)マルチキャストで M−SEARCH
M-SEARCH * HTTP/1.1
MX: 3
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
// ST: upnp:rootdevice // 2017.12 RS-500KI NG
ST: urn:schemas-upnp-org:service:WANPPPConnection:1
// ST: urn:schemas-upnp-org:service:WANIPConnection:1
・ MX = Maximum Wait MAN = Mandatory Extension ST = Search Target
2)マルチキャスト応答例
HTTP/1.1 200 OK
CACHE-CONTROL: max-age=120
Location: http://192.168.1.1:2869/upnp/rootdevice.xml
SERVER: IGD-HTTP/1.1 UPnP/1.0 UPnP-Device-Host/1.0
ST: upnp:rootdevice
EXT:
USN: uuid:6d04368b-92fbc975::upnp:rootdevice
・ Location にドキュメントのアドレス(URL = IPアドレス + ポート番号 + ドキュメントのパス名とファイル名)がセットされています。
2.UPnPに関するドキュメントを取得
1)HTTPでGET
GET /upnp/rootdevice.xml HTTP/1.1
Host: 192.168.1.1
Connection: Close
2)HTTP応答例
HTTP/1.1 200 OK
CONTENT-LENGTH: 3646
CONTENT-TYPE: text/xml
Connection: close
<?xml version="1.0"?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<device>
<deviceType>urn:schemas-upnp-org:device:InternetGatewayDevice:1</deviceType>
<friendlyName>RV-230NE</friendlyName>
...
(略)
...
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:WANPPPConnection:1</serviceType>
<serviceId>urn:upnp-org:serviceId:WANPPPConn1</serviceId>
<controlURL>/upnp/control/WANPPPConn1</controlURL>
<eventSubURL>/upnp/event/WANPPPConn1</eventSubURL>
<SCPDURL>/upnp/WANPPPConn1.xml</SCPDURL>
</service>
...
(略)
...
</serviceList>
</device>
</deviceList>
</device>
</deviceList>
<presentationURL>http://192.168.1.1/</presentationURL>
</device>
</root>
controlURL の中にSOAPメッセージのPOST先アドレスが記述されているルーターもあります。
<controlURL>http://192.168.11.1:5440/upnp/control?WANPPPConnection</controlURL>
3.ポートマッピングの設定
1)SOAPでPOST
POST /upnp/control/WANPPPConn1 HTTP/1.1
Host: 192.168.1.1:2869
Content-Length: 716
Content-Type: text/xml; charset="utf-8"
Connection: Close
SOAPACTION: "urn:schemas-upnp-org:service:WANPPPConnection:1#AddPortMapping"
<?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:AddPortMapping xmlns:m="urn:schemas-upnp-org:service:WANPPPConnection:1">
<NewRemoteHost></NewRemoteHost>
<NewExternalPort>50123</NewExternalPort>
<NewProtocol>TCP</NewProtocol>
<NewInternalPort>50123</NewInternalPort>
<NewInternalClient>192.168.1.10</NewInternalClient>
<NewEnabled>1</NewEnabled>
<NewPortMappingDescription>Test</NewPortMappingDescription>
<NewLeaseDuration>0</NewLeaseDuration>
</m:AddPortMapping>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
・要求内容
項目 | 値 | 記事 |
NewRemoteHost | 空 | 指定した送信元からのメッセージ(パケット)のみ転送するときに設定する |
NewExternalPort | 50123 | 通常、NewInternalPort と同じ値 |
NewProtocol | TCP | プロトコル。TCP または UDP |
NewInternalPort | 50123 | 転送先パソコンの受信処理プログラムのポート番号(宛先ポート) |
NewInternalClient | 192.168.1.10 | 転送先パソコンのローカルアドレス(宛先アドレス) |
NewEnabled | 1 | 1(TRUE) または 0(FALSE) |
NewPortMappingDescription | Test | コメント記述欄 |
NewLeaseDuration | 0 | 設定の有効期間(秒)。0 のときは無期限 |
2)SOAP応答例
HTTP/1.1 200 OK
CONTENT-LENGTH: 348
CONTENT-TYPE: text/xml; charset="utf-8"
SERVER: IGD-HTTP/1.1 UPnP/1.0 UPnP-Device-Host/1.0
EXT:
<?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:AddPortMappingResponse xmlns:m="urn:schemas-upnp-org:service:WANPPPConnection:1">
</m:AddPortMappingResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
・成功したときは HTTP/1.1 200 OK が返ります。
3)SOAP応答例(エラーのとき)
HTTP/1.1 500 Internal Server Error
CONTENT-LENGTH: 574
CONTENT-TYPE: text/xml; charset="utf-8"
SERVER: IGD-HTTP/1.1 UPnP/1.0 UPnP-Device-Host/1.0
EXT:
<?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>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Client</faultcode>
<faultstring>UPnPError</faultstring>
<detail>
<UPnPError xmlns="urn:schemas-upnp-org:control-1-0">
<errorCode xmlns="">718</errorCode>
<errorDescription xmlns="">ConflictInMappingEntry</errorDescription>
</UPnPError>
</detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
・指定したポート番号がすでに別のパソコンに割り当てられているときは、HTTP/1.1 500 Internal Server Error が返ります。
ポートマッピングの設定の削除 (DeletePortMapping)
1.ルーターを探す 〜 2.UPnPに関するドキュメントを取得 は「ポートマッピングの設定」と同じです。
3.ポートマッピングの設定の削除
1)SOAPでPOST
POST /upnp/control/WANPPPConn1 HTTP/1.1
Host: 192.168.1.1:2869
Content-Length: 470
Content-Type: text/xml; charset="utf-8"
Connection: Close
SOAPACTION: "urn:schemas-upnp-org:service:WANPPPConnection:1#DeletePortMapping"
<?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:DeletePortMapping xmlns:m="urn:schemas-upnp-org:service:WANPPPConnection:1">
<NewRemoteHost></NewRemoteHost>
<NewExternalPort>50123</NewExternalPort>
<NewProtocol>TCP</NewProtocol>
</m:DeletePortMapping>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
・要求内容
項目 | 値 |
NewRemoteHost | 空 |
NewExternalPort | 50123 |
NewProtocol | TCP |
2)SOAP応答例
HTTP/1.1 200 OK
CONTENT-LENGTH: 354
CONTENT-TYPE: text/xml; charset="utf-8"
SERVER: IGD-HTTP/1.1 UPnP/1.0 UPnP-Device-Host/1.0
EXT:
<?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:DeletePortMappingResponse xmlns:m="urn:schemas-upnp-org:service:WANPPPConnection:1">
</m:DeletePortMappingResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
・成功したときは HTTP/1.1 200 OK が返ります。
ポートマッピング情報の取得 (GetGenericPortMappingEntry)
1.ルーターを探す 〜 2.UPnPに関するドキュメントを取得 は「ポートマッピングの設定」と同じです。
3.ポートマッピング情報の取得
1)SOAPでPOST
POST /upnp/control/WANPPPConn1 HTTP/1.1
Host: 192.168.1.1:2869
Content-Length: 415
Content-Type: text/xml; charset="utf-8"
Connection: Close
SOAPACTION: "urn:schemas-upnp-org:service:WANPPPConnection:1#GetGenericPortMappingEntry"
<?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:GetGenericPortMappingEntry xmlns:m="urn:schemas-upnp-org:service:WANPPPConnection:1">
<NewPortMappingIndex>0</NewPortMappingIndex>
</m:GetGenericPortMappingEntry>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
・要求内容
項目 | 値 | 記事 |
NewPortMappingIndex | 0 | 取得したい情報のインデックス。インデックスは 0, 1, 2 〜 |
2)SOAP応答例
HTTP/1.1 200 OK
CONTENT-LENGTH: 725
CONTENT-TYPE: text/xml; charset="utf-8"
SERVER: IGD-HTTP/1.1 UPnP/1.0 UPnP-Device-Host/1.0
EXT:
<?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:GetGenericPortMappingEntryResponse xmlns:m="urn:schemas-upnp-org:service:WANPPPConnection:1">
<NewRemoteHost></NewRemoteHost>
<NewExternalPort>50123</NewExternalPort>
<NewProtocol>TCP</NewProtocol>
<NewInternalPort>50123</NewInternalPort>
<NewInternalClient>192.168.1.10</NewInternalClient>
<NewEnabled>1</NewEnabled>
<NewPortMappingDescription>Test</NewPortMappingDescription>
<NewLeaseDuration>0</NewLeaseDuration>
</m:GetGenericPortMappingEntryResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
・成功したときは HTTP/1.1 200 OK が返ります。
・応答にセットされるポートマッピング情報はポートマッピングの設定でセットした内容です。
3)SOAP応答例(エラーのとき)
HTTP/1.1 500 Internal Server Error
CONTENT-LENGTH: 578
CONTENT-TYPE: text/xml; charset="utf-8"
SERVER: IGD-HTTP/1.1 UPnP/1.0 UPnP-Device-Host/1.0
EXT:
<?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>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Client</faultcode>
<faultstring>UPnPError</faultstring>
<detail>
<UPnPError xmlns="urn:schemas-upnp-org:control-1-0">
<errorCode xmlns="">713</errorCode>
<errorDescription xmlns="">SpecifiedArrayIndexInvalid</errorDescription>
</UPnPError>
</detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
・NewPortMappingIndex に 2 をセットして情報取得を行った例です。該当インデックスが存在しなければ HTTP/1.1 500 Internal Server Error が返ります。
グローバルアドレス(WAN側アドレス)の取得 (GetExternalIPAddress)
1.ルーターを探す 〜 2.UPnPに関するドキュメントを取得 は「ポートマッピングの設定」と同じです。
3.グローバルアドレス(WAN側アドレス)の取得
1)SOAPでPOST
POST /upnp/control/WANPPPConn1 HTTP/1.1
Host: 192.168.1.1:2869
Content-Length: 345
Content-Type: text/xml; charset="utf-8"
Connection: Close
SOAPACTION: "urn:schemas-upnp-org:service:WANPPPConnection:1#GetExternalIPAddress"
<?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:GetExternalIPAddress xmlns:m="urn:schemas-upnp-org:service:WANPPPConnection:1"></m:GetExternalIPAddress>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
2)SOAP応答例
HTTP/1.1 200 OK
CONTENT-LENGTH: 423
CONTENT-TYPE: text/xml; charset="utf-8"
SERVER: IGD-HTTP/1.1 UPnP/1.0 UPnP-Device-Host/1.0
EXT:
<?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:WANPPPConnection:1">
<NewExternalIPAddress>118.111.224.218</NewExternalIPAddress>
</m:GetExternalIPAddressResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
・成功したときは HTTP/1.1 200 OK が返ります。
・<NewExternalIPAddress> タグの中にグローバルアドレスがセットされています。
その他
UPnPの手順をC言語+ソケットでプログラムするときの留意点です。
1.SSDP
1)マルチキャストは、どのインターフェイスを使用してマルチキャストするかの指定が必要です。
2)応答の中の Location は大文字の LOCATION のルーターもあります。location もあるかもしれません。
2.HTTP
1)HTTP/1.1 ではHTTPヘッダに Connection: Close を記述しないと、Webサーバー(ルーター)側が一定時間コネクションを切断しません(Persistent Connection)。その結果、プログラムが recv() で待機してしまいます。
2)HTTP/1.1 でHTTPヘッダに Connection: Close を記述して要求しても、ルーターからの応答のヘッダは Connection: Keep-Alive となっていてコネクションを切断しないルーターがありました。このようなルーターへの配慮が必要です。
3)HTTP/1.0 で GET するとWebサーバー(ルーター)は応答を返すとすぐにコネクションを切断するはずですが、一定時間コネクションを切断しないルーターがありました。HTTP/1.0 を使用するときはこのようなルーターへの配慮が必要です。
4)GET のとき、HTTPヘッダのあとに空行を1行加えるのを忘れないように。
このTipsについて
1.このTipsはいくつかのルーターを使用して確認を行っていますが、GARAさんの知識や理解の不足による誤りがあるかもしれません。このためTipsの使用により万一損害が生じましても責任を負いかねますのでご了承ください。また、誤りや記述ミスにお気付きの場合はメールでご連絡いただければ幸いです。
2.動作確認に使用したルーターは次の機種です。
1 | NTT | RV-230NE、RV-S340NE、RV-440MI、RS-500KI |
2 | NEC | Aterm WR6670S |
3 | BUFFALO | BBR-4MG、BBR-4HG、WBR-B11 |
4 | I・O DATA | NP-BBRL |
5 | COREGA | CG-BARMX3 |
6 | Micro Research | MR-OPTG5、MR-OPT100E |
2010.6 現在。
赤字の機種は2017.12に追加
3.改定履歴
1)SSDPで指定するサービス名を「WANPPPConnection:1(または WANIPConnection:1)」から「rootdevice」に変更。テストに使用したルーターは全てこれでOKで、この方法だとSSDPが1回で済むため。(2010.6)
2)上記方法はNTTルーター RS-500KI では失敗することが分かりました。このためSSDPで指定するサービス名を「rootdevice」から「WANPPPConnection:1」に戻しました。(2017.12)
参考文献
UPnP Device Architecture 1.0
WANPPPConnection:1 Service Template Version 1.01
HOME TOP