10

これを使って、socket(PF_INET, SOCK_DGRAM, 0)ソケットの元の宛先IPアドレスを取得できます。

元の宛先ポートを取得するにはどうすればよいですか?

4

2 に答える 2

13

リダイレクトメカニズムに依存します。REDIRECT(内部的にはNAT)を使用している場合は、NATが適用される前に、SO_ORIGINAL_DSTまたはlibnetfilter_conntrackを使用して接続の元の宛先を照会する必要があります。ただし、同じリスナーソケットで複数の接続を提供できるため、このルックアップはすべてのパケットに対して実行する必要があります。

conntrackコマンドラインツールを使用して、libnetfilter_conntrackとそれが提供するサービスを試すことができます。

別の方法は、リダイレクトにTPROXYを使用することです。これは、このような場合に使用することを目的としていました。そこで、recvmsg()を使用した補助メッセージを使用して、パケットの元の宛先を取得できます。探すべき鍵はIP_RECVORIGDSTsetsockoptです。

TPROXYの詳細については、カーネルのドキュメントディレクトリのtproxy.txtというファイルを参照してください。使用するのは少し難しいですが、パケットフィルタリングサブシステムではなく、スタックによって実装されるため、より確実に機能します。

編集: TProxyを使用してUDP宛先アドレスを照会する方法を追加します。

  1. UDPソケットを開き、0.0.0.0またはより具体的なIPにバインドします
  2. setsockopt(fd、SOL_IP、IP_RECVORIGDSTADDR、...)を介してIP_RECVORIGDSTを有効にします
  3. フレームを受信するには、recvfrom()/ recv()の代わりにrecvmsg()を使用します
  4. recvmsg()は、パケットと一連の補助メッセージを返します。
  5. 補助メッセージを繰り返し、レベルSOL_IP、インデックスIP_ORIGDSTADDRのCMSGブロックを見つけます
  6. このCMSGブロックには、IP情報とポート情報の両方を含むstructsockaddr_inが含まれます。

編集済み: SO_ORIGINAL_DSTとudp

SO_ORIGINAL_DSTはudpソケットで機能するはずですが、カーネルでは接続エンドポイントを指定できません。SO_ORIGINAL_DSTを呼び出すソケットを使用して、このアドレス情報を取得します。

これは、UDPソケットが(リダイレクト先のアドレス/ポートに)適切にバインドされ、(問題のクライアントに)接続されている場合にのみ機能することを意味します。リスナーソケットはおそらく0.0.0.0にバインドされており、単一のクライアントだけでなく複数のクライアントにもサービスを提供しています。

ただし、宛先アドレスを照会するために実際のリスナーソケットを使用する必要はありません。UDPは接続の確立時にデータグラムを送信しないため、新しいUDPソケットを作成し、リダイレクトアドレスにバインドして、クライアント(とにかく最初のパケットをリスナーに送信してから知っているアドレス)に接続できます。次に、このソケットを使用してSO_ORIGINAL_DSTを実行できますが、原因は次のとおりです。

  1. このようなソケットを開くと、カーネルは、クライアントがリスナーソケットではなく、最初のソケットの後に追加のパケットを送信する場合に優先します。
  2. アプリケーションがSO_ORIGINAL_DSTを呼び出す機会があるまでに、conntrackエントリがタイムアウトした可能性があるため、これは本質的に際どいものです。
  3. それは遅く、多くのオーバーヘッドがあります

TProxyベースの方法の方が明らかに優れています。

于 2011-04-28T06:39:35.160 に答える
1

解析してみてください/proc/net/nf_conntrack

于 2011-04-11T06:26:52.770 に答える