从NFQUEUE返回到netfilter后如何强制重新路由数据包

我有一个在用户空间中运行的缓存应用程序。通常,它使用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队列中注入到网络上?如果可行,我可以阻止原始请求,然后将缓存的回复作为全新内容发送。

提前感谢您的任何建议。

iCMS 回答:从NFQUEUE返回到netfilter后如何强制重新路由数据包

我为这个问题想到的最佳答案是打开一个原始套接字,并将其装入我的预构建数据包。至关重要的是,您必须创建一个与生成的数据包匹配的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,sizeof(one));

第一个告诉内核我已经有标头,因此无需尝试创建它们。第二个命令告诉内核在通过套接字发送的每个数据包上给标记值1,我可以在路由或iptables规则中对此进行匹配。

后来,我建立了一个目标地址,并使用sendto()发送数据包:

retval = sendto(sid,pL3,len,(struct sockaddr *)&daddr,sizeof(daddr));

最后,我安装了一条规则,告诉netfilter不要对标记为1的TCP数据包进行连接跟踪。由于我已经在上面添加了sockopt,因此我生成的所有数据包都带有此标记,因此效果很好:

 sudo iptables -t raw -I OUTPUT -p tcp -m mark --mark 1 -j CT --notrack
本文链接:https://www.f2er.com/1556516.html

大家都在问