linux内核的netfilter框架
netfilter的五个hook点
在linux的netfilter框架中定义了五个hook点,在这些hook点上可以控制流量的转发行为。
Prerouting
Input
Foward
Output
postrouting
内核协议栈的三条流量路径
网卡接收到发送到本主机的流量路径
-
prerouting->路由选择->input->内核协议栈->应用层程序 1,2,3,4
- 直接从网络层开始分析,网络层接收报文的第一个函数是ip_rcv函数,下面NF_HOOK是调用了我们的第一个hook点PRE_ROUTING,在执行完prerouting后会调用ip_rcv_finish函数
-
在这个函数中调用了ip_rcv_finish函数
ip_rcv_finish_core函数中调用了ip_route_input_noref函数,这个函数是路由选择函数,在这里主要用来判断报文是否发送给本机或者需要本机转发的
-
在路由选择后继续调用dst_input函数,因为这个报文是发送给本机的所有这里会调用ip_local_deliver函数
-
在ip_local_deliver函数中进入到了LOCAL_IN的hook点,也就是input点,在执行完后会调用ip_local_deliver_finish函数
-
在这个函数中调用ip_protocol_deliver_rcu函数
-
到此网络层的已经处理完毕,下面调用了tcp_v4_rcv函数将报文送到传输层
-
到此将报文发送到本主机的核心代码已经完成
网卡收到需要本主机转发的流量路径
-
prerouting->路由选择->forward->postrouting 1,5,6
-
直接从网络层开始分析,网络层接收报文的第一个函数是ip_rcv函数,下面NF_HOOK是调用了我们的第一个hook点PRE_ROUTING,在执行完prerouting后会调用ip_rcv_finish函数
-
在这个函数中调用了ip_rcv_finish函数
ip_rcv_finish_core函数中调用了ip_route_input_noref函数,这个函数是路由选择函数,在这里主要用来判断报文是否发送给本机或者需要本机转发的
-
在路由选择后继续调用dst_input函数,因为这个报文不是发送给本机的所有这里会调用ip_forward函数,在这个函数中会调用FORWARD的hook点
-
在ip_forward_finish中会调用dst_output函数
-
继续调用ip_output函数
-
在这里可以看到进入到了POST_ROUTING的hook点,然后调用ip_finish_output
-
在ip_finish_output中又调用了ip_finish_output2函数
-
又调用了ip_neigh_for_gw函数进行arp查询
-
查看出neigh后调用neigh_output
-
继续调用neigh_hh_output函数
-
上图中设置了mac地址并且调用了dev_queue_xmit函数来将报文送入到数据链路层处理
从本主机发出的流量路径
-
应用层->内核协议栈->路由选择->output->postrouting 7,8,9,10,6
-
从本机发送的报文仍然从网络层开始向下发送,第一个调用的函数__ip_queue_xmit,在这个函数中调用了 ip_route_output_ports进行路由查询,并将路由后从哪个设备信息设置到skbuf中,最后又调用了ip_local_out函数
-
在里面调用了LOCAL_OUT的hook点,又继续调用dst_output函数
-
继续调用ip_output函数
-
在这里可以看到进入到了POST_ROUTING的hook点,然后调用ip_finish_output
-
在ip_finish_output中又调用了ip_finish_output2函数
-
又调用了ip_neigh_for_gw函数进行arp查询
-
查看出neigh后调用neigh_output
-
继续调用neigh_hh_output函数
-
上图中设置了mac地址并且调用了dev_queue_xmit函数来将报文送入到数据链路层处理
总结
上面说明了netfilter的五个hook点在linux内核协议栈的处理位置,通过说明内核协议栈的三条流量处理路径和经过的hook点在源码中的位置来更好的理解