UPnPでポート開放

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
みなみ

UPnPでポート開放

#1

投稿記事 by みなみ » 14年前

Winsockを使ってチャットを作成しています。
ローカルネットワーク上では自分のPC二台でやり取りができたのですが
インターネットを通してやり取りをするとなるとルーターからポートを開放しなければならないので
UPnPを使用してポートを開放したいです。

自分がサーバーを起動し、ユーザーがクライアントとなれば、私がルーターにアクセスして手動で開放してもいいのですが、
配布したりしてサーバーを私以外の人が起動するときに手間を取らせないためにソフト側でポートの開放をしたいです。

http://ohwhsmm7.blog28.fc2.com/blog-entry-15.html
こちらのページを見つけたのですが、いまいちピンとこないので
他にいいやり方が載ってるページ、もしくはいいやり方を教えてください。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: UPnPでポート開放

#2

投稿記事 by softya(ソフト屋) » 14年前

UPnP以前の質問ですが、サーバーと成るPCのIPアドレスはどうやって相手の方に通知する予定でしょうか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

みなみ

Re: UPnPでポート開放

#3

投稿記事 by みなみ » 14年前

softya(ソフト屋) さんが書きました:UPnP以前の質問ですが、サーバーと成るPCのIPアドレスはどうやって相手の方に通知する予定でしょうか?
あぁ、その問題がありましたね。。。
忘れていました。
まだ考えていないのですがそちらを先に考えた方がよろしいでしょうか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: UPnPでポート開放

#4

投稿記事 by softya(ソフト屋) » 14年前

みなみ さんが書きました:
softya(ソフト屋) さんが書きました:UPnP以前の質問ですが、サーバーと成るPCのIPアドレスはどうやって相手の方に通知する予定でしょうか?
あぁ、その問題がありましたね。。。
忘れていました。
まだ考えていないのですがそちらを先に考えた方がよろしいでしょうか?
どうやって、サーバーやクライアントのIPアドレスを相手に渡すかは重要な問題ですので、UPnPとは別に解決する必要があります。
ルータが間に挟まっている場合は、PCがグローバルIPアドレスを調べるためには外部サーバで調べるしか有りません。
その外部サーバは自分で用意するか、公開されているサーバを利用条件の許される範囲内で利用する必要があります。

出来れば、サーバーとクライアントのマッチングをする公開マッチングサーバーを用意したほうがいろんな人に遊んでもらうには良いと思います。
マッチング後は、各々のサーバーとクライアント間で通信してもらいます。
そういう仕組にしないと、お互いにメールアドレスを知る知人同士でしか使えないと思いますよ。

それとUPnPのコードですが、私もUPnPはやったことはないですが、このCOMコードは難しくないのでよく分からなくても試してみてはどうでしょうか?
char *ip = "192.168.xxx.xxx"; <- 自分のPCのローカルIPアドレス
BSTR description = SysAllocString( L"????" ); <- ここはポートマッピングに登録する名前。適当で良いと思います。
int port = xxxx; <- 開放するポート番号
を入力するだけで動くと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

みなみ

Re: UPnPでポート開放

#5

投稿記事 by みなみ » 14年前

softya(ソフト屋) さんが書きました:
みなみ さんが書きました:
softya(ソフト屋) さんが書きました:UPnP以前の質問ですが、サーバーと成るPCのIPアドレスはどうやって相手の方に通知する予定でしょうか?
あぁ、その問題がありましたね。。。
忘れていました。
まだ考えていないのですがそちらを先に考えた方がよろしいでしょうか?
どうやって、サーバーやクライアントのIPアドレスを相手に渡すかは重要な問題ですので、UPnPとは別に解決する必要があります。
ルータが間に挟まっている場合は、PCがグローバルIPアドレスを調べるためには外部サーバで調べるしか有りません。
その外部サーバは自分で用意するか、公開されているサーバを利用条件の許される範囲内で利用する必要があります。

出来れば、サーバーとクライアントのマッチングをする公開マッチングサーバーを用意したほうがいろんな人に遊んでもらうには良いと思います。
マッチング後は、各々のサーバーとクライアント間で通信してもらいます。
そういう仕組にしないと、お互いにメールアドレスを知る知人同士でしか使えないと思いますよ。

それとUPnPのコードですが、私もUPnPはやったことはないですが、このCOMコードは難しくないのでよく分からなくても試してみてはどうでしょうか?
char *ip = "192.168.xxx.xxx"; <- 自分のPCのローカルIPアドレス
BSTR description = SysAllocString( L"????" ); <- ここはポートマッピングに登録する名前。適当で良いと思います。
int port = xxxx; <- 開放するポート番号
を入力するだけで動くと思います。
レンタルサーバーで掲示板を運営したりしているので
そこにソケットで接続してIPを取得するというやり方がいいかな?と考えました。
どうでしょうか?

このコードVC++2010でも使えるのでしょうか?
エラーばかり出てどこを直したらいいのかわからなくて困っています。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: UPnPでポート開放

#6

投稿記事 by softya(ソフト屋) » 14年前

みなみ さんが書きました:レンタルサーバーで掲示板を運営したりしているので
そこにソケットで接続してIPを取得するというやり方がいいかな?と考えました。
どうでしょうか?
オリジナルのCGIが使えるなら問題ないと思います。
みなみ さんが書きました:このコードVC++2010でも使えるのでしょうか?
エラーばかり出てどこを直したらいいのかわからなくて困っています。
とりあえず、ヘッダがなかったので加えたのとこちらの都合の良いアドレスなどが埋めこんであります。
動作テストしましたが、UPnPはうまく動いたようです。

「UPnPCJ」 ← 動作確認ツール。UPnPツールなわけですが。
http://www.geocities.jp/umemasu2010/upnpcj/
インストール版で出来る"UPnPCJ (手動開放)"で起動して、⑬PortMapで確認。

コード:

#include <windows.h>
#include <Natupnp.h>

int main()
{
	// まずCOMの初期化
	::CoInitialize( NULL );

	// インスタンス取得
	IUPnPNAT *nat;
	::CoCreateInstance( CLSID_UPnPNAT, NULL, CLSCTX_ALL, IID_IUPnPNAT, (void **)&nat );

	// ポートマッピングのリスト取得
	IStaticPortMappingCollection *maps = NULL;
	nat->get_StaticPortMappingCollection( &maps );

	// アドレスと名前を登録できる形式に変更
	char *ip = "192.168.1.17"; //<- 自分のIPアドレス
	WCHAR localIPWideString[ 16 ];
	MultiByteToWideChar( CP_ACP, 0, ip, -1, localIPWideString, 16 );
	BSTR localIPBstr = SysAllocString( localIPWideString );
	BSTR proto = SysAllocString( L"TCP" ); //<- TCP/IPで登録する
	BSTR description = SysAllocString( L"UPNPXXX" ); //<- ここはポートマッピングに登録する名前

	// ポートマッピング
	int port = 19191; //<- 開放するポート番号
	IStaticPortMapping *map;
	maps->Add( port, proto, port, localIPBstr, VARIANT_TRUE, description, &map );

	// BSTR の解放
	SysFreeString( description );
	SysFreeString( proto );
	SysFreeString( localIPBstr );

	// オブジェクト解放
	map->Release();
	maps->Release();
	nat->Release();

	// COMの終了
	::CoUninitialize();

}
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

Mr.D

Re: UPnPでポート開放

#7

投稿記事 by Mr.D » 14年前

横から失礼いたします。
当方も先日までUPnPでのポート開放に
躓いていたのですが何とか形にできました。

が、次はP2P?部となる通信部分をどのようにすればよいのか
色々と試してみてはいるのですが通信ができません。

現状できているのは、ポートマッピングとそれに伴う
双方(2台)のPCのグローバルIPアドレス、サブネット、ローカルIPアドレス(各種ポート)
一通り、通信に必要そうな物は取得(設定)できているのですが
winsock2で単純に
SockAddr.sin_port = htons(port);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
※上記port、addressは取りあえずです。
とお決まりの形ではだめのようで・・・。
どなたか助言可能であれば御助けください。

※開発環境は、Windows7 VC++2008(2010)Express

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: UPnPでポート開放

#8

投稿記事 by softya(ソフト屋) » 14年前

Mr.D さんが書きました:横から失礼いたします。
当方も先日までUPnPでのポート開放に
躓いていたのですが何とか形にできました。

が、次はP2P?部となる通信部分をどのようにすればよいのか
色々と試してみてはいるのですが通信ができません。

現状できているのは、ポートマッピングとそれに伴う
双方(2台)のPCのグローバルIPアドレス、サブネット、ローカルIPアドレス(各種ポート)
一通り、通信に必要そうな物は取得(設定)できているのですが
winsock2で単純に
SockAddr.sin_port = htons(port);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
※上記port、addressは取りあえずです。
とお決まりの形ではだめのようで・・・。
どなたか助言可能であれば御助けください。

※開発環境は、Windows7 VC++2008(2010)Express
別のトピックにされた方が良いかと思います。
その時に、どうだめなのかの詳細や考えているP2Pのアルゴリズムの解説と出来ればコードをお貼りください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

みなみ

Re: UPnPでポート開放

#9

投稿記事 by みなみ » 14年前

softya(ソフト屋) さんが書きました:
みなみ さんが書きました:レンタルサーバーで掲示板を運営したりしているので
そこにソケットで接続してIPを取得するというやり方がいいかな?と考えました。
どうでしょうか?
オリジナルのCGIが使えるなら問題ないと思います。
みなみ さんが書きました:このコードVC++2010でも使えるのでしょうか?
エラーばかり出てどこを直したらいいのかわからなくて困っています。
とりあえず、ヘッダがなかったので加えたのとこちらの都合の良いアドレスなどが埋めこんであります。
動作テストしましたが、UPnPはうまく動いたようです。

「UPnPCJ」 ← 動作確認ツール。UPnPツールなわけですが。
http://www.geocities.jp/umemasu2010/upnpcj/
インストール版で出来る"UPnPCJ (手動開放)"で起動して、⑬PortMapで確認。

コード:

#include <windows.h>
#include <Natupnp.h>

int main()
{
	// まずCOMの初期化
	::CoInitialize( NULL );

	// インスタンス取得
	IUPnPNAT *nat;
	::CoCreateInstance( CLSID_UPnPNAT, NULL, CLSCTX_ALL, IID_IUPnPNAT, (void **)&nat );

	// ポートマッピングのリスト取得
	IStaticPortMappingCollection *maps = NULL;
	nat->get_StaticPortMappingCollection( &maps );

	// アドレスと名前を登録できる形式に変更
	char *ip = "192.168.1.17"; //<- 自分のIPアドレス
	WCHAR localIPWideString[ 16 ];
	MultiByteToWideChar( CP_ACP, 0, ip, -1, localIPWideString, 16 );
	BSTR localIPBstr = SysAllocString( localIPWideString );
	BSTR proto = SysAllocString( L"TCP" ); //<- TCP/IPで登録する
	BSTR description = SysAllocString( L"UPNPXXX" ); //<- ここはポートマッピングに登録する名前

	// ポートマッピング
	int port = 19191; //<- 開放するポート番号
	IStaticPortMapping *map;
	maps->Add( port, proto, port, localIPBstr, VARIANT_TRUE, description, &map );

	// BSTR の解放
	SysFreeString( description );
	SysFreeString( proto );
	SysFreeString( localIPBstr );

	// オブジェクト解放
	map->Release();
	maps->Release();
	nat->Release();

	// COMの終了
	::CoUninitialize();

}
わざわざコード書いていただきありがとうございます。

コード:

#include <windows.h>
#include <Natupnp.h>
#include <objbase.h>
#include <oleauto.h>

#pragma comment(lib,"ole32.lib")
#pragma comment(lib,"oleaut32.lib")

int main()
{
    // まずCOMの初期化
    ::CoInitialize( NULL );
 
    // インスタンス取得
    IUPnPNAT *nat;
    ::CoCreateInstance( CLSID_UPnPNAT, NULL, CLSCTX_ALL, IID_IUPnPNAT, (void **)&nat );
 
    // ポートマッピングのリスト取得
    IStaticPortMappingCollection *maps = NULL;
    nat->get_StaticPortMappingCollection( &maps );
 
    // アドレスと名前を登録できる形式に変更
    char *ip = "192.168.11.2"; //<- 自分のIPアドレス
    WCHAR localIPWideString[ 16 ];
    MultiByteToWideChar( CP_ACP, 0, ip, -1, localIPWideString, 16 );
    BSTR localIPBstr = SysAllocString( localIPWideString );
    BSTR proto = SysAllocString( L"TCP" ); //<- TCP/IPで登録する
    BSTR description = SysAllocString( L"TOOL" ); //<- ここはポートマッピングに登録する名前
 
    // ポートマッピング
    int port = 57630; //<- 開放するポート番号
    IStaticPortMapping *map;
    maps->Add( port, proto, port, localIPBstr, VARIANT_TRUE, description, &map );
 
    // BSTR の解放
    SysFreeString( description );
    SysFreeString( proto );
    SysFreeString( localIPBstr );
 
    // オブジェクト解放
    map->Release();
    maps->Release();
    nat->Release();
 
    // COMの終了
    ::CoUninitialize();
 
}
このようにしてコンパイルは通ったのですが
実行ファイルを起動してもポートの開放がされません。
ipconfigで自分のIPアドレスは確認しました。
ルーターの設定でUPnPは許可にしています。

どこがおかしいのでしょうか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: UPnPでポート開放

#10

投稿記事 by softya(ソフト屋) » 14年前

みなみ さんが書きました:このようにしてコンパイルは通ったのですが
実行ファイルを起動してもポートの開放がされません。
ipconfigで自分のIPアドレスは確認しました。
ルーターの設定でUPnPは許可にしています。
どの様にしてポートの開放を確認されたのでしょうか?
それとTCP/UDPのプロトコルはあっていますか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

みなみ

Re: UPnPでポート開放

#11

投稿記事 by みなみ » 14年前

softya(ソフト屋) さんが書きました:
みなみ さんが書きました:このようにしてコンパイルは通ったのですが
実行ファイルを起動してもポートの開放がされません。
ipconfigで自分のIPアドレスは確認しました。
ルーターの設定でUPnPは許可にしています。
どの様にしてポートの開放を確認されたのでしょうか?
それとTCP/UDPのプロトコルはあっていますか?
ルーターにアクセスして確認しました。

TCP/UDPのプロトコルがあっているかどうかとは
どういう意味でしょうか?

http://gyazo.com/3814e4ed8fe797207c8037f329e0a370.png
これがルーターにアクセスしたときの画像なのですが、
手動でポートを開放すると
「ポート変換登録情報」というところに開放されているポートが書かれているのですが
今回のアプリを実行したところ、ここに登録されることはなかったです。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: UPnPでポート開放

#12

投稿記事 by softya(ソフト屋) » 14年前

みなみ さんが書きました:ルーターにアクセスして確認しました。
ルータでは確認できないみたいなので、UPnPCと言うツールをご紹介しました。
つまり、ルータには登録されません(恒久な登録情報ではないためです)
みなみ さんが書きました:TCP/UDPのプロトコルがあっているかどうかとは
どういう意味でしょうか?
UPnPのコードですがTCPで通信するポートを開けています。
もし、通信でUDPを使っていたらポートが空いていない状態です。
なので、TCP/UDPのどちらの通信を使われているかお聞きしました。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

Mr.D

Re: UPnPでポート開放

#13

投稿記事 by Mr.D » 14年前

横から失礼します。
何から何まで 同じ境遇で少し怖いのですが...
上記のソースの場合だと、
現状登録されているポート周りの判定等々が無い等の問題点が幾つか挙げられます。
※当方は、違う方法で行っているためその点も考慮して作っております。
あと上記のソースに追記で、「maps->Remove(port, proto);」を追加して閉鎖もおすすめ致します。
もう一つ、ルーターのTOP画面に「ユーティリティー機能」という文言と一緒に
「ネットワークサービスの一覧を表示」というボタンがあると思います。
そちらを押して頂くと、上記ソースを起動後であれば
|パソコン名    |IPアドレス |サービス |
|名称不明      |192.168.***.***|□□     |
|(**:**:**:**:**:**) |          |      |
の自分のローカルIPアドレスの右側に ファミコンのコントローラーみたいなアイコンが追加されます。
そのコントローラーが出ているIPに対しては、ポートマッピング成功です。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: UPnPでポート開放

#14

投稿記事 by softya(ソフト屋) » 14年前

Mr.D さんが書きました:横から失礼します。
何から何まで 同じ境遇で少し怖いのですが...
上記のソースの場合だと、
現状登録されているポート周りの判定等々が無い等の問題点が幾つか挙げられます。
※当方は、違う方法で行っているためその点も考慮して作っております。
あと上記のソースに追記で、「maps->Remove(port, proto);」を追加して閉鎖もおすすめ致します。
もう一つ、ルーターのTOP画面に「ユーティリティー機能」という文言と一緒に
「ネットワークサービスの一覧を表示」というボタンがあると思います。
そちらを押して頂くと、上記ソースを起動後であれば
|パソコン名    |IPアドレス |サービス |
|名称不明      |192.168.***.***|□□     |
|(**:**:**:**:**:**) |          |      |
の自分のローカルIPアドレスの右側に ファミコンのコントローラーみたいなアイコンが追加されます。
そのコントローラーが出ているIPに対しては、ポートマッピング成功です。
ポート判定は確かに無いですね。
それと今のコードはmaps->Remove(port, proto);を入れてしまうと単なる接続・閉鎖するだけのプログラムになってしまいますので、実際のプログラムに入れ込むときに必要なことだけを理解してください。UPnPと実際のプログラムを一体化させると思いますので。

それと家のBBR-4HGは「ネットワークサービスの一覧を表示」は古いのでないんですよね。ファームは最新なんですが。
最近のは便利なのが付いてますね。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

閉鎖

“C言語何でも質問掲示板” へ戻る