Open tingjunli opened 5 years ago
这种情况是否出现在同五元组的流量一直持续,而中途路由出口变更的情况下? 本模块内的映射表存活状态理应不会影响到内核的 CT 表,可能是使用了模块内过期的映射表项导致的。 如果路由出口变更后,客户端停止流量,过几分钟后再使用同样的五元组发包,能否成功重新建立 NAT 会话?
是你说的这种情况下出现的问题(同五元组的流量一直持续,而中途路由出口变更的情况),客户端停止流量,过几分钟是可以重新建立会话的,但是如果客户端不停止流量,重新发起新的会话连接,也没有办法创建新的会话。我查看了full-cone源码和内核NAT源码,原因是因为full-cone在SNAT的时候,没有更新新会话的出接口ifindex,导致内核中的出接口检查失效,所以后面该5元组的会话都不会因为出接口的变化而失效,如下图
这个BUG好像还没修复
@liangchen2233 抱歉,之前测试环境坏了一直没有验证这个 pull request。能否测试一下 #19 是否解决了这个问题?
您好,没有解决
我在最近实际使用中还发现,不仅是出接口发生改变(路由改变)后没有自动跟踪到,出接口的 IP 发生改变后貌似也不能检测到,在流量一直有的情况下当前 CT 无法自动删除。
您好,没有解决
我自己测试的话,只是换了出接口,CT表是能够及时删除的,你可以把那个patch合入再验证看看
试试我改的 https://github.com/llccd/netfilter-full-cone-nat/tree/dev ,原理是把nat_mapping
里面的ifindex
改成出接口IP,同时合并@tingjunli的patch,这样出接口改变或出接口IP改变就应该都没问题了。
Update: 在fullconenat_tg_init
里面调用一下nf_nat_masquerade_inet_register_notifiers
好像就行了
试试我改的 https://github.com/llccd/netfilter-full-cone-nat/tree/dev ,原理是把
nat_mapping
里面的ifindex
改成出接口IP,同时合并@tingjunli的patch,这样出接口改变或出接口IP改变就应该都没问题了。 Update: 在fullconenat_tg_init
里面调用一下nf_nat_masquerade_inet_register_notifiers
好像就行了
不能,直接炸了
@taolu-soft 你的内核版本是多少,是模块加载不上还是运行崩溃了,能不能提供stacktrace?
另外,解决CT表无法及时删除的最简单方法是
我做了一个临时的 patch,大家可以再测试一下,在我的环境上是ok的。加上这个 patch 之后应该不需要再依赖 MASQUERADE 模块
https://gist.github.com/Chion82/9a6880edf4cd6e1993e22b5460bde869
这样好像就是将MASQUERADE模块里的notifier重新实现了一遍,如果MASQUERADE模块同时加载的话,相同代码的功能就会执行两遍。
另外,不依赖MASQUERADE是不可能的,如果你在编译内核时把MASQUERADE禁用,nat
结构体里面根本就不会有masq_index
这个成员。
我觉得使用下面的方法更好,调用下面两个函数可以直接注册和MASQUERADE模块相同的notifier,而且在与MASQUERADE模块同时加载时只会注册一次:
nf_nat_masquerade_inet_register_notifiers()
,nf_nat_masquerade_ipv4_register_notifier()
@llccd 是的,因为我的测试环境内核很老了,我在浏览 MASQUERADE 模块的源码时还没有这个公共函数,所以就把 MASQUERADE 中的部分代码做了一下版本兼容直接复制过来用了。这个只是临时的用于测试的补丁,尽可能保持简单,除了 notifier 没有修改别的东西,用来供各位测试是否解决了这个issue的。如果这个能够解决,之后会参考你的方法将更优雅的 fix 并入本仓库中。
我指的不依赖 MASQUERADE 模块指的是不需要在运行时加载 MASQUERADE 模块。
@llccd 是的,因为我的测试环境内核很老了,我在浏览 MASQUERADE 模块的源码时还没有这个公共函数,所以就把 MASQUERADE 中的部分代码做了一下版本兼容直接复制过来用了。这个只是临时的用于测试的补丁,尽可能保持简单,除了 notifier 没有修改别的东西,用来供各位测试是否解决了这个issue的。如果这个能够解决,之后会参考你的方法将更优雅的 fix 并入本仓库中。
我指的不依赖 MASQUERADE 模块指的是不需要在运行时加载 MASQUERADE 模块。
/root/netfilter-full-cone-nat/xt_FULLCONENAT.c: 在函数‘fullconenat_device_event’中: /root/netfilter-full-cone-nat/xt_FULLCONENAT.c:743:15: 错误:提供给函数‘nf_ct_iterate_cleanup’的实参太少 (void *)(long)dev->ifindex);
@taolu-soft patch 更新修复了,请重新编译试一下。
@taolu-soft patch 更新修复了,请重新编译试一下。 还是这样,内核版本:3.10.0-957.10.1.vz7.85.17 /root/netfilter-full-cone-nat/xt_FULLCONENAT.c: 在函数‘fullconenat_device_event’中: /root/netfilter-full-cone-nat/xt_FULLCONENAT.c:746:15: 错误:提供给函数‘nf_ct_iterate_cleanup’的实参太少 (void *)(long)dev->ifindex);
这样好像就是将MASQUERADE模块里的notifier重新实现了一遍,如果MASQUERADE模块同时加载的话,相同代码的功能就会执行两遍。
另外,不依赖MASQUERADE是不可能的,如果你在编译内核时把MASQUERADE禁用,
nat
结构体里面根本就不会有masq_index
这个成员。我觉得使用下面的方法更好,调用下面两个函数可以直接注册和MASQUERADE模块相同的notifier,而且在与MASQUERADE模块同时加载时只会注册一次:
- 对于>=5.2版本的内核,可以使用
nf_nat_masquerade_inet_register_notifiers()
,- 对于<5.2且>=3.18版本的内核,可以使用
nf_nat_masquerade_ipv4_register_notifier()
- 对于3.18版本以下的内核,只能重新实现notifier或者加载MASQUERADE模块
void nf_nat_masquerade_ipv4_register_notifier(void) { / check if the notifier was already set / if (atomic_inc_return(&masquerade_notifier_refcount) > 1) return;
/* Register for device down reports */
register_netdevice_notifier(&masq_dev_notifier);
/* Register IP address change reports */
register_inetaddr_notifier(&masq_inet_notifier);
} EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4_register_notifier);
这是4.x内核里的,貌似对3.18-5.2处理有误?
如: 源IP、源端口、协议、目的IP、目的端口、目的协议都不变化的情况下,只有路由后的出接口变化,使用被动老化机制时会导致旧连接(旧的接口IP)一直存在,新的出接口IP无法正常使用