系统相关
首页 > 系统相关> > Linux Netfilter框架分析

Linux Netfilter框架分析

作者:互联网

目录

Netfilter框架

netfilter是Linux底层包处理框架,在协议栈中提供了若干hook点,可以用于对数据包进行过滤、修改、地址转换(SNAT/DNAT)等处理。

Netfilter的5个hook点

netfilter在内核协议栈的不同位置实现了5个hook点:

---> PRE_ROUTING ---> [Routing Decision] ---> FORWARD ---> [Routing Decision] ---> POST_ROUTING --->
				 	|                                				 ^
				 	|                                				 |
					v                                 				 |
					LOCAL_IN                        			LOCAL_OUT
				 	|                                				 ^
					|                                 				 |
					v                                				 |
				            		LOCAL PROCESS
// include/uapi/linux/netfilter_ipv4.h

/* IP Hooks */
/* After promisc drops, checksum checks. */
#define NF_IP_PRE_ROUTING	0
/* If the packet is destined for this box. */
#define NF_IP_LOCAL_IN		1
/* If the packet is destined for another interface. */
#define NF_IP_FORWARD		2
/* Packets coming from a local process. */
#define NF_IP_LOCAL_OUT		3
/* Packets about to hit the wire. */
#define NF_IP_POST_ROUTING	4
#define NF_IP_NUMHOOKS		5

ip_tables等内核模块可以通过向这5个hook点注册处理函数(handler),当数据包经过hook点时,调用回调函数handler对数据包进行处理。

netfilter协议栈数据流分析

Wikipedia上关于netfilter在协议栈中的架构图
image

连接跟踪conntrack

conntrack连接跟踪表条目

数据包经过conntrack时,conntrack会提取相关信息来唯一标识一条连接,对于TCP/UDP协议,一条连接信息通过源IP、源端口、目的IP、目的端口确定,对于ICMP协议,由type、code、id字段确定。
在用户态可以使用命令conntrack -L来查看系统上的连接跟踪表:

ipv4     2 tcp      6 33 SYN_SENT src=172.16.200.119 dst=172.16.202.12 sport=54786 dport=10051 [UNREPLIED] src=172.16.202.12 dst=172.16.200.119 sport=10051 dport=54786 mark=0 zone=0 use=2

如上是一条conntrack条目,它代表当前已跟踪到的某个连接,conntrack维护的所有信息都包含在这个条目中,通过它就可以知道某个连接处于什么状态

连接跟踪表大小

连接跟踪表能够存放的conntrack条目的最大值,即系统运行的最大连接跟踪数记作CONNTRACK_MAX
在内核中,连接跟踪表示一个二维数组结构的哈希表,哈希表的大小记作HASHSIZE,哈希表的每一项称为bucket,因此哈希表中有HASHSIZEbucket,每个bucket包含一个链表,每个链表能够存放若干个conntrack条目(bucket size)。

因此,系统允许的最大连接跟踪数为:
CONNTRACK_MAX = HASHSIZE * bucket size

#查看系统当前最大连接跟踪数CONNTRACK_MAX
sysctl -a | grep net.netfilter.nf_conntrack_max
#net.netfilter.nf_conntrack_max = 3203072

#查看当前连接跟踪表大小HASHSIZE
sysctl -a | grep net.netfilter.nf_conntrack_buckets
#400384
#或者这样
cat /sys/module/nf_conntrack/parameters/hashsize
#400384 

这两个的比值即为bucket size

对于新收到的数据包,内核使用如下步骤判断该数据包是否属于已有连接:

管理连接跟踪表

在用户态,使用工具conntrack实现对连接跟踪表的增删改查操作

#查看连接跟踪表所有条目  
conntrack -L
#清除连接跟踪表
conntrack -F
#删除连接跟踪表中所有源地址是1.2.3.4的条目
conntrack -D -s 1.2.3.4

iptables

iptables是Linux系统上的主机防火墙,依赖于netfilter框架实现,在内核态通过ip_tables内核模块与netfilter交互。
iptables由table和chain组成,以前是四表五链,新增后已经不止四表了。可以说table是chain的集合,chain是iptables规则的集合。

iptables table

iptables规则通过table来组织,根据需要做的操作分为Filter Table、NAT Table、Mangle Table、Raw Table、Security Table等。

iptables chain

在每个table内,规则进一步组织成chain,5个chain与netfilter的5个hook点一一对应:

chain的优先级:

table和chain的关系

以上说明了iptables有哪些table和哪些chain,接下来讨论两个问题:

  1. 每个table里面都有哪些chain
    下面表格展示了table和chain的关系,横向是table,纵向是chain,标记Y的表示table里有这个chain,例如让raw表中有PREROUTING和OUTPUT两个chain。
  2. 注册到同一个hook的不同chain执行的优先级问题,例如3个table中都有PREROUTING这条chain,应该按照怎样的顺序调用他们?
    对应到列从上往下,就是hook点触发时chain的调用顺序。当一个包触发netfilter hook点时,处理过程将沿着列从上向下执行
table/chain PREROUTING INPUT FORWARD OUTPUT POSTROUTING
[routing decision] Y
raw Y Y
连接跟踪 Y Y
mangle Y Y Y Y Y
nat(DNAT) Y Y
[routing decision] Y Y
filter Y Y Y
security Y Y Y
nat(SNAT) Y Y

iptables状态匹配

conntrack可以跟踪数据包的状态,iptables使用-m state进行状态匹配正是使用了conntrack连接跟踪表中标记的状态。
数据包内核态状态比较多,映射到用户空间有5种状态:

参考

https://opengers.github.io/openstack/openstack-base-netfilter-framework-overview/#conntrack条目
http://arthurchiao.art/blog/conntrack-design-and-implementation-zh/#5-个-hook-点
https://arthurchiao.art/blog/deep-dive-into-iptables-and-netfilter-arch-zh/#chain-遍历优先级

eBPF开发:
https://duo.com/labs/tech-notes/writing-an-xdp-network-filter-with-ebpf
https://github.com/cloudflare/cloudflare-blog/blob/master/2018-07-dropping-packets/xdp-drop-ebpf.c
https://gist.github.com/fntlnz/f6638d59e0e39f0993219684d9bf57d3
https://davidlovezoe.club/wordpress/archives/937

标签:chain,框架,IP,跟踪,conntrack,Linux,数据包,连接,Netfilter
来源: https://www.cnblogs.com/init0ne/p/14602887.html