12

iptablesすべての発信 UDP パケットをローカル ソケットにリダイレクトするルールを作成しようとしていますが、宛先情報も必要です。私はから始めました

sudo iptables -t nat -A sshuttle-12300 -j RETURN   --dest 127.0.0.0/8 -p udp
sudo iptables -t nat -A sshuttle-12300 -j REDIRECT --dest 0.0.0.0/0   -p udp --to-ports 15000

これで、ポート 15000 のソケットを使用して、すべての送信 UDP パケットを取得できるようになりました。

ここで、宛先情報 (ターゲット ホストとポート番号) が必要なので、単純な UDP ソケットでは不十分です。完全な IP ヘッダーを取得するために raw ソケットが必要です。

しかし、結局のところ、受信したパケットはlocalhost:15000. ソケットがある場所なので、これは理にかなっていますが、それは私が望んでいるものではありません。によってパケットがリダイレクトされる前のホスト/ポートが必要ですiptables

グーグルはこの質問につながり、答えは2つのアプローチを示唆していました.TPROXYSO_ORIGINAL_DST、前者を推奨しているので、それを試してみました.

iptablesのルールを追加TPROXY:

sudo iptables -t mangle -A PREROUTING -j TPROXY --dest 0.0.0.0/0 -p udp --on-port 15000

tproxy.txtから読み取ると、オプションを使用してリッスン ソケットを作成する必要がありIP_TRANSPARENTます (これはルートとして実行されます)。

from socket import *
s = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)
# The IP_TRANSPARENT option isn't defined in the socket module.
# Took the value (19) from the patch in http://bugs.python.org/issue12809
s.setsockopt(SOL_IP, 19, 1)
s.bind(('0.0.0.0', 15000))
s.recv(4096) # Will hang until it receives a packet

では、別のスクリプトを作成してテスト パケットを生成し、何かが起こるかどうかを確認してみましょう。

from socket import *
s = socket(AF_INET, SOCK_DGRAM)
s.connect(('192.168.1.1', 9001))
s.send('hello')

しかし、受信側では何も起こりません。recv通話がハングしたようで、データを受信して​​いません。

したがって、全体的な質問は次のいずれかです。

  • TPROXYルールからデータを受け取るコードに何か問題がありますか?

また

  • これを達成する別の方法はありますか (宛先情報を取得する方法で、すべての発信 UDP パケットをローカルソケットにリダイレクトします)?

編集:パケットが通過するときに検査するだけでなく、パケットをリダイレクト(したがって傍受)したいと主張する必要があります。

4

3 に答える 3

10

あなたの質問は興味深いものでした。

次のソリューションは、ホストによって生成された UDP トラフィックをマークし、それをローカル ホスト アプリケーションに再ルーティングすることに基づいています。アプリケーションでは、UDP ソケットを使用してデータを読み取る必要があります。これは、ホスト自体に宛てられていないものであっても同様です (以下の方法を参照してください)。

ネットワーク設定:

  • ホストを出る UDP トラフィックをマークします
  • 1 でマークされたトラフィックは、処理のためにルーティング テーブル 100 に渡されます
  • トラフィックをアプリケーションにルーティングする
iptables -A OUTPUT -t mangle -p udp -j MARK --set-mark 1
ip rule add fwmark 1 lookup 100
ip route add local 0.0.0.0/0 dev lo table 100

ソケット設定:

  • UDP ソケットの作成 (通常)
  • 非ローカル アドレスのバインド/読み取りを有効にする
#ifndef IP_TRANSPARENT
#define IP_TRANSPARENT 19
#endif

int val = 1; 
setsockopt(sockfd, SOL_IP, IP_TRANSPARENT, &val, sizeof(val));

これで、ソケットから読み取ることができるはずです。Etienne Perot からのヒント: すべての UDP トラフィックを受け入れるには、0.0.0.0 にバインドします。

ここで非常に興味深いと思ったのは、ローカルで生成された (ルーティングされたものではない) トラフィックが、iptables とルート ルールを使用して分類および再ルーティングされる可能性があることです。

お役に立てれば。

于 2012-04-10T07:25:40.467 に答える
4

tun / tapデバイスを使用でき、Pythonから簡単に読み取ることができます。例:

tunnel.py

import os
from fcntl import ioctl
from select import select
import struct
import subprocess

TUNSETIFF = 0x400454ca
TUNMODE = 0x0001

tunFile = os.open("/dev/net/tun", os.O_RDWR)
ifs = ioctl(f, TUNSETIFF, struct.pack("16sH", "tun%d", TUNMODE))
ifname = ifs[:16].strip("\x00")
print "Allocated interface %s. Configure it and use it" % ifname
subprocess.call("ifconfig %s 192.168.13.1" % ifname,shell=True)
# Reading
def read():
    r = select([tunFile], [], [])[0][0]
    if r == tunFile:
        return os.read(tunFile, 1600)
    return None

# Writing
def write(buf):
    os.write(tunFile, buf)

完全な例はここにあります

パケットをインターフェース「tun0」または印刷されたinetrface名にルーティングします。

Linuxディストリビューションは何もインストールする必要はありませんが、Windowsを使用している場合はこれを使用し、MacOSの場合はこれを使用します

編集1ここからのメモ

タップインターフェイスとtunインターフェイスの違いは、tapインターフェイスが完全なイーサネットフレームを出力する(そして指定する必要がある)のに対し、tunインターフェイスは生のIPパケットを出力する(指定する必要がある)ことです(カーネルによってイーサネットヘッダーが追加されることはありません)。 )。インターフェイスがtunインターフェイスのように機能するか、tapインターフェイスのように機能するかは、インターフェイスの作成時にフラグで指定されます。

パケットヘッダー情報(src、dstなど)を検索するには、 dpktを使用できます。

from dpkt import ip 
from tunnel import read,write # tunnel.py
while 1:
    data = read()
    if data:
        ipObj = ip.IP(data[4:])
        print ipObj.src, ipObj.dst
于 2012-04-08T19:36:56.187 に答える
1

ホストを制御しますか?その場合、Open vSwitchを使用して、問題のフローだけにまたがるルールを記述し、すべての IP 情報をタップ ポートに保持します (その後、リスナーをタップ ポートにバインドするだけです)。

(OVS はあらゆる方法ではるかに複雑なことを行うことができますが、これは比較的単純なタスクです)

于 2012-04-06T04:37:46.213 に答える