Netfilter是一个可以高度定制协议栈的优良框架,早就已经被包含于Linux内核了,关于它的设计,可以在其官方网站上找到N多可以一看的东西。被讨论最多的就是HOOK点的位置的设计(人家老外关注的核心的设计,而不是如何去实现它,以及实现了之后的源码分析),最好还是看一下这些讨论。
若想实现一个透明的防火墙,那么对Netfilter几本框架的理解是少不了的,除此之外还会有一些问题,比如下面的几个问题:
1.为何OUTPUT设计在路由之后?
2.为何FORWARD设计在路由之后?
3.桥接层的Netfilter钩子函数为何有那么多的Stolen?
对于问题1,我觉得不难回答,因为Linux的路由模块直接区分了本地和非本地的概念,且路由结果中包含了目标设备的很多信息,包括网卡信息,发送回调函数等,并且此时已经选择了源IP地址(对于TCP,UDP而言,非tso情形下,因为在进入IP层之前要计算校验码,需要一个伪头,而伪头中有一个源IP地址,所以在进入IP层之前就需要先路由一下),OUTPUT这个HOOK点需要的信息基本都在路由之后被确定,DNAT是该HOOK点上比较特殊的,因为它改变了目标地址,那么就需要被重新路由,当然对于DNAT之后的重新路由责任上由DNAT模块自己负责。回答了问题1,问题2基本就不用回答了,至于问题3,则比较复杂,因为这涉及到了Bridge Netfilter和IP Netfilter的联动问题。
Bridge和IP在透明防火墙中是需要联动的,因为IP层可以进行更多的控制,比如更多的策略(string match)进行Filter,比如可以进行基于五元素的连接追踪等,虽然这些都可以在Bridge层完成,但是模块化以及KISS原则将Bridge从这些复杂的策略当中分离了,使它仅仅处理它应该处理的事,如果需要IP层的帮助,那么直接call即可,Netfilter机制使用NF_HOOK宏就可以让一个任意层的数据包被任意层的任意HOOK处理,并且每个HOOK点的钩子函数遍历处理还可以在任意点被中断(NF_STOP),然后在任意时间的任意其它地点重新在被中断的HOOK点的被中断的钩子函数处继续遍历下去,这是通过NF_HOOK_THRESH宏来完成的,另外任意的HOOK点钩子函数都可以将数据包偷走(NF_STOLEN),如下图所示:
1.几个HOOK点
2.每一个HOOK上按照优先级排序的钩子函数
3.NF_HOOK_THRESH宏
4.nf_hook_ops结构体
5.几个nf_XX_hook_priorities优先级枚举
若想实现一个透明的防火墙,那么对Netfilter几本框架的理解是少不了的,除此之外还会有一些问题,比如下面的几个问题:
1.为何OUTPUT设计在路由之后?
2.为何FORWARD设计在路由之后?
3.桥接层的Netfilter钩子函数为何有那么多的Stolen?
对于问题1,我觉得不难回答,因为Linux的路由模块直接区分了本地和非本地的概念,且路由结果中包含了目标设备的很多信息,包括网卡信息,发送回调函数等,并且此时已经选择了源IP地址(对于TCP,UDP而言,非tso情形下,因为在进入IP层之前要计算校验码,需要一个伪头,而伪头中有一个源IP地址,所以在进入IP层之前就需要先路由一下),OUTPUT这个HOOK点需要的信息基本都在路由之后被确定,DNAT是该HOOK点上比较特殊的,因为它改变了目标地址,那么就需要被重新路由,当然对于DNAT之后的重新路由责任上由DNAT模块自己负责。回答了问题1,问题2基本就不用回答了,至于问题3,则比较复杂,因为这涉及到了Bridge Netfilter和IP Netfilter的联动问题。
Bridge和IP在透明防火墙中是需要联动的,因为IP层可以进行更多的控制,比如更多的策略(string match)进行Filter,比如可以进行基于五元素的连接追踪等,虽然这些都可以在Bridge层完成,但是模块化以及KISS原则将Bridge从这些复杂的策略当中分离了,使它仅仅处理它应该处理的事,如果需要IP层的帮助,那么直接call即可,Netfilter机制使用NF_HOOK宏就可以让一个任意层的数据包被任意层的任意HOOK处理,并且每个HOOK点的钩子函数遍历处理还可以在任意点被中断(NF_STOP),然后在任意时间的任意其它地点重新在被中断的HOOK点的被中断的钩子函数处继续遍历下去,这是通过NF_HOOK_THRESH宏来完成的,另外任意的HOOK点钩子函数都可以将数据包偷走(NF_STOLEN),如下图所示:
1.几个HOOK点
2.每一个HOOK上按照优先级排序的钩子函数
3.NF_HOOK_THRESH宏
4.nf_hook_ops结构体
5.几个nf_XX_hook_priorities优先级枚举