ip_conntrack将无状态的在高层有联系的单个IP数据报用状态联系了起来,实际上是在更底层破坏了分组交换网的单分组转发的原则。
ip_conntrack基于五元组来追踪一个流,在流的开头或者涉及到状态切换的时候设置一些状态和cache,属于同一流的后续分组就可以共享这些状态和cache,这些状态和cache用于更高层的逻辑判断,比如NAT,或者Netfilter的state这些match。
在纯转发网络中或者是ACL比较简单的网络节点上,我们希望ip_conntrack可以保存下面的一些信息:
1.五元组标识的数据流。这个在标准内核中已经实现,NAT模块使用的正是这个信息。
2.高层filter的结果信息,如果一个流的第一个包被高层drop了,那么希望ip_conntrack保存这个结果信息,后续的包在PREROUTING这个HOOK点直接drop,而不必继续往上层走了。这个在标准的内核中还没有实现,可能是因为要涉及高层过滤规则和底层的ip_conntrack保存的信息之间的同步,比如一个UDP流,开始由于某种事件被drop了,不久的后来又被accept了。处理这种同步非常复杂,特别是在内核中这么做。
3.IP层的路由结果信息。由于IP数据报的单包被路由的,如果多个IP数据报被看作了一个流,那么流的第一个数据报的路由结果就可以被ip_conntrack保存下来,后来的数据报直接根据该保存的结果直接转发,而不必再经过标准的IP路由或者IP路由缓存。这个在标准的Linux内核中也没有实现,原因也是信息同步问题,特别是涉及动态路由协议并且收敛慢的时候。
但是,如果你确定的知道信息同步问题不会发生,比如配置静态的filter,配置静态的路由,那么上述的2和3还是有必要实现的,幸运的是,这种实现很容易,以路由缓存为例,基于2.6.32版本的内核,只需要在struct nf_conn中添加一个指针dst_entry,保存一个流的第一个包的路由结果信息,这个信息应该是第一个包的POSTROUTING或者OUTPUT这个HOOK点上被添加进nf_conn结构体,然后在PREROUTING中被检查,如果检查存在这个dst_entry,则直接转发,调用dst_output,这里没有和filter联动,简单点说,不考虑filter,并且配置静态路由,路由不会改变的情况下,这种方式十分可行,为什么呢?因为本来ip_conntrack的加载就使得TCP/IP协议栈内核路径多了一次流匹配,到了IP层还要进行route查找或者cache查找,为何不在仅有的一次查找中完成所有这些呢,当然前提是一切都是静态的情况下。其实加入这个patch并不会带来性能的多大提升,但是它能使得ip_conntrack对性能的危害减轻一些。
ip_conntrack基于五元组来追踪一个流,在流的开头或者涉及到状态切换的时候设置一些状态和cache,属于同一流的后续分组就可以共享这些状态和cache,这些状态和cache用于更高层的逻辑判断,比如NAT,或者Netfilter的state这些match。
在纯转发网络中或者是ACL比较简单的网络节点上,我们希望ip_conntrack可以保存下面的一些信息:
1.五元组标识的数据流。这个在标准内核中已经实现,NAT模块使用的正是这个信息。
2.高层filter的结果信息,如果一个流的第一个包被高层drop了,那么希望ip_conntrack保存这个结果信息,后续的包在PREROUTING这个HOOK点直接drop,而不必继续往上层走了。这个在标准的内核中还没有实现,可能是因为要涉及高层过滤规则和底层的ip_conntrack保存的信息之间的同步,比如一个UDP流,开始由于某种事件被drop了,不久的后来又被accept了。处理这种同步非常复杂,特别是在内核中这么做。
3.IP层的路由结果信息。由于IP数据报的单包被路由的,如果多个IP数据报被看作了一个流,那么流的第一个数据报的路由结果就可以被ip_conntrack保存下来,后来的数据报直接根据该保存的结果直接转发,而不必再经过标准的IP路由或者IP路由缓存。这个在标准的Linux内核中也没有实现,原因也是信息同步问题,特别是涉及动态路由协议并且收敛慢的时候。
但是,如果你确定的知道信息同步问题不会发生,比如配置静态的filter,配置静态的路由,那么上述的2和3还是有必要实现的,幸运的是,这种实现很容易,以路由缓存为例,基于2.6.32版本的内核,只需要在struct nf_conn中添加一个指针dst_entry,保存一个流的第一个包的路由结果信息,这个信息应该是第一个包的POSTROUTING或者OUTPUT这个HOOK点上被添加进nf_conn结构体,然后在PREROUTING中被检查,如果检查存在这个dst_entry,则直接转发,调用dst_output,这里没有和filter联动,简单点说,不考虑filter,并且配置静态路由,路由不会改变的情况下,这种方式十分可行,为什么呢?因为本来ip_conntrack的加载就使得TCP/IP协议栈内核路径多了一次流匹配,到了IP层还要进行route查找或者cache查找,为何不在仅有的一次查找中完成所有这些呢,当然前提是一切都是静态的情况下。其实加入这个patch并不会带来性能的多大提升,但是它能使得ip_conntrack对性能的危害减轻一些。
最后说一下可恶的NAT,NAT实则破坏了互联网的原则,它使互联网不再互联。这就不由想起一些专家们的话,Internet在设计从来就是先天不足的,现在的Internet已经贴满了补丁,没有地方再贴了,可是反对意见有的是,Internet的发展完全是一幅油画的创作过程,草稿和定版都位于同一张纸上!
本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1270917