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
  • NF_IP_PRE_ROUTING:数据包一进入协议栈即触发,在进行任何路由判断之前
  • NF_IP_LOCAL_IN:经过路由判断,如果数据包目的是本机,将触发该hook
  • NF_IP_FORWARD:经过路由判断,如果数据包目的是其他主机,将触发该hook转发
  • NF_IP_LOCAL_OUT:本机准备发送的数据包,在进入协议栈后触发该hook
  • NF_IP_POST_ROUTING:准备发出去的包或转发的包,经过路由判断后,离开网卡前的最后一个hook点
// 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在协议栈中的架构图

连接跟踪conntrack

  • conntracknetfilter实现的连接跟踪机制,是NATiptables状态匹配(-m state)的基础,conntrack依赖的内核模块为nf_conntrack
  • conntrack在内核中的位置有两处:PREROUTINGOUTPUT之前,进入主机的所有数据包会通过PREROUTING处的conntrack,主机本地进程产生的数据包对外发出时会通过OUTPUT处的conntrack。从netfilter协议栈架构图可以看出,conntrack所处的位置非常靠前,仅位于raw表之后,如果raw将数据包标记为NOTRACK,则conntrack不会跟踪该数据包连接。
  • conntrack通过连接跟踪表来维护所有的连接信息,当有数据包通过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维护的所有信息都包含在这个条目中,通过它就可以知道某个连接处于什么状态

  • 此连接使用ipv4协议,是一条tcp连接(tcp的协议类型代码是6)
  • 33是这条conntrack条目在当前时间点的生存时间(每个conntrack条目都会有生存时间,从设置值开始倒计时,倒计时完后此条目将被清除),可以使用sysctl -a |grep conntrack | grep timeout查看不同协议不同状态下生存时间设置值,当然这些设置值都可以调整,注意若后续有收到属于此连接的数据包,则此生存时间将被重置(重新从设置值开始倒计时),并且状态改变,生存时间设置值也会响应改为新状态的值
  • SYN_SENT是到此刻为止conntrack跟踪到的这个连接的状态(内核角度),SYN_SENT表示这个连接只在一个方向发送了一初始TCP SYN包,还未看到响应的SYN+ACK包(只有tcp才会有这个字段)。
  • src=172.16.200.119 dst=172.16.202.12 sport=54786 dport=10051是从数据包中提取的此连接的源目地址、源目端口,是conntrack首次看到此数据包时候的信息。
  • [UNREPLIED]说明此刻为止这个连接还没有收到任何响应,当一个连接已收到响应时,[UNREPLIED]标志就会被移除
  • 接下来的src=172.16.202.12 dst=172.16.200.119 sport=10051 dport=54786地址和端口和前面是相反的,这部分不是数据包中带有的信息,是conntrack填充的信息,代表conntrack希望收到的响应包信息。意思是若后续conntrack跟踪到某个数据包信息与此部分匹配,则此数据包就是此连接的响应数据包。注意这部分确定了conntrack如何判断响应包(tcp/udp),icmp是依据另外几个字段

连接跟踪表大小

连接跟踪表能够存放的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

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

  • 内核提取此数据包信息(源IP、源端口、目的IP、目的端口、协议号)进行hash计算得到hash值,在哈希表中以此hash值做索引进行查找,查找结果即为该数据包所属的bucket。这一步计算时间很短
  • 遍历对应的bucket,查找是否能匹配到conntrack条目。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等。

  • Filter Table:过滤功能,判断一个数据包是否应该放行
  • NAT Table:地址转换
  • Mangle Table:修改包的IP头,如TTL、服务类型
  • Raw Table:决定数据包是否被连接跟踪机制处理,对于不需要跟踪的数据包可以打上NOTRACK标签
  • Security Table:标记SELinux

iptables chain

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

  • PREROUTING: 由NF_IP_PRE_ROUTING 触发
  • INPUT: 由NF_IP_LOCAL_IN 触发
  • FORWARD: 由NF_IP_FORWARD 触发
  • OUTPUT: 由NF_IP_LOCAL_OUT 触发
  • POSTROUTING: 由NF_IP_POST_ROUTING 触发

chain的优先级:

  • 收到的目的为本机的包:PREROUTING->INPUT
  • 收到的目标为其他主机的包:PREROUTING->FORWARD->POSTROUTING
  • 本机产生准备发出的包:OUTPUT->POSTROUTING

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种状态:

  • NEW:新到达的包为合法包并且在连接跟踪表中关联不到,则为这个包创建一条新连接条目
  • ESTABLISHED:接收到的包为已有连接的响应包,则将NEW状态改为ESTABLISHED状态。对于TCP连接来说,就是跟SYN包对应的SYN/ACK包,对于UDP、ICMP来说就是与源相反的包
  • RELATED:接收到的包不属于已有连接,但是和已有连接存在一定的关系,称为辅助连接,例如 FTP 数据传输连接,或者是其他协议试图建立连接时的 ICMP 应答包
  • INVALID:包无法识别等原因,标记为非法
  • UNTRACKED:raw表中标记为NOTRACK

参考

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

Linux Netfilter框架分析的更多相关文章

  1. 【原创】Linux v4l2框架分析

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  2. Android/Linux Thermal框架分析及其Governor对比

    图表 1 Thermal框架 随着SoC性能的快速提升,功耗也极大提高,带来的负面影响是SoC的温度提高很快,甚至有可能造成物理损坏.同时功耗浪费也降低了电池寿命. 从上图可知,Thermal框架可以 ...

  3. 12.2 linux USB框架分析(详细注册match匹配过程)

     首先我们先来简单说一说USB的框架,之后在来具体分析源码,以便加深理解!其实USB的框架比较像“平台总线.设备.驱动”的框架,也分为总线.设备.驱动三大块.其中总线驱动是已经由内核完成的,一旦接入u ...

  4. Android/Linux下CGroup框架分析及其使用

    1 cgroup介绍 CGroup是control group的简称,它为Linux kernel提供一种任务聚集和划分的机制,可以限制.记录.隔离进程组(process groups)所使用的资源( ...

  5. linux内核netfilter模块分析之:HOOKs点的注册及调用

    转自;http://blog.csdn.net/suiyuan19840208/article/details/19684883 -1: 为什么要写这个东西?最近在找工作,之前netfilter 这一 ...

  6. Linux驱动:LCD驱动框架分析

    一直想花时间来整理一下Linux内核LCD驱动,却一直都忙着做其他事情去了,这些天特意抽出时间来整理之前落下的笔记,故事就这样开始了.LCD驱动也是字符设备驱动的一种,框架上相对于字符设备驱动稍微复杂 ...

  7. Linux USB驱动框架分析(2)【转】

    转自:http://blog.chinaunix.net/uid-23046336-id-3243543.html   看了http://blog.chinaunix.net/uid-11848011 ...

  8. Linux USB驱动框架分析 【转】

    转自:http://blog.chinaunix.net/uid-11848011-id-96188.html 初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结 ...

  9. linux驱动基础系列--linux spi驱动框架分析

    前言 主要是想对Linux 下spi驱动框架有一个整体的把控,因此会忽略某些细节,同时里面涉及到的一些驱动基础,比如平台驱动.设备模型等也不进行详细说明原理.如果有任何错误地方,请指出,谢谢! spi ...

随机推荐

  1. dpkg -S {file} #ubuntu 14.04 rpm -qf {file} #centos 7

    Linux查找命令或组件对应安装包的方法原创FJEagle 最后发布于2017-12-15 19:10:06 阅读数 4603 收藏展开Linux查找命令或组件对应安装包的方法当新搭建服务器或者维护不 ...

  2. docker部署harbor私有镜像库(3)

    一.harbor介绍 在实际生产运维中,往往需要把镜像发布到几十.上百台或更多的节点上.这时单台Docker主机上镜像已无法满足,项目越来越多,镜像就越来越多,都放到一台Docker主机上是不行的,我 ...

  3. OSI 七层参考模型与 TCP/IP 四层协议

    OSI 七层参考模型 OSI (Open System Interconnect,开放系统互连参考模型)是由 ISO(国际标准化组织)定义的,它是个灵活的.稳健的和可互操作的模型,并不是协议,常用来分 ...

  4. JavaEE 前后端分离以及优缺点

    前端概念 前端是一切直接与用户交互的页面或软件(用户看得见.摸得着)的统称,比如各种网站网页.andorid 手机各种 App.苹果手机各种 app.微信小程序.网络游戏客户端等.所以,普通人使用计算 ...

  5. 利用TortoiseGit向Github上传文件

    利用TortoiseGit向Github上传文件 第一步:建一个新文件夹,作为本地仓库 第二步:右键选择设置为版本库 若弹出,确认即可 重新打开改文件,会发现多了一个绿色的小勾 在文件夹中会自动生成一 ...

  6. android设置时钟

    <TextClock        android:id="@+id/timeText"        android:layout_width="match_pa ...

  7. 在vue中使用prismjs

    wqy的笔记:http://www.upwqy.com/details/261.html 作者:wqy 1 首先在项目中安装prismjs插件: cnpm install prismjs -S 2 安 ...

  8. Django(43)restful接口规范

    restful接口规范   什么是接口规范?接口规范就是为了采用不同的后台语言,也能使用同样的接口获取到同样的数据.如何写接口:接口规范是规范化书写接口的,写接口要写url.响应数据 ​  注:如果将 ...

  9. centOS 7-Hadoop3.3.0完全分布式部署

    本文内容不乏对各大佬的案例借鉴,侵删. 本次实验用到的有虚拟机,Xshell,Hadoop压缩包和jdk压缩包   hadoop111A:192.168.241.111 hadoop222B:192. ...

  10. GO学习-(9) Go语言基础之切片

    Go语言基础之切片 本文主要介绍Go语言中切片(slice)及它的基本使用. 引子 因为数组的长度是固定的并且数组长度属于类型的一部分,所以数组有很多的局限性. 例如: func arraySum(x ...