我有一个在用户空间中运行的缓存应用程序。通常,它使用DPDK直接与NIC交互,而无需内核交互,从线路上抓取数据包,然后通过它们,从缓存中生成响应,或者在某些情况下阻止它们。它对端点是透明的,并被编写为直接处理来自NIC的原始数据包数据。值得注意的是,我在这里不是在做普通的套接字编程--所有的事情都是在数据包级别处理的,没有与TCP/IP堆栈交互。
由于冗长乏味的原因,我想添加一些NAT功能。作为概念证明,我希望使用iptables/netfilter在我的应用程序上放置一个前端。因此,我使用如下命令完成了NAT部分:
sudo iptables --table nat --append PREROUTING --in-interface seg1a -j DNAT --to-destination $SERVERIP
sudo iptables --table nat --append POSTROUTING --out-interface seg1b -j MASQUERADE
sudo route add $SERVERIP seg1b这对我的目的很有效。客户端现在连接到我的系统上的一个接口,但它们的流量被重定向到服务器。我保证他们的流量会通过我的系统,所以一切都很好。
但作为缓存,我需要能够响应来自客户端的一些请求。我想我可以使用NFQUEUE来实现这一点,通过一个小的应用程序从netfilter队列中读取数据,并通过IPC向我的应用程序传递数据包。我使用的iptables规则如下:
sudo iptables --table mangle --append FORWARD -j NFQUEUE只要我的应用程序不响应任何东西,它就可以正常工作。但是,当我的缓存试图响应来自一个端点的某些东西时,事情就出错了。高速缓存反转所有的L2-4报头,管理序列号和ack号等,但是分组不会返回到客户端。
我认为发生的情况是数据包的路由决策是在它被发送到NFQUEUE之前做出的。因此,即使缓存返回源IP地址和目标IP地址颠倒的内容,也与数据包的路由无关。
我尝试了许多方法来更改响应数据包的路由,但似乎都不起作用。如何更改从netfilter队列读取的数据包的路由?如果做不到这一点,有没有一种好方法可以直接将数据包从netfilter队列注入到线路上?如果这是可行的,我可以阻止原始请求,然后发送缓存的回复作为一个全新的东西。
提前感谢您的任何建议。
发布于 2020-09-23 04:42:32
对于这个问题,我想出的最好的答案是打开一个原始套接字,并将我预先构建的数据包提供给它。最重要的是,您必须创建一个iptables规则来匹配您生成的数据包,并告诉netfilter不要进行连接跟踪。否则,netfilter会看到注入的数据包,并认为存在连接冲突。然后它会进行端口转发,因此数据包从不同的端口传出,而不是您放入的端口!
我是这样构建套接字的:
sid = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);然后,我打开了几个选项(为了简洁起见,保留了故障处理):
int one = 1;
const int *val = &one;
retval = setsockopt(sid, IPPROTO_IP, IP_HDRINCL, val, sizeof(one));
retval = setsockopt(sid, SOL_SOCKET, SO_MARK, val, sizeof(one));其中的第一个告诉内核我已经有了头文件,所以不需要尝试创建它们。第二个命令告诉内核将通过套接字发送的每个数据包的标记值设置为1,我可以在路由或iptables规则中与之匹配。
稍后,我构建了一个目的地址,并使用sendto()发送数据包:
retval = sendto(sid, pL3, len, 0, (struct sockaddr *)&daddr, sizeof(daddr));最后,我安装了一个规则,告诉netfilter不要对标有1的TCP数据包进行连接跟踪。因为我添加了上面的sockopt,所以所有生成的数据包都有这个标记,所以效果很好:
sudo iptables -t raw -I OUTPUT -p tcp -m mark --mark 1 -j CT --notrackhttps://stackoverflow.com/questions/63926718
复制相似问题