Linux之ip_conntrack容易混淆的问题点滴

《再次深入到ip_conntrack的conntrack full问题》最后的一个问题提示ip_conntrack有一个event机制,可以主动通报ip_conntrack的一些事件,包括追踪信息到期删除等事件,通知给谁呢?当然是通知给所有感兴趣的模块了,其中之一就是用户态进程,这样用户态进程得知可以采取一些措施,比如防火墙上设置一些放过规则等,这个通知机制使用了观察者设计模式。Linux ip_conntrack的一些细节问题由于Linux的ip_conntrack具有大量的状态,而每一种状态都有一定的超时时间,这些状态中的个别可以和网络协议的不同状态建立映射关系,另一些则不能。如果协议本身是有状态的,那么就很方便建立一种映射关系,反之如果协议没有状态,那么就不能建立映射关系。有时候,对于无状态的协议而言,ip_conntrack的状态超时时间会带来一些令人郁闷的问题。

总之,Linux的ip_conntrack机制如果深究起来还真的看点,如果搞防火墙开发,实属不可不察也。下面就举几个例子。

例子举例例子1:

对于UDP而言,它本身没有状态,无需建立连接,无需确认,纯粹就是一个数据报协议,因此ip_conntrack使用经验值来设定各个状态的超时时间,但是如果双方有一段时间没有发包,那么当初始接收端再发起一个数据包时,就会给防火墙上的基于ctstate的过滤规则带来影响,具体参见《再次深入到ip_conntrack的conntrack full问题》。

例子2:对于UDP而言,如果在Linux防火墙上使用NAT,那么在数据通信期间,即使NAT规则被删除或者被修改,该数据流依然会使用老的NAT规则而不是不使用任何规则或者使用新的规则。例子3:在早期的内核上,加载ip_conntrack模块,然后ping一个可以ping通的地址,则在/proc/net/ip_conntrack中却看不到该连接的追踪信息,而ping一个根本不可达的地址,反而能看到一个反方向为UNREPLY的追踪信息。值得注意的是,起码在2.6.32内核上,这个问题不再存在,而在2.6.9内核上还是存在的,具体哪个版本修正了它,没有详细看内核的ChangeLog。例子4:对于TCP而言,只要一个连接断开了,/proc/net/ip_conntrack中的关于该连接的追踪信息将马上被删除,而不会像UDP那样保留。针对以上问题的一些解释例子1的解释:这个没有什么好说的,根本原因就是UDP本身没有状态,而ip_conntrack将establish状态强加给了一个UDP连接,所谓的ip_conntrack的establish状态对于所有的协议都是说有去有回的流,,当然对于UDP更是这样。对于TCP而言,ip_conntrack将不是syn状态的流量都映射成了establisd状态(注意不是TCP的established状态),这也符合上述定义。在ip_conntrack处理的入口的最后:

if(set_reply)set_bit(IPS_SEEN_REPLY_BIT,&ct->status);

这说明只要set_reply为真就会修改ct的一个状态位,而set_reply在ip_conntrack_in的resolve_normal_ct调用中就会被设置。因此可见IP_CT_ESTABLISHED状态和具体的协议是无关的,对于TCP而言,所有SYN后面的包都会是IP_CT_ESTABLISHED状态。然而由于TCP本身拥有可以监控连接的状态,比如close-wait等,因此它在ip_conntrack中又有一些子状态,这个用于在适当的时候释放ip_conntrack数据结构,因此只要TCP的ip_conntrack的time-wait子状态到期,其ip_conntrack数据结构就会被当即释放,这一切正是因为TCP将其协议状态映射成了ip_conntrack的子状态,而这些子状态知道什么时候一个tcp流结束了。然而这一切对于UDP以及ICMP而言就没有这么幸运了,它们没有所谓的子状态,它们只能使用大胆的ip_conntrack状态。

每一天都是一个阶梯,是向既定目标迈进的新的一步。

Linux之ip_conntrack容易混淆的问题点滴

相关文章:

你感兴趣的文章:

标签云: