1. netfilter框架

Netfilter 是Linux内核中进行数据包过滤、连接跟踪、地址转换等的主要实现框架。当我们希望过滤特定的数据包或者需要修改数据包的内容再发送出去,这些动作主要都在netfilter中完成。

iptables工具就是用户空间和内核的Netfilter模块通信的手段,iptables命令提供很多选项来实现过滤数据包的各种操作,所以,我们在定义数据包过滤规则时,并不需要去直接修改内核中的netfilter模块,后面会讲到iptables命令如何作用于内核中的netfilter。

Netfilter的实质就是定义一系列的hook点(挂钩),每个hook点上可以挂载多个hook函数,hook函数中就实现了我们要对数据包的内容做怎样的修改、以及要将数据包放行还是过滤掉。数据包进入netfilter框架后,实际上就是依次经过所有hook函数的处理,数据包的命运就掌握在这些hook函数的手里。

本文基于内核版本2.6.31。

所有的hook点都放在一个全局的二维数组,每个hook点上的hook函数按照优先级顺序注册到一个链表中,注册的接口为nf_register_hook()。这个二维数组的定义如下:

struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]__read_mostly;

其中NFPROTO_NUMPROTO 为netfilter支持的协议类型:

enum {NFPROTO_UNSPEC=  0,NFPROTO_IPV4   =  2,NFPROTO_ARP    =  3,NFPROTO_BRIDGE=  7,NFPROTO_IPV6   = 10,NFPROTO_DECNET= 12,NFPROTO_NUMPROTO,
};

我们看到枚举值并不连续,这是为了和协议族定义的值保持一致,因为注册hook函数的时候是根据协议族来注册的,如PF_INET=2,则对应的NFPROTO_IPV4=2。

NF_MAX_HOOKS是每种协议最多可挂的hook点的个数,它的值是8。如IPv4挂了5个,分别为:

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
};

也就是说,对于IPv4协议来讲,一共有5个hook点,这5个hook点上注册的hook函数放在下列链表中:

Hook点

该hook点上注册的hook函数链表的表头

NF_INET_PRE_ROUTING

nf_hooks[NFPROTO_IPV4][ NF_INET_PRE_ROUTING]

NF_INET_LOCAL_IN

nf_hooks[NFPROTO_IPV4][ NF_INET_LOCAL_IN]

NF_INET_FORWARD

nf_hooks[NFPROTO_IPV4][ NF_INET_FORWARD]

NF_INET_LOCAL_OUT

nf_hooks[NFPROTO_IPV4][ NF_INET_LOCAL_OUT]

NF_INET_POST_ROUTING

nf_hooks[NFPROTO_IPV4][ NF_INET_POST_ROUTING]

对于发往本地的数据包,会依次经过NF_INET_PRE_ROUTING和NF_INET_LOCAL_IN两个hook点的处理。

对于本地向外发出去的数据包,会依次经过NF_INET_LOCAL_OUT和NF_INET_POST_ROUTING两个hook点的处理。

对于经过本机转发的数据包,会依次经过F_INET_PRE_ROUTING、NF_INET_FORWARD和NF_INET_POST_ROUTING三个hook点的处理。

2. netfilter中的表

为了便于和用户态的iptables命令交互,引入了表的概念,iptables命令定义了各种规则,这些规则的目的就是对数据包进行过滤和处理。为了将规则分类,在内核中,用户设置的规则被放到了不同的表中。同时也方便管理和查找规则。

netfilter中的表存放在&init_net->xt.tables[NFPROTO_NUMPROTO]链表数组中,tables是一个list_head类型的链表,NFPROTO_NUMPROTO是一个枚举类型,包括各协议族,上面已经提到过。

可以看出每个协议有单独的链表来存放自己所有的netfilter的表,例如IPv4一共有5张表:

filter表:对数据包进行过滤。

NAT表:对数据包进行地址转换。

mangle表:主要用来修改数据包。

security表:用于实现强制访问控制安全模型。

raw表:其他各种用途。

常用的两个表就是filter表(用来进行数据包过滤)和NAT表(NAT转换规则以及作用于连接跟踪)。

而hook函数就是去遍历这些表中的规则,并根据这些规则去处理数据包。

这些表都是struct xt_table类型的。例如ipv4的netfilter表称为iptables,可以在&init_net ->ipv4中找到,如下:

struct xt_table  *iptable_filter;
struct xt_table *iptable_mangle;
struct xt_table *iptable_raw;
struct xt_table *arptable_filter;
struct xt_table *iptable_security;
struct xt_table *nat_table;

表结构的注册通过xt_register_table()函数完成,注册的表都放在&init_net ->xt.tables[]链表数组中。

而查找和执行表的规则是通过xxt_do_table()完成的,如ipt_do_table()、ip6t_do_table()、arpt_do_table()。

我们暂时只关心ipv4,通过ipt_do_table()函数的调用者我们可以看到哪些hook点会去查找哪些表:

caller

module

hook点

priority

table

ipt_local_in_hook

iptable filter

NF_INET_LOCAL_IN

NF_IP_PRI_FILTER

filter

ipt_hook

iptable filter

NF_INET_FORWARD

NF_IP_PRI_FILTER

filter

ipt_local_out_hook

iptable filter

NF_INET_LOCAL_OUT

NF_IP_PRI_FILTER

filter

ipt_pre_routing_hook

iptables mangle

NF_INET_PRE_ROUTING

NF_IP_PRI_MANGLE

mangle

ipt_local_in_hook

iptables mangle

NF_INET_LOCAL_IN

NF_IP_PRI_MANGLE

mangle

ipt_forward_hook

iptables mangle

NF_INET_FORWARD

NF_IP_PRI_MANGLE

mangle

ipt_local_hook

iptables mangle

NF_INET_LOCAL_OUT

NF_IP_PRI_MANGLE

mangle

ipt_post_routing_hook

iptables mangle

NF_INET_POST_ROUTING

NF_IP_PRI_MANGLE

mangle

ipt_local_in_hook

iptables security

NF_INET_LOCAL_IN

NF_IP_PRI_SECURITY

security

ipt_forward_hook

iptables security

NF_INET_FORWARD

NF_IP_PRI_SECURITY

security

ipt_local_out_hook

iptables security

NF_INET_LOCAL_OUT

NF_IP_PRI_SECURITY

security

ipt_hook

iptables raw

NF_INET_PRE_ROUTING

NF_IP_PRI_RAW

raw

ipt_local_hook

iptables raw

NF_INET_LOCAL_OUT

NF_IP_PRI_RAW

raw

nf_nat_rule_find

nat

NAT的4个hook点

NF_IP_PRI_NAT_DST/

NF_IP_PRI_NAT_SRC

nat

可以看到iptable有5张表:filter、mangle、security、raw和nat表。这些表中的规则可以通过用户态的iptables程序来配置,netfilter中的hook函数会去根据用户配置的iptables规则来处理数据包。

上图是IPv4协议中每个hook点上注册的hook函数(虚线框中的函数,按照箭头方向的优先级顺序被调用),注意,图中假设security/mangle/raw这三个表中没有规则,所以没有相应的hook函数。netfilter的入口点为ip_rcv()函数。图中有四种hook函数:

1. 紫色的两个函数用来对分片包进行重组。

2. 蓝色的四个函数用来实现数据包的连接跟踪(conntrack)模块。

3. 绿色的三个函数用来用来进行数据包的过滤(查找filter表中的规则)。

4. 粉色的四个函数用来实现NAT地址转换(查找NAT表中的规则)。

3. 遍历hook函数

上一节我们看到了每个hook点上都注册了哪些hook函数,每当数据包经过某个hook点时,netfilter就遍历这个hook上的所有hook函数来处理数据包。遍历的宏为:

NF_HOOK(pf, hook, skb, indev, outdev, okfn)

参数解释:

pf:协议族,如PF_INET对应IPv4。

hook:指明要遍历那个hook点,如NF_INET_PRE_ROUTING。

skb:待处理的数据包的sk_buff结构指针。

indev:数据包的来源设备。

outdev:数据包的目的去向设备。

okfn:函数指针。如果数据包成功走完hook点上的所有hook函数,接下来执行okfn函数,函数名一般名为xxx_finish。

NF_HOOK()调用nf_hook_slow()来执行遍历动作,其实现就是去遍历注册到nf_hooks[pf][hook]链表中的hook函数并执行,根据返回结果来决定数据包的去向。

hook函数返回值的说明:

  • NF_ACCEPT: 接受分组,使之穿过网络实现中剩余的协议层(或该hook点上后续的hook函数)。
  • NF_STOLEN: 挂钩函数窃取了一个分组,并处理了该分组,此时,该分组已与内核无关,不必再调用其他挂钩,还必须取消其他协议层的处理。
  • NF_DROP: 丢弃分组,其中的数据可以释放了。
  • NF_QUEUE: 将分组置于一个等待队列上,以便其数据可以由用户空间代码处理。不会执行其他hook函数。
  • NF_REPEAT: 再次调用该hook函数。

4. netfilter的一些补充

※.  每个hook代码都分为两部分,即hook函数和xx_finish()函数,这样做,是因为编译内核时可以选择不编译netfilter模块,xx_finish函数的内容是即使没有netfilter模块,内核也要必须对数据包做的事情。

※.  netfilter可以指定一个优先级,低于这个优先级的hook函数不被执行,nf_hook_thresh(..., int thresh, int cond)函数的thresh参数就是优先级。同时还可以通过cond参数(取0或1)更干脆的取消整个链的遍历。

※.  我们发现遍历hook的代码都放在函数的最后,如下面代码中的ip_forward_finish函数,

NF_HOOK(PF_INET, NF_INET_FORWARD, skb, skb->dev,rt->u.dst.dev, ip_forward_finish);

这样的话,ip_forward_finish函数即使不被声明为inline,其执行效率也挺高,因为GNU C有一个尾部过程调用的优化,省去了函数返回的开销。

※.  hook点NF_INET_PRE_ROUTING在协议收包时进入。而NF_INET_LOCAL_OUT在上层发包的时候进入,在ip_push_pending_frames(),ip_queue_xmit()和raw_send_hdrine()等函数会去走该hook点。

后面几篇文章会依次介绍netfilter中的连接跟踪和NAT模块,并分析用户态的iptables工具是如何作用于netfilter的,为了方便和netfilter交互,iptables工具中也有表(table)的概念,并将hook点称为链(chain)。

linux 内核 netfilter 网络过滤模块 (1)-框架相关推荐

  1. linux 内核 netfilter 网络过滤模块 (2)-conntrack

    连接跟踪(conntrack)用来跟踪和记录一个连接的状态,它为经过协议栈的数据包记录状态,这为防火墙检测连接状态提供了参考,同时在数据包需要做NAT时也为转换工作提供便利. 本文基于Linux内核2 ...

  2. linux 内核 netfilter 网络过滤模块 (5)-iptables

    iptables是用户态的配置工具,用于实现网络层的防火墙,用户可以通过iptables命令设置一系列的过滤规则,来截获特定的数据包并进行过滤或其他处理. iptables命令通过与内核中的netfi ...

  3. linux 内核 netfilter 网络过滤模块 (4)-期望连接

    传统的conntrack和NAT处理只对IP层和传输层头部进行转换处理,但是一些应用层协议,在协议数据报文中包含了地址信息.为了使得这些应用也能透明地完成NAT转换,NAT使用一种称作ALG的技术,它 ...

  4. linux 内核 netfilter 网络过滤模块 (3)-NAT

    本文对netfilter中NAT部分的源码进行分析,读者需要先对NAT的基本概念有一个大致了解. 1. NAT模块的初始化 NAT模块的初始化过程主要是初始化一些全局变量以及注册NAT相关的hook函 ...

  5. Linux内核:网络过滤器简介与示例代码

    目录 简单的例子 实施 用户空间处理 Linux的一大优点是其网络功能.路由器,交换机等许多网络产品均基于嵌入式Linux操作系统. 网络过滤是Linux内核中很好的基础结构,它使我们能够过滤和操作网 ...

  6. linux内核netfilter,linux内核netfilter实现url重定向

    原标题:linux内核netfilter实现url重定向 一.NetFilter NetFilter在2.4.x内核中引入,成为linux平台下进行网络应用的主要扩展,不仅包括防火墙的实现,还包括报文 ...

  7. Linux内核学习--内存管理模块

    Linux内核学习--内存管理模块 首先,Linux内核主要由五个部分组成,他们分别是:进程调度模块.内存管理模块.文件系统模块.进程间通信模块和网络接口模块. 本部分所讲的内存是内存管理模块,其主要 ...

  8. 解析Linux内核的基本的模块管理与时间管理操作---超时处理【转】

    转自:http://www.jb51.net/article/79960.htm 这篇文章主要介绍了Linux内核的基本的模块管理与时间管理操作,包括模块加载卸载函数的使用和定时器的用法等知识,需要的 ...

  9. linux 内核学习11-内核模块参数

    linux 内核学习11-内核模块参数 内核模块作为一个可拓展的动态模块,为Linux内核提供灵活性,所以需要依据不同的场景来传递不同的参数,实现不同的功能 1. 准备工作 #define modul ...

最新文章

  1. PCL显示法线no override found vtkactor
  2. 编码小记(未整理-持续更新)
  3. 【ES6】对象的拓展
  4. 【源资讯 第36期】赶超 Java 和 PHP,Python 成最热门编程语言?
  5. VTK:图片之ImageHistogram
  6. mac osx安装mysql5.7.9
  7. Linux开放21通信,linux下开启ftp的21号port
  8. SAP License:未分配差异的另类查询办法
  9. 转:C#读取PDF、TXT内容
  10. mac 使用vmware funsion 挂载cdlinux跑wifi字典经历
  11. java的代码大全_java代码大全
  12. 在Mac电脑的输入法中如何开启自动纠正模糊拼音功能?
  13. 关于U盘被写保护无法格式化的解决方法
  14. php实现pdf转图片
  15. Matlab中常用的统计量函数
  16. larval PHP artisan命令
  17. 使用 JavaScript 拦截和跟踪浏览器中的 HTTP 请求
  18. java软件工程师工作业绩_java软件工程师个人简历
  19. 邦纳超声波传感器T30UXDA
  20. 消息中间件合集:MQ(ActiveMQ/RabbitMQ/RocketMQ)+Kafka+笔记

热门文章

  1. 通过 vSphere WS API 获取 vCenter Datastore Provisioned Space 置备空间
  2. altium designer学习记录
  3. Makefile文件应用——huge项目
  4. 重磅:苹果人工智能最完整解密,iBrain早已无处不在
  5. 如何知道刚刚插入数据库那条数据的id
  6. UDP_CORK,TCP_CORK以及TCP_NODELAY
  7. [20170513]update结果集.txt
  8. github新建repositories后import已有code 随后同步更新
  9. Java自带的性能监测工具之jinfo
  10. c# 多线程排队队列实现的源码