私が理解しているように、これはクライアントが接続要求を行ったときに何が起こるかです:
connect()
リクエストを送信します。accept()
を使用してリクエストを受け入れます。サーバーがクライアント要求を受け入れるとすぐに、カーネルはサーバーにランダムなポート番号を割り当て、さらにsend()
およびreceive()
を割り当てます。サーバー上の同じポート番号は送信とリッスンに使用され、以前のポートはまだ新しい接続をリッスンしていますこれらすべてを考慮して、サーバーはどのようにしてクライアントが受信しているポートを見つけますか?クライアントがTCPセグメントを送信元ポートと宛先ポートで送信することを知っているので、サーバーはそのセグメントの送信元ポートを宛先ポートとして使用しますが、どの関数がサーバーを呼び出して検索しますかそのポートについてアウト?それはaccept()
ですか?
パケットのTCP(またはUDPなど)ヘッダーの一部です。したがって、サーバーは、クライアントが指示するのでそれを検出します。これは、クライアントのIPアドレス(IPヘッダーの一部)を見つける方法に似ています。
たとえば、すべてのTCPパケットには、IPヘッダーが含まれています(少なくとも送信元IP、宛先IP、およびプロトコル[TCP])。次に、TCPヘッダーがあります(送信元ポートと宛先ポートに加えて)。
カーネルがSYNパケット(TCP接続の開始)を受信し、リモートIPが10.11.12.13(IPヘッダー内)およびリモートポートが12345(TCP内)の場合_ヘッダー)。リモートIPとポートを認識します。 SYN | ACKを返信します。 ACKが返された場合、listen
呼び出しは、その接続用に設定された新しいソケットを返します。
TCPソケットは、4つの値(リモートIP、ローカルIP、リモートポート、ローカルポート)によって一意に識別されます。それらの少なくとも1つが異なる限り、複数の接続/ソケットを持つことができます。
通常、ローカルポートとローカルIPは、サーバープロセスへのすべての接続で同じです(たとえば、sshdへのすべての接続はlocal-ip:22になります)。 1つのリモートマシンが複数の接続を行う場合、それぞれが異なるリモートポートを使用します。したがって、リモートポート以外はすべて同じになりますが、それは問題ありません。4つのうち1つだけが異なっていれば十分です。
Wirehsarkなどを使用してパケットを表示すると、すべてのデータにラベルが付けられます。これが強調表示された送信元ポートです(デコードされたパケットで強調表示されていること、および下部の16進ダンプに注意してください)。
「接続要求(通常、クライアントプログラムのconnect()
システムコール)によって ウェイハンドシェイク が発生します。(クライアントからサーバーへの)3ウェイハンドシェイクの最初のパケットはSYNフラグセット。クライアントプログラムのカーネルが割り当てたTCPポート番号が含まれます。
これは NmapとNatural SYNパケットに関する記事 で確認できます。 Nmap SYNパケットのデコードには、「source.60058> dest.22」というフレーズがあります。 「正当なSYNパケット」のデコードには、「source.35970> dest.80」というフレーズが含まれています。 2つのSYNパケットは、パケットがTCPポート60058およびポート35970からそれぞれであることをリモートカーネルに通知します。
TCPソケットはストリーム指向のソケットです。 2つのソケット記述子(ユーザーとピアが所有)は確実に接続されています。したがって、クライアントのポートを気にする必要はありません。ソケット記述子を記述するだけです。
また、本当にログを知りたい場合は、getsockname(2)を使用してください(おそらくロギング用)。
接続はタプル(ソースIP、ソースポート、宛先IP、宛先ポート)によって定義されます。答えは逆になります。