1

TUNTAP を使用して Python トンネリング プロジェクトに取り組んでいます。TUNTAP インターフェイスで受信したデータには、すべてのヘッダーを含む元の IP パケットが含まれています。私は2つのうちの1つを行うことができます。

受信側は Twisted で聞いています。発信側には、IP パケットをダンプする raw ソケットがあります。パケットをダンプする前に、プログラムは送信元アドレスをサーバーのアドレスと交換します。また、TCP および UDP チェックサムを再計算します。また、次のいずれかの方法を使用してポートをスワップします。この情報は NAT テーブルで追跡されます

1) 次のように、ユーザーごとに 1 つのポートを使用します。

 US.ER.01.IP:10000 ----> SE.RV.ER.IP:3000 ----> facebook.com:80
 US.ER.01.IP:10001 ----> SE.RV.ER.IP:3000 ----> facebook.com:80
 US.ER.02.IP:3000 ----> SE.RV.ER.IP:3001 ----> facebook.com:80

2 番目のユーザーが 1 秒で facebook を同時に要求した場合、これは問題を引き起こす可能性がありますか? システムは、Facebook の返信をどのようにルーティングするかをどのように知るのでしょうか。ポート 3000 で着信しているため、user1 に属していますが、10000 または 10001 にマップされますか?

2) 次のような接続ごとに一意のポートを使用します。

 US.ER.01.IP:10000 ----> SE.RV.ER.IP:3000 ----> facebook.com:80
 US.ER.01.IP:10001 ----> SE.RV.ER.IP:3001 ----> facebook.com:80
 US.ER.02.IP:3000 ----> SE.RV.ER.IP:3002 ----> remoteHost.com:22

NAT テーブルからエントリを削除するタイミングを知るにはどうすればよいですか? この方法を使用すると、NAT テーブルがすぐにいっぱいになることがわかりました。これに対する解決策は次のとおりです。

  I could wit for FIN packets from the server.  This will not work with UDP though.
  I could age the NAT entry on each hit.  I could then run garbage collection 
     every N seconds.  I see this being an issue if garbage collection runs
     and how would a server's delayed response get to the proper host if it gets
     deleted from the table.

raw ソケットからの読み取りの問題もあります。送信方法は知っていますが、個々の IP パケットを受信することは可能でしょうか。raw ソケットは、sock.recieve(65535) 呼び出しごとに 1 つのパケットを受信し、複数の IP パケットを受信する可能性がありますか?

どの実装が最適ですか? 他に気をつけるべきヒントやことはありますか?

編集:

わかりましたので、N個のクライアントがいます。誤解されている場合は、enitre /30 がクライアントとそれ自体の間で使用されます。トンネルを可能にするのは単なる抽象化です。私もそれが問題だとは思いませんでしたが、websocket は実際には LAN 上の「プロキシ」を通過します (IPdata は単純に新しい websocket に再パッケージ化されますが、マッピングは一意です)。説明をそれほど混乱させたくありませんでした。これがどのように変化するかわかりません。

      Client PC     CLIENT PC              Client PC----->LAN                               INTERNET    
 Client 1: 10.1.1.2 ----> 10.1.1.1 ----> Websocket(IPdata) ----> Browser ---> newWebSocket(IPData) ----> SE.RV.ER.IP
 Client 2: 10.1.1.4 ----> 10.1.1.3 ----> Websocket(IPdata) ----> Browser ---> newWebSocket(IPData) ----> SE.RV.ER.IP
 Client 3: 10.1.1.6 ----> 10.1.1.5 ----> Websocket(IPdata) ----> Browser ---> newWebSocket(IPData) ----> SE.RV.ER.IP

各クライアントは、そのデフォルト ルートをトンネル エンドポイント (たとえば 10.1.1.1) に設定します。クライアントは IP データグラムを取得し、それを Websocket に入れ、その Websocket を LAN 上のブラウザーに送信します。次に、LAN はそれをサーバー (またはおそらく別のプロキシ) に送信します。Websocket の内部には、元の IP データグラムが含まれています (ソースは 10.1.1.2 またはその他の内部 IP です)。

サーバーはインターネットから Websocket メッセージを受信することに注意してください。Pythonサーバーはこれをどのように使用しますか? それ自体で新しいトンネルを作成し、パケットをそのままトンネルにダンプし、適切にルーティングしますか?

それとも、マッピングを使用できますか?

この websocket チェーンを介してトンネル抽象化を「マップ」するにはどうすればよいでしょうか? クライアントにはインターネットへのルートはありませんが、インターネットにアクセスできる「ブラウザ」に到達できます。これは、VPN トンネルの場合と同じようです。抽象化は次のようになります。

 Client 1: 10.1.1.2 ----> 10.1.1.1 ----> Websocket(IPdata) ----> Browser ---> newWebSocket(IPData) ----> SE.RV.ER.IP -> Internet
           10.1.2.2------------------------------------------------------------------------------------> 10.1.2.1 ----> Internet

私を正しい軌道に乗せるためのリソースを知っていれば、それは素晴らしいことです!

4

1 に答える 1

5

NAT の実装

質問で概説した理由とまったく同じように、ユーザーごとに単一のポートではなく、接続ごとに一意のポートを使用する必要があります。 -tuple (protocol,local-address,local-port,remote-address,remote-port) であり、それらを明確にすることはできません。

さらに、NAT トラバーサルを行ういくつかのプロトコルと仲良くしたい場合は、可能であれば元の送信元ポートを再マップしないようにする必要があります。つまり、既存の接続と競合する場合にのみ (新しいランダム ポートに) 再マップする必要があります。あなたは追跡しています。

NAT を正しく実装するには、各接続の状態を追跡する必要があります。

TCP の場合、これはフラグを監視し、 a が表示されたときに新しい状態を設定し、両側から sSYNが表示されたときに状態を破棄することを意味します。FIN追跡する状態には、少なくとも元の送信元ポートと再マップされた送信元ポート (同じである可能性があります。上記を参照) が含まれている必要があります。FTP をサポートしたい場合は、FTP TCP 制御接続の内容を盗聴し、そこに含まれる IP アドレスを書き換える必要があります (これは、より多くの状態を追跡する必要があることを意味します。シーケンス番号の再マッピングを開始する必要があることを意味します)。また、接続を適切に閉じずにエンドポイントが消えた場合に備えて、追跡された接続ごとにタイムアウトを関連付ける必要があります。

UDP の場合、これは、ローカルとリモートのポート番号の組み合わせを監視し、表示される一意の組み合わせ (アドレスとポートの 4 つのタプル) ごとに状態を作成することを意味します。UDP はコネクションレスであるため、タイムアウトに基づいてこの状態情報を期限切れにする必要があります。このタイムアウトは、状態テーブルが大きくなりすぎないようにするために、TCP に使用するタイムアウトよりもはるかに短くなります (数時間ではなく数分単位)。

ICMP エコー リクエストの場合、ポート番号の役割を果たす icmp_id を使用して、UDP と同様の方法で処理を進める必要があります。

到達不能な宛先のような他のタイプの ICMP の場合は、ICMP パケットを検査して、追跡している TCP または UDP 接続の一部であるかどうかを確認し、元の送信元に変換して戻す必要があります。

ルーティング ループを防ぐために、変換されたパケットを転送するときに IP TTL を減らす必要もあります。

おそらく、私が忘れているもっと重要なビットがいくつかあります。つまり、NAT の実装は、ルーターの IP スタックの実装によく似ています。そのため、NAT は常にカーネルの IP スタックに固定されており、ユーザー空間には実装されていません。

パケットの送受信

したがって、私が理解しているアーキテクチャは次のとおりです。

  1. クライアントは、TUNTAP インターフェイスに入るパケットを発信します
  2. ソフトウェアはこのパケットを取得し、Websocket メッセージにカプセル化して送信します
  3. Twisted サーバーがそれを取得し、その魔法を実行します
  4. 変換されたパケットは、生のソケットを介してサーバーから送信されます

帰り道:

  1. 返信は何らかの形でサーバーに返されます (おそらくlibpcap )
  2. あなたのコードは逆の魔法を行います
  3. サーバーは結果を Websocket 経由でクライアントに送り返します
  4. クライアントは、結果のバケットが TUNTAP インターフェースを介して戻ってくるのを確認します。

フォワード パスの最後のステップとリターン パスの最初のステップを処理する最も簡単な方法は、2 番目の TUNTAP デバイス、tunつまりサーバー上のインターフェイスです。

于 2012-11-05T03:40:16.540 に答える