Netfilter hooks

Netfilter hooks

Netfilter hooks—-https://wiki.nftables.org/wiki-nftables/index.php/Netfilter_hooks
kernel 在线源码(代码可跳转)—-https://elixir.bootlin.com/linux/v5.4.281/source/net


Netfilter 与iptables/ebtables

ebtables

Netfilter 在 链路层(L2)提供了以下 6 个 hook 点

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include/uapi/linux/netfilter_bridge.h
/* Bridge Hooks */
/* After promisc drops, checksum checks. */
#define NF_BR_PRE_ROUTING	0
/* If the packet is destined for this box. */
#define NF_BR_LOCAL_IN		1
/* If the packet is destined for another interface. */
#define NF_BR_FORWARD		2
/* Packets coming from a local process. */
#define NF_BR_LOCAL_OUT		3
/* Packets about to hit the wire. */
#define NF_BR_POST_ROUTING	4
/* Not really a hook, but used for the ebtables broute table */
#define NF_BR_BROUTING		5
#define NF_BR_NUMHOOKS		6

enum nf_br_hook_priorities {
	NF_BR_PRI_FIRST = INT_MIN,
	NF_BR_PRI_NAT_DST_BRIDGED = -300,
	NF_BR_PRI_FILTER_BRIDGED = -200,
	NF_BR_PRI_BRNF = 0,
	NF_BR_PRI_NAT_DST_OTHER = 100,
	NF_BR_PRI_FILTER_OTHER = 200,
	NF_BR_PRI_NAT_SRC = 300,
	NF_BR_PRI_LAST = INT_MAX,
};

ebtables 即以太网桥防火墙,以太网桥工作在数据链路层,ebtables用来过滤数据链路层数据包。在内核中,ebtables 的数据截获点比 iptables 更“靠前”,它获得的数据更“原始”,ebtables 多用于桥模式,比如控制 VLAN ID 等。 ebtables 的配置分为表、链和规则三级。

  • ebtables 有三个tables:filter ,nat ,broute
    • filter:过滤本机流入流出的数据包时默认使用的表。 它包含有 3 条链,分别为 INPUT 链、OUTPUT 链、FORWARD 链。
    • nat :主要用于修改数据帧的MAC地址,实现地址转换(mac-NAT)。 它包含有 3 条链,分别为 PREROUTING 链、OUTPUT链、POSTROUTING 链。
    • broute:网桥的一种特殊工作模式,它可以根据配置对满足某些规则的包送入三层进行路由;也可以根据配置对满足某些规则的二层包进行 bridge。类似于 VPP(Vector packet processing)中的 bridge-domain。它只有 1 个 BROUTING 链。
  • ebtables 共分为以下 6 条内置链:
    • INPUT: 数据帧的目的地址是网桥本身。
    • FORWARD: 被网桥转发的数据帧。
    • OUTPUT: 处理网桥自身产生并向外发送的数据帧。同样用于修改目的MAC地址,但作用范围仅限于本机发出的流量
    • PREROUTING: 处理刚进入网桥的数据帧,在桥接决策之前生效。这是修改目的MAC地址(MAC DNAT)的理想位置,可以实现流量重定向。
    • POSTROUTING: 处理即将离开网桥的数据帧,在桥接决策之后生效。这是修改源MAC地址(MAC SNAT)的地方,可以实现MAC地址伪装
    • BROUTING: 以太帧进入网桥设备后首先通过的就是 BROUTING 链,经过 BROUTING 后才决定数据包是进入网桥转发处理流程还是本地路由处理流程。

    BROUTING链,当规则返回ACCEPT时,意味着“我允许这个帧通过”。这个帧会被视为普通的桥接流量,进入标准的桥接处理流程。接下来,内核会去查找MAC地址表,根据目的MAC决定是将它转发到另一个桥接端口,还是递交给本机的上层协议栈(如果目的MAC是本机网桥的MAC)。当规则返回 DROP 时,在 BROUTING 链的语境下,它有一个特殊含义:“中断桥接”(skb should be routed, not bridged.)。内核收到这个信号后,就不会再把这个数据帧当成二层流量来处理了。相反,它会把这个帧“踢”给上层的 IP 协议栈。此时,这个帧就变成了一个普通的 IP 数据包,后续会进入 iptables 的 PREROUTING 链,并最终根据路由表来决定是发给本机还是路由转发。可查看bridge\netfilter\ebtable_broute.c 的 ebt_broute 函数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# ebtables -t filter -LLc
Bridge table: filter

Bridge chain: INPUT, entries: 0, policy: ACCEPT

Bridge chain: FORWARD, entries: 0, policy: ACCEPT

Bridge chain: OUTPUT, entries: 0, policy: ACCEPT
#
# ebtables -t nat -LLc
Bridge table: nat

Bridge chain: PREROUTING, entries: 0, policy: ACCEPT

Bridge chain: OUTPUT, entries: 0, policy: ACCEPT

Bridge chain: POSTROUTING, entries: 0, policy: ACCEPT
#
# ebtables -t broute -LLc
Bridge table: broute

Bridge chain: BROUTING, entries: 0, policy: ACCEPT
#

iptables

Netfilter 在 网络层(L3)提供了以下 5 个 hook 点,包经过协议栈时会触发内核模块注册在这里的处理函数。触发哪个 hook 取决于包的方向(ingress/egress)、包的目的地址、包在上一个 hook 点是被丢弃还是拒绝等等

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include/uapi/linux/netfilter.h
enum nf_inet_hooks {
	NF_INET_PRE_ROUTING,   //接收到的包进入协议栈后立即触发此 hook,在进行任何路由判断 (将包发往哪里)之前
	NF_INET_LOCAL_IN,      //接收到的包经过路由判断,如果目的是本机,将触发此 hook
	NF_INET_FORWARD,       //接收到的包经过路由判断,如果目的是其他机器,将触发此 hook
	NF_INET_LOCAL_OUT,     //本机产生的准备发送的包,在进入协议栈后立即触发此
	NF_INET_POST_ROUTING,  //本机产生的准备发送的包或者转发的包,在经过路由判断之后, 将触发此 hook
	NF_INET_NUMHOOKS
};

enum nf_dev_hooks {
	NF_NETDEV_INGRESS,
	NF_NETDEV_NUMHOOKS
};

enum {
	NFPROTO_UNSPEC =  0,
	NFPROTO_INET   =  1,
	NFPROTO_IPV4   =  2,
	NFPROTO_ARP    =  3,
	NFPROTO_NETDEV =  5,
	NFPROTO_BRIDGE =  7,
	NFPROTO_IPV6   = 10,
	NFPROTO_DECNET = 12,
	NFPROTO_NUMPROTO,
};
#include\uapi\linux\netfilter_ipv4.h
enum nf_ip_hook_priorities {
	NF_IP_PRI_FIRST = INT_MIN,
	NF_IP_PRI_RAW_BEFORE_DEFRAG = -450,
	NF_IP_PRI_CONNTRACK_DEFRAG = -400,
	NF_IP_PRI_RAW = -300,
	NF_IP_PRI_SELINUX_FIRST = -225,
	NF_IP_PRI_CONNTRACK = -200,
	NF_IP_PRI_MANGLE = -150,
	NF_IP_PRI_NAT_DST = -100,
	NF_IP_PRI_FILTER = 0,
	NF_IP_PRI_SECURITY = 50,
	NF_IP_PRI_NAT_SRC = 100,
	NF_IP_PRI_SELINUX_LAST = 225,
	NF_IP_PRI_CONNTRACK_HELPER = 300,
	NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
	NF_IP_PRI_LAST = INT_MAX,
};
#include\uapi\linux\netfilter_ipv6.h
enum nf_ip6_hook_priorities {
	NF_IP6_PRI_FIRST = INT_MIN,
	NF_IP6_PRI_RAW_BEFORE_DEFRAG = -450,
	NF_IP6_PRI_CONNTRACK_DEFRAG = -400,
	NF_IP6_PRI_RAW = -300,
	NF_IP6_PRI_SELINUX_FIRST = -225,
	NF_IP6_PRI_CONNTRACK = -200,
	NF_IP6_PRI_MANGLE = -150,
	NF_IP6_PRI_NAT_DST = -100,
	NF_IP6_PRI_FILTER = 0,
	NF_IP6_PRI_SECURITY = 50,
	NF_IP6_PRI_NAT_SRC = 100,
	NF_IP6_PRI_SELINUX_LAST = 225,
	NF_IP6_PRI_CONNTRACK_HELPER = 300,
	NF_IP6_PRI_LAST = INT_MAX,
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# iptables -t raw -nvL
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
# iptables -t mangle -nvL
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
# iptables -t nat -nvL
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
# iptables -t filter -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
  • iptables 有四个表raw ,mangle ,nat ,filter

    • filter 表:过滤(放行/拒绝)
    • nat 表:网络地址转换
    • mangle 表:修改 IP 头,可以修改数据包的 TTL;还可以对数据包打上只在内核内有效的“标记”(internal kernel “mark”),后续的 table 或工具可以根据这些标记进行处理。标记不会修改包本身,只是在包的内核表示上做标记。iptables 只能在 mangle 表中打 mark,在 ebtables 中,所有的表(filter、nat、broute)都可以用来打 mark。
    • raw 表:conntrack 相关,iptables 防火墙是有状态的:对每个数据包进行判断的时候是依赖已经判断过的数据包。建立在 netfilter 之上的连接跟踪(connection tracking)特性使得 iptables 将数据包看作是已有连接或会话的一部分,而不是一个由独立、不相关的数据包而组成的流。
  • 不同场景下报文的游走流程:

    • 收到的、目的是本机的包: PRETOUTING -> INPUT
    • 收到的、目的是其他主机的包: PRETOUTING -> FORWARD -> POSTROUTING
    • 本地产生的包: OUTPUT -> POSTROUTING
Licensed under CC BY-NC-SA 4.0
使用 Hugo 构建
主题 StackJimmy 设计