送信元ポートはどのように決定され、特定のポートを使用するように強制するにはどうすればよいですか


26

https://www.google.co.ukに接続すると、これは216.58.198.228:443に変わります。次に、[私のIPアドレス]:63998で私への接続が開きます。

私の質問は、63998ポートがどのように選択されるかであり、63999に強制する方法があります。


9
強制的に63999にする方法はありますか?これを実行しようとする理由はありますか?
-AL

1
アプリケーションを記述している場合は、必要な(未使用の)ソースポートを開くことができます。しかし、それは良い考えではなく、なぜあなたがこれを望むのか明確ではありませんか?
pjc50

6
@ pjc50実際、この質問はXYの問題を抱えているようです。
開発

1
宛先ポート番号は宛先マシンに対して「ローカル」であるため、タイトルを「ローカル」ではなく「ソース」に変更するために編集を送信しましたが、最初のTCP SYNパケットのソースは、接続
モンティハーダー

回答:


39

ローカルポートの決定方法

ポート番号は、Ephemeral Portsと呼ばれるポート番号の範囲からTCP実装ソフトウェアによって選択されます。

使用するポート番号と範囲を選択する正確なメカニズムは、オペレーティングシステムに依存します。


63999に強制する方法はありますか。

これは、TCP実装ソフトウェアの構成を変更することで実行できます。

さまざまなオペレーティングシステム用にエフェメラルポート範囲を構成する手順については、「エフェメラルポート範囲の変更」を参照してください

  • LinuxおよびWindowsの手順は、参照用のこの回答に含まれています。

ただし、範囲を1つのポートに制限することはお勧めできません(例:)63999

  • 実際、Windowsではこれは次のように不可能です。

    設定できるポートの最小範囲は255です。


エフェメラルポート範囲

TCP / IPv4接続は2つのエンドポイントで構成され、各エンドポイントはIPアドレスとポート番号で構成されます。したがって、クライアントユーザーがサーバーコンピューターに接続するとき、確立された接続は、4つのタプル(サーバーIP、サーバーポート、クライアントIP、クライアントポート)と考えることができます。

通常、4つのうち3つは既知です。クライアントマシンは独自のIPアドレスを使用し、リモートサービスに接続する場合、サーバーマシンのIPアドレスとサービスポート番号が必要です。

すぐには明らかにならないのは、接続が確立されると、接続のクライアント側がポート番号を使用することです。クライアントプログラムが特定のポート番号を明示的に要求しない限り、使用されるポート番号は一時的なポート番号です。

エフェメラルポートは、マシンのIPスタックによって割り当てられた一時的なポートであり、この目的のために指定されたポート範囲から割り当てられます。接続が終了すると、一時ポートは再利用できますが、ほとんどのIPスタックは、一時ポートのプール全体が使用されるまでそのポート番号を再利用しません。

そのため、クライアントプログラムが再接続すると、新しい接続の側に別の一時ポート番号が割り当てられます。

エフェメラルポート範囲のソース


エフェメラルポート範囲の変更

Linux:

Linuxでは、ファイルを使用するだけで一時的なポート範囲を表示および変更できます/proc/sys/net/ipv4/ip_local_port_range。たとえば、これはカーネル2.2システムのデフォルト設定を示しています。

$ cat /proc/sys/net/ipv4/ip_local_port_range 
1024 4999

これを優先範囲に変更するには、次のようにします(スーパーユーザーとして):

# echo "49152 65535" > /proc/sys/net/ipv4/ip_local_port_range 

システムを起動するたびにこれを行う必要がある/etc/rc.local ため、範囲が常に使用されるように、システム起動スクリプトに必ず行を追加してください。

また、適切なカーネルメモリが使用可能な場合、Linux 2.4カーネルはデフォルトで32768〜61000の範囲を使用するため、新しいLinuxシステムでは範囲を変更する必要はありません。

最後に、ファイルシステムsysctlを使用するのではなく、インターフェイスを使用して設定を変更できる場合もあることに注意してください/procsysctlパラメーターの名前は「net.ipv4.ip_local_port_range」です。/etc/sysctl.confファイルがある場合は編集するか、sysctlを使用してこのパラメーターを変更する場合は、スタートアップスクリプトにコマンドを手動で実行させますsysctl

Windows Vista / Windows Server 2008以降:

Windows VistaおよびWindows Server 2008では、Microsoft Knowledgebase Article 929851に従って、Windowsはデフォルトで広い範囲(49152-65535)を使用するようになりました。同じ記事では、必要に応じて範囲を変更する方法も示していますが、ほとんどのサーバーではデフォルトの範囲で十分です。

エフェメラルポート範囲を変更するソース

次のnetshコマンドを使用して、Windows VistaまたはWindows Server 2008コンピューターを実行しているコンピューターの動的ポート範囲を表示でき ます。

netsh int ipv4 show dynamicport tcp
netsh int ipv4 show dynamicport udp
netsh int ipv6 show dynamicport tcp
netsh int ipv6 show dynamicport udp 

ノート:

  • 範囲は、各トランスポートおよびIPの各バージョンに対して個別に設定されます。
  • これで、ポート範囲は本当に開始点と終了点を持つ範囲になりました。
  • Windows Server 2008を実行しているサーバーを展開するMicrosoftのお客様は、内部ネットワークでファイアウォールが使用されている場合、サーバー間のRPC通信で問題が発生する場合があります。
  • このような場合は、ファイアウォールを再構成して、動的ポート範囲が49152 〜のサーバー間のトラフィックを許可することをお勧めします65535
  • この範囲は、サービスおよびアプリケーションで使用される既知のポートに追加されます。
  • または、サーバーが使用するポート範囲を各サーバーで変更できます。

netsh次のコマンドを使用して、この範囲を調整します。

netsh int <ipv4|ipv6> set dynamic <tcp|udp> start=number num=range

このコマンドは、TCPの動的ポート範囲を設定します。開始ポートは数値であり、ポートの総数は範囲です。以下はサンプルコマンドです。

netsh int ipv4 set dynamicport tcp start=10000 num=1000
netsh int ipv4 set dynamicport udp start=10000 num=1000
netsh int ipv6 set dynamicport tcp start=10000 num=1000
netsh int ipv6 set dynamicport udp start=10000 num=1000

これらのサンプルコマンドは、動的ポート範囲をポート10000で始まり、ポート10999(1000ポート)で終わるように設定します。

ノート:

  • 設定できるポートの最小範囲は255です。
  • 設定できる最小の開始ポートは1025です。
  • (設定されている範囲に基づく)最大エンドポートはを超えることはできません65535
  • Windows Server 2003の既定の動作を複製するには1025、開始ポート3976として使用し、TCPとUDPの両方の範囲として使用します。これにより、開始ポート1025と終了ポートがになり5000ます。

ソースMicrosoftナレッジベースの記事929851

Windows XP以前:

古いWindowsオペレーティングシステム(Windows XPおよびそれ以前)の場合、Windowsは一時ポート範囲に1024から4999の従来のBSD範囲を使用します。残念ながら、一時ポート範囲の上限しか設定できないようです。以下は、Microsoft Knowledgebase Article 196271から抜粋した情報です。

  • レジストリエディター(Regedt32.exe)を起動します。
  • レジストリで次のキーを見つけます。

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

  • [編集]メニューで[値の追加]をクリックし、次のレジストリ値を追加します。

    値の名前:MaxUserPortデータ型:REG_DWORD値:(65534例)

    有効範囲:5000-65534(10進数)デフォルト:0x1388(10進数5000)

    説明:このパラメーターは、アプリケーションがシステムに使用可能なユーザーポートを要求するときに使用される最大ポート番号を制御します。通常は、(、短命である)エフェメラルポートは、の値の間に割り当てられる10245000包括。

  • レジストリエディターを終了します。

注意:他の関連するKB記事(あり812873主張はあなたがポートを除外することができることを意味する可能性が除外範囲、設定することを可能にする)1024-9999一時的なポートが可能レンジ持っている(たとえば)が10000-65534。ただし、これを機能させることはできませんでした(2004年10月現在)。

エフェメラルポート範囲を変更するソース


1
少なくともWindowsの場合、システム全体でポート範囲を制限できるようです。ほとんどの場合、これは特に、1つのポートにそれを制限する、おそらく悪いアイデアで、次のようになります参照してくださいKB 929851、Windows 7の上の少なくとも仕事で記載されているコマンド
セス・

@Sethはい。私は彼のOSについては言及しなかったOPので、これを言及するには消極的だったと私はNのオペレーティングシステムをカバーするための答えを拡大したくなかった...
DavidPostill

あなたはそれについて正しいです。結局のところ、たくさんのオペレーティングシステムがあります。もともとこの質問に答えようとしていたときに偶然出会ったものです。あなたの答えが速くなったので、私はそれを追加すると思いました。それは本当によく書かれた答えです!:)プログラミングを再プログラミングするよりも、構成を変更するだけで十分な場合があるというヒントとして追加しただけです(多分、私の理解はまったく異なる-私にとっては再コンパイルに似ているように聞こえます)。
セス

1
実際、Linuxでも非常に簡単です。"49152 65535"> / proc / sys / net / ipv4 / ip_local_port_rangeをエコーするだけですコマンドごとに実行できるほど単純です。
MariusMatutiae

2
はかないポート範囲を変更するよりも、bind呼び出す前にアプリケーションがシステムコールを呼び出す方がずっと良いでしょうconnect。一部のアプリケーションにはオプションがありますが、他のアプリケーションにはありません。
カスペルド

9

David Postillの答えは完全に正しいです。Linuxでの一時ポート範囲の変更は非常に簡単であり、OPが肯定的な答えを持っていることを強調することで、それに追加したいと思います。

EPRを次のように変更します。

echo "40000 60000" > /proc/sys/net/ipv4/ip_local_port_range 

また、次のスクリプトを使用して、ポート50000(例として)を選択できます。

OLD_RANGE=$(cat /proc/sys/net/ipv4/ip_local_port_range)
MY_PORT=50000
echo "$MY_PORT $MY_PORT" > /proc/sys/net/ipv4/ip_local_port_range
sudo -u SomeUser SomeApplication  & 
echo $OLD_RANGE" > /proc/sys/net/ipv4/ip_local_port_range 

ここで注意点が1つあります。範囲内にポートが1つしかないため、別のアプリケーションが上記の3行目と4行目の実行の間にそれを奪う可能性があります。また、競合状態がなくても、大きなEPRを復元するまで他のすべてのアプリケーションを麻痺させます。そのため、できるだけ早く元の範囲を復元しました。

したがって、場合のOPのオペレーティングシステムがLinuxをしていた、その答えは、それが簡単に行うことができるということだったでしょう。

驚くべきことに、これはBSDではそれほど単純ではなく、そのいくつかはEPRの実行時カーネル設定さえもしていません。MacOS X、FreeBSD、およびOpenBSDでは、ファイル/etc/sysctl.confを変更する必要がありますが、EPRには異なる選択肢があります。

かかわらず、上記とOSのの、何かがあるという事実ができて行うことは、それが意味するものではありませんべき行われるように:なぜ地球上であなたはこれが必要なのですか?単一のユースケースを考えることはできません。


Linuxの例+1。
DavidPostill

へへ。BSD / OSではカーネルの再コンパイルが必要です:)
DavidPostill

1
@DavidPostillそれは大きな残念です。
MariusMatutiae

コード例に欠陥があります。あなたの型キャストは非常に見当違いです。さらにBIND_PORT、コードを元のコードとまったく同じように使用できるように、オプションにすることをお勧めします。私htons(bind_port_env ? atoi(bind_port_env) : 0)は正しいことをすると思います。
カスペルド

1

Linuxカーネルも持っていることを追加する価値があります

net.ipv4.ip_local_reserved_ports

少し反対のノブですが、それでも非常に便利な場合があります。そうすると、そうでなければ一時的なポート範囲で特定のポートを開くサービスに「穴を開ける」ことができるからです。

ドキュメントからの短い抜粋:

既知のサードパーティアプリケーション用に予約されているポートを指定します。これらのポートは、自動ポート割り当てでは使用されません(たとえば、ポート番号0でconnect()またはbind()を呼び出す場合)。明示的なポート割り当て動作は変更されていません。

入力と出力の両方に使用される形式は、コンマで区切られた範囲のリストです(ポート1、2、3、4、および10の場合は「1,2-4,10-10」など)。ファイルに書き込むと、以前に予約されたすべてのポートがクリアされ、現在のリストが入力で指定されたもので更新されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.