Python/iptables:捕获所有UDP数据包及其原始目标

Eti*_*rot 11 python sockets udp iptables packet-capture

我正在尝试编写一个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
Run Code Online (Sandbox Code Playgroud)

这很好,现在我可以通过端口15000上的套接字获取所有传出的UDP数据包.

现在,我需要目标信息(目标主机和端口号),因此简单的UDP套接字是不够的; 需要一个原始套接字,以便它获得完整的IP标头.

然而,事实证明,收到的数据包似乎已得到解决localhost:15000.这是有道理的,因为那是套接字的位置,但这不是我想要的; 我希望在重定向数据包之前使用主机/端口iptables.

谷歌搜索导致了这个问题,答案提出了两种方法:TPROXY并且SO_ORIGINAL_DST,推荐前者,这就是我试图使用的方法.

添加了以下iptables规则TPROXY:

sudo iptables -t mangle -A PREROUTING -j TPROXY --dest 0.0.0.0/0 -p udp --on-port 15000
Run Code Online (Sandbox Code Playgroud)

tproxy.txt读取,我们需要创建一个带有该IP_TRANSPARENT选项的侦听套接字(这是以root身份完成的):

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
Run Code Online (Sandbox Code Playgroud)

好的,现在让我们编写另一个脚本来生成一个测试包,看看是否有任何事情发生:

from socket import *
s = socket(AF_INET, SOCK_DGRAM)
s.connect(('192.168.1.1', 9001))
s.send('hello')
Run Code Online (Sandbox Code Playgroud)

但接收方没有任何反应.的recv通话似乎挂起,没有收到任何数据.

所以,整体问题是:

  • 代码中是否存在从TPROXY规则接收数据的错误?

要么

  • 有没有其他方法来实现这一点(将所有传出的UDP数据包重定向到本地套接字,并获取目标信息)?

编辑:我应该坚持要重新定向(因此拦截)数据包,而不是在它们经历时检查它们.

Edw*_*rdH 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
Run Code Online (Sandbox Code Playgroud)

套接字设置:

  • 创建UDP套接字(常规)
  • 启用非本地地址的绑定/读取
#ifndef IP_TRANSPARENT
#define IP_TRANSPARENT 19
#endif

int val = 1; 
setsockopt(sockfd, SOL_IP, IP_TRANSPARENT, &val, sizeof(val));
Run Code Online (Sandbox Code Playgroud)

您现在应该可以从套接字读取.提示形式Etienne Perot:要接受所有UDP流量,请绑定到0.0.0.0.

我在这里发现的非常有趣的是,可以使用iptables和路由规则对本地生成的流量(而不是路由流量)进行分类和重新路由.

希望这可以帮助.