Ephemeralポートとして利用されるポートの範囲を変更する

今日、仕事で調べたらとてもおもしろかったので忘れないうちに記録しておきます。

(要求)Ephemeralポートとして利用されるポートを制限したい

特定のTCPポートで接続を受け付ける自作のサービスアプリケーションを作るときに悩むのが、何番ポートを使うのかということです。
一般的にTCP/UDPで使えるポート番号は1〜65535となっていますが、これらすべてが自由に使っていいというわけではありません。IANAによってポート番号の範囲ごとにその用途は決められているので、それを考慮して利用すべきです。

ポート番号の範囲 呼称 説明
1 〜 1024 Well Known Port IANAが管理しているよく知られたサービスの使うポート
1025 〜 49151 Registered Port IANAが利便性を考慮して公開している登録済みサービスの使用ポート
49152 〜 65535 Ephemeral Port 好きに使っていいポート


上記を見る限りでは49152〜65535が適しているように見えますが、インターネットに公開しない場所ではRegisteredポートもよく使われます。以前イントラ内で限定公開したサービスでは、わたしの誕生日にちなんで5325番を使いました。
ただし注意が必要なのはEphemeralポートというのはその名のとおり一時的な接続に使うためのポートであり、つまりネットワークを経由して外部のサービスへ接続する際のクライアントポートとして利用されるものでもあります。そのため、いざサービスを起動してみたら既に他のセッションで使われていたのでリッスンできなかったなんてこともあるのです。


そんなことにならないように、あらかじめ利用するポートを予約しておいて一時接続のためのポートとしてOSに利用されないようにする方法を以下で紹介します。


(対応方法) OSによって対応方法は異なるのでそれぞれを紹介

Windows 2000 or Windows 2003 Server or Windows XPの場合

Windows 2000, 2003, XPの場合はレジストリに予約したいポートの範囲を記載することで予約可能です。



↑こんな感じでxxxx-yyyyとすれば、xxxxからyyyyまでのポート番号を予約します


詳しくはこちらに記載されています。
Windows 2003とXPは同じ方法(Regedit.exeで編集)ですが、Windows 2000はRegEdt32.exeを使う方法になっています。レジストリファイルを作って実行するだけだったら内容は一緒で大丈夫そうです。

Windows Vista or Windows Server 2008以降の場合(Windows Server 2012R2までは動作確認済み)

Kernelが6以上の環境では2003以前のレジストリを使う方法の代わりにnetshコマンドを使うようになっています。

@netsh int ipv4 set dynamicport tcp start=5000 num=1000


↑これはポート番号を5000から1000個分予約する(つまり6000まで予約)という指定


詳しくはこちらに記載されています。

(おまけ)OSが変わって変更になったのは予約方法だけではないらしい

この確認をする過程でわかったのですが、ポート番号の予約をする方法はOSごとに違うのは見てのとおりですが、Ephemeralポートとして使用できる範囲に設定されているポート番号もOSごとに異なるようなのです。
具体的には2003以前は1025〜5000がEphemeralポートとして利用されていたようですが、Vista以降は49152〜65536が利用されるようです。


Vista以降の環境であれば「netsh int ipv4 show dynamicport tcp」というコマンドで範囲を確認することが可能です。

C:\Users\itotto>netsh int ipv4 show dynamicport tcp

プロトコル tcp の動的ポートの範囲
---------------------------------
開始ポート      : 49152
ポート数        : 16384


C:\Users\itotto>


そういうわけでVista以前にRegisteredポートやEphemeralポートを使って作っていたプログラムがVistaになったら突然動かなくなったという一因にはなりそうな気がします。


(関連リンク)