Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

对于5元组没有变化的连接,前后两次SNAT出接口变化后,CT表无法及时删除失效的跟踪连接,导致新的NAT会话失败 #18

Open
tingjunli opened this issue Nov 5, 2018 · 17 comments

Comments

@tingjunli
Copy link

如:
源IP、源端口、协议、目的IP、目的端口、目的协议都不变化的情况下,只有路由后的出接口变化,使用被动老化机制时会导致旧连接(旧的接口IP)一直存在,新的出接口IP无法正常使用

@tingjunli tingjunli changed the title 路由后的出接口down之后,如果没有收到删除跟踪连接的event事件,旧的连接一直存在,则会导致某些连接失败 前后两次SNAT出接口变化后,CT表无法及时删除失效的跟踪连接,导致NAT会话失败 Nov 7, 2018
@tingjunli tingjunli changed the title 前后两次SNAT出接口变化后,CT表无法及时删除失效的跟踪连接,导致NAT会话失败 对于5元组没有变化的连接,前后两次SNAT出接口变化后,CT表无法及时删除失效的跟踪连接,导致NAT会话失败 Nov 7, 2018
@tingjunli tingjunli changed the title 对于5元组没有变化的连接,前后两次SNAT出接口变化后,CT表无法及时删除失效的跟踪连接,导致NAT会话失败 对于5元组没有变化的连接,前后两次SNAT出接口变化后,CT表无法及时删除失效的跟踪连接,导致新的NAT会话失败 Nov 7, 2018
@Chion82
Copy link
Owner

Chion82 commented Nov 8, 2018

这种情况是否出现在同五元组的流量一直持续,而中途路由出口变更的情况下?
本模块内的映射表存活状态理应不会影响到内核的 CT 表,可能是使用了模块内过期的映射表项导致的。
如果路由出口变更后,客户端停止流量,过几分钟后再使用同样的五元组发包,能否成功重新建立 NAT 会话?

@tingjunli
Copy link
Author

tingjunli commented Nov 12, 2018

是你说的这种情况下出现的问题(同五元组的流量一直持续,而中途路由出口变更的情况),客户端停止流量,过几分钟是可以重新建立会话的,但是如果客户端不停止流量,重新发起新的会话连接,也没有办法创建新的会话。我查看了full-cone源码和内核NAT源码,原因是因为full-cone在SNAT的时候,没有更新新会话的出接口ifindex,导致内核中的出接口检查失效,所以后面该5元组的会话都不会因为出接口的变化而失效,如下图
image

@liangchen2233
Copy link

这个BUG好像还没修复

@Chion82
Copy link
Owner

Chion82 commented Apr 1, 2020

@liangchen2233 抱歉,之前测试环境坏了一直没有验证这个 pull request。能否测试一下 #19 是否解决了这个问题?

@liangchen2233
Copy link

您好,没有解决

@Chion82
Copy link
Owner

Chion82 commented Apr 8, 2020

我在最近实际使用中还发现,不仅是出接口发生改变(路由改变)后没有自动跟踪到,出接口的 IP 发生改变后貌似也不能检测到,在流量一直有的情况下当前 CT 无法自动删除。

@tingjunli
Copy link
Author

您好,没有解决

我自己测试的话,只是换了出接口,CT表是能够及时删除的,你可以把那个patch合入再验证看看

@llccd
Copy link
Contributor

llccd commented Apr 25, 2020

试试我改的 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
Copy link

试试我改的 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好像就行了

不能,直接炸了

@llccd
Copy link
Contributor

llccd commented May 12, 2020

@taolu-soft 你的内核版本是多少,是模块加载不上还是运行崩溃了,能不能提供stacktrace?

另外,解决CT表无法及时删除的最简单方法是

  1. 添加赋值ifindex的patch
  2. 确保MASQUERADE模块已加载,或者MASQUERADE编译进内核(可以不添加MASQUERADE规则,但模块要加载)

@Chion82
Copy link
Owner

Chion82 commented May 21, 2020

我做了一个临时的 patch,大家可以再测试一下,在我的环境上是ok的。加上这个 patch 之后应该不需要再依赖 MASQUERADE 模块

https://gist.github.com/Chion82/9a6880edf4cd6e1993e22b5460bde869

@llccd
Copy link
Contributor

llccd commented May 21, 2020

这样好像就是将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模块

@Chion82
Copy link
Owner

Chion82 commented May 22, 2020

@llccd 是的,因为我的测试环境内核很老了,我在浏览 MASQUERADE 模块的源码时还没有这个公共函数,所以就把 MASQUERADE 中的部分代码做了一下版本兼容直接复制过来用了。这个只是临时的用于测试的补丁,尽可能保持简单,除了 notifier 没有修改别的东西,用来供各位测试是否解决了这个issue的。如果这个能够解决,之后会参考你的方法将更优雅的 fix 并入本仓库中。

我指的不依赖 MASQUERADE 模块指的是不需要在运行时加载 MASQUERADE 模块。

@taolu-soft
Copy link

@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);

@Chion82
Copy link
Owner

Chion82 commented May 27, 2020

@taolu-soft patch 更新修复了,请重新编译试一下。

@taolu-soft
Copy link

@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);

@MeIsReallyBa
Copy link

这样好像就是将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处理有误?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants