我正在尝试编写一个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头。
然而,事实证明,收到的数据包似乎是针对localhost:15000
的。这是有道理的,因为那是套接字的位置,但这不是我想要的;在数据包被iptables
重定向之前,我想要主机/端口。
谷歌搜索导致this question,答案提示两种方法: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
从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
好的,现在让我们编写另一个脚本来生成一个测试包,看看是否发生了什么:
from socket import *
s = socket(AF_INET, SOCK_DGRAM)
s.connect(('192.168.1.1', 9001))
s.send('hello')
但接收方没有任何反应。 recv
电话似乎挂起,没有收到任何数据。
所以,整体问题是:
TPROXY
规则接收数据?或
修改:我应该坚持要重定向(因此拦截)数据包,而不仅仅是检查它们。
答案 0 :(得分:9)
我发现你的问题很有趣。
以下解决方案基于标记主机生成的UDP流量并将其重新路由回本地主机应用程序。在应用程序中,应该使用UDP套接字来读取数据,即使是那些不是主机本身的数据(见下文)。
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
#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和路由规则对本地生成的流量(而不是路由流量)进行分类和重新路由。
希望这有帮助。
答案 1 :(得分: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)
可以找到完整示例here
并将数据包路由到接口“tun0”或打印的非界面名称。
linux发行版不需要安装任何东西,但是如果你在Windows上使用this,并且对于mac os使用this
编辑1 来自here的注释:
tap接口和tun接口之间的区别在于tap接口输出(并且必须给出)完整的以太网帧,而tun接口输出(并且必须给出)原始IP数据包(并且不添加以太网接头)由内核)。在创建接口时,是否使用标志指定接口的功能类似于tun接口或类似tap接口。
用于查找包头信息(如src,dst& etc ......),您可以使用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
答案 2 :(得分:1)
你控制主人吗?如果是这样,您可以使用Open vSwitch编写一个仅涵盖相关流的规则,将所有IP信息保留到tap端口(然后将侦听器绑定到tap端口)。
(OVS可以做各种更复杂的事情,但这是一项相对简单的任务)