我有一个缓存应用程序,它在用户空间中运行,并为在网络其他地方的外部主机上运行的客户端提供加速服务。简而言之,我的程序监视网络流量并进行深度数据包检查,以生成对某些客户端请求的加速回复。
由于冗长乏味的原因,我想添加一些 NAT 功能。作为概念验证,我希望使用 iptables/netfilter 在我的应用程序上放置一个前端。大多数情况下,它运行良好。我可以成功进行 NAT,并且可以使用 NFQUEUE 将流量转发到我的应用程序,允许它读取它们并进行数据包检查。
但是,当我的缓存尝试生成响应并返回给客户端时,我遇到了困难。我尝试通过原始套接字将内部生成的响应数据包馈送到网络,以便将它们发送回客户端。我发现数据包的 TCP 源端口正在更改。我交给原始套接字的数据包的源端口为 2049(NFS),但实际输出的数据包的源端口为 1024。
经过进一步分析,我怀疑我生成的数据包违反了 netfilter 的连接跟踪和 NAT 代码。Netfilter 认为它们不是我将它们注入的连接的一部分,但它们与该连接具有相同的元组。因此它认为它看到了冲突并进行端口转发。这显然是一个问题,因为在客户端看来它们应该属于同一个连接。
有没有好的方法可以跳过某些数据包的最后 NAT 步骤?如果做不到这一点,有没有办法以编程方式告诉 netfilter 我的数据包属于特定的客户端连接,即使它们来自原始套接字而不是网络?
答案1
这是 Netfilter 代码中带有原始套接字和连接跟踪的极端情况。Netfilter 连接跟踪功能会更改源端口,因为通过原始套接字发出的数据包与现有的连接跟踪不匹配。
您可以使用以下 IPTables 规则解决此行为:
iptables -t raw -I OUTPUT -p tcp -j CT --notrack
另一个选项是设置以下 sysctl 值:
net.netfilter.nf_conntrack_tcp_loose=0
我不知道这些设置对其他操作可能产生的副作用。就我而言,我没有注意到任何副作用,但您的情况可能有所不同。