[TOC]
### **简介**
Netfilter是linux内核中的数据包过滤框架(也可以说它是内核的一个子系统)。它提供了一种钩子机制,可以让其他内核模块比如conntrack、nat等向它的钩子点注册回调函数。
简单来说:Netfilter是一个框架,不是模块,它提供钩子点;conntrack、nat是内核模块,实现具体的数据包过滤与管理功能。内核模块是可以卸载的,但框架只有在编译内核的时候选择编译或者不编译,不能够卸载。我们编译Linux内核时,如果选择了Netfilter子系统,那么这些钩子点就已经在Linux内核网络中。
### **支持多种协议族**
Netfilter是一种通用的数据包处理框架,所谓通用是指它支持多种协议族。在4.4的内核版本中, Netfilter支持的协议族如下:
> include/uapi/linux/netfilter.h
```
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,
};
```
我们可以通俗地理解为,Netfilter框架可以处理不同协议的包,比如IPv4、IPv6等。不过,上面的名字不一定表示协议的名字,比如BRIDGE就不是协议的名字,它表示Netfilter可以处理二层的数据帧。
### **钩子点与钩子函数**
Netfilter提供钩子点,其他内核模块可以向钩子点注册钩子函数。Netfilter定义一个全局二维数组,用来存储所有协议族的钩子点与钩子函数。在4.4的内核中,该数组的定义如下:
> net/netfilter/core.c
```
struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
```
`NF_MAX_HOOKS`的值为8,说明有些协议族会有八个钩子点。
在iptables中,有五条链,它们的名字分别是`PREROUTING`、`POSTROUTING`、`INPUT`、`OUTPUT`、`FORWARD`。钩子点其实是没有名字的,比如`nf_hooks_needed[NFPROTO_IPV4][0]`就表示IPv4协议的第0个钩子点。不过,第0个钩子点的钩子函数是根据`PREROUTING`链中的规则对数据包进行处理的。所以为了把钩子点和链对应起来,内核中给`nf_hooks_needed[NFPROTO_IPV4][x]`中的第二个下标`x`命名了一系列常量,如下:
> include/uapi/linux/netfilter_ipv4.h
```
/* only for userspace compatibility */
#ifndef __KERNEL__
...
/* 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
...
#endif /* ! __KERNEL__ */
```
上面我们可以看出,对于IPv4协议,给钩子点的命名分别为`NF_IP_PRE_ROUTING`、`NF_IP_POST_ROUTING`等。
不过,从上面的注释可以看到,上面的钩子名的常量定义其实不是在内核空间的,是给用户空间所使用的。什么意思呢?就是说,如果用户要进行内核编程,那么用到的常量就是`NF_IP_PRE_ROUTING`。在内核中,使用到的钩子名的常量不是这样叫的。那是怎么的呢?
其实,在内核空间中,由于IPv4和IPv6的钩子点个数一样多,都是5个,所以内核对于这两个协议,统一了钩子点的常量定义,如下:
> include/uapi/linux/netfilter.h
```
enum nf_inet_hooks {
NF_INET_PRE_ROUTING,
NF_INET_LOCAL_IN,
NF_INET_FORWARD,
NF_INET_LOCAL_OUT,
NF_INET_POST_ROUTING,
NF_INET_NUMHOOKS
};
```
所以在我们后面的章节中,我们对钩子点的叫法分别为`NF_INET_xxxx`。
虽然,IPv4与IPv6协议的钩子点命名统一了,但是二者的钩子函数是不一样的。也就是说,IPv4的钩子点的函数是注册在`nf_hooks_needed[NFPROTO_IPV4][x]`中的,IPv6的钩子点的函数是注册在`nf_hooks_needed[NFPROTO_IPV6][x]`中的。而不是两种协议的钩子函数都注册在`nf_hooks_needed[NFPROTO_INET][x]`中。
conntrack、nat等模块可以向上面的五个钩子点注册钩子函数,对数据包进行处理。钩子函数的返回值如下:
> include/uapi/linux/netfilter.h
```
/* Responses from hook functions. */
#define NF_DROP 0
#define NF_ACCEPT 1
#define NF_STOLEN 2
#define NF_QUEUE 3
#define NF_REPEAT 4
#define NF_STOP 5
#define NF_MAX_VERDICT NF_STOP
```
上面返回值的含义可以参考[这里](http://www.hyuuhit.com/2018/07/15/netfilter/)
### **参考**
* https://blog.csdn.net/jasonchen_gbd/article/details/44873089
* https://blog.csdn.net/wenqian1991/article/details/50365689
* http://www.hyuuhit.com/2018/07/15/netfilter/
* http://wiki.dreamrunner.org/public_html/Linux/Networks/netfilter.html
- 应用层
- HTTP
- Cookie
- Session
- HTTP报文格式
- HTTP的Header字段
- HTTPS
- 简介
- 原理
- RSA加密与解密
- 证书签名与验证
- TLS双向认证
- openssl命令汇总
- DNS
- DNS的记录类型
- DNS的报文格式
- FAQ
- 传输层
- TCP
- CloseWait
- 网络层
- IPv6
- 链路层
- 链接层基础知识
- VLAN
- FAQ
- Linux网络收发包
- 网卡收包
- 网卡发包
- 收发包FAQ
- LVS
- 安装-DR模式
- 基本原理
- Ipvsadm命令
- Netfilter
- Netfilter简介
- 注册钩子函数
- Netfilter中数据包流向
- Iptables的数据结构
- 连接跟踪
- 初识连接跟踪
- 连接跟踪详解
- 连接跟踪数据结构
- 数据包与连接的状态
- NAT
- IPVS
- KubeProxy的IPVS模式
- Linux虚拟网络设备
- 虚拟网络设备简介
- Tap
- VethPair
- Vlan
- Vxlan
- Flannel的VXLAN原理
- Openstack的VXLAN原理
- VXLAN总结
- Bridge
- 给容器设置主机网段IP
- Macvlan
- Ipvlan
- IPIP
- IPIP使用介绍
- IPIP源码分析
- Limdiag网络
- 详细设计
- kubeovn
- IP命令
- Calico
- Calico常见问题
- ARP无响应
- 其他