linux nf_conntrack 连接跟踪机制
PRE_ROUTING和LOCAL_OUT点可以看作是整个netfilter的入口,而POST_ROUTING和LOCAL_IN可以看作是其出口;
报文到本地:PRE_ROUTING----LOCAL_IN---本地进程
需要本机转发的数据包:PRE_ROUTING---FORWARD---POST_ROUTING---外出
从本机发出的数据包:LOCAL_OUT----POST_ROUTING---外出
数据包文到达内核协议栈时,使用sk_buff{}(即skb),其类型为struct nf_conntrack *;该结构记录了连接记录被公开应用的计数,也方便其他地方对连接跟踪的引用;
连接跟踪在实际应用中一般都通过强制类型转换将nfct转换成指向struct nf_conn { }类型;
同时:skb->nfctinfo 记录了该数据包的连接状态和该连接状态的相关信息;nfctinfo表示了每个数据包的几种连接状态;
Neftilter框架用struct nf_conn{ }来记录一个数据包与其连接的状态关系;
其中nfctinfo 取值有
- /* Connection state tracking for netfilter. This is separated from,
- but required by, the NAT layer; it can also be used by an iptables
- extension. */
- enum ip_conntrack_info {
- /* Part of an established connection (either direction).
- 已建立连接的一部分(任一方向) */
- IP_CT_ESTABLISHED,
- /* Like NEW, but related to an existing connection, or ICMP error
- (in either direction). */
- /* 已建立连接的关联连接,或者是ICMP错误(任一方向) */
- IP_CT_RELATED,
- /* Started a new connection to track (only
- IP_CT_DIR_ORIGINAL); may be a retransmission. */
- /* 开始一个新连接; 可能是重传 */
- IP_CT_NEW,
- /* >=这个值的都是响应方向的 */
- /* >= this indicates reply direction */
- IP_CT_IS_REPLY,
- /* 已建立连接的响应 */
- IP_CT_ESTABLISHED_REPLY = IP_CT_ESTABLISHED + IP_CT_IS_REPLY,
- /* 已建立连接的关联连接的响应 */
- IP_CT_RELATED_REPLY = IP_CT_RELATED + IP_CT_IS_REPLY,
- /* No NEW in reply direction. */
- /* IP_CT类型的数量 */
- /* Number of distinct IP_CT types. */
- IP_CT_NUMBER,
- /* only for userspace compatibility */
- #ifndef __KERNEL__
- IP_CT_NEW_REPLY = IP_CT_NUMBER,
- #endif
- };
在连接跟踪内部,收到的每个skb首先被转换成一个nf_conntrack_tuple{}结构,也就是说nf_conntrack_tuple{}结构才是连接跟踪系统所“认识”的数据包 ;
skb和ip_conntrack_tuple{}结构之间是如何转换的呢?
对于TCP/UDP协议,根据“源、目的IP+源、目的端口”再加序列号就可以唯一的标识一个数据包了;对于ICMP协议,根据“源、目的IP+类型+代号”再加序列号才可以唯一确定一个ICMP报文等等
nf_conntrack 数据结构
- /*
- struct sk_buff {
- struct nf_conntrack *nfct;//指向struct nf_conn实例
- ..............
- };
- */
- struct nf_conn {//每个struct nf_conn实例代表一个连接。每个skb都有一个指针,指向和它相关联的连接。
- /* Usage count in here is 1 for hash table/destruct timer, 1 per skb,
- * plus 1 for any connection(s) we are `master' for
- *
- * Hint, SKB address this struct and refcnt via skb->nfct and
- * helpers nf_conntrack_get() and nf_conntrack_put().
- * Helper nf_ct_put() equals nf_conntrack_put() by dec refcnt,
- * beware nf_ct_get() is different and don't inc refcnt.
- */
- struct nf_conntrack ct_general; //对连接的引用计数
- spinlock_t lock;
- u16 cpu;
- /* These are my tuples; original and reply */
- /* Connection tracking(链接跟踪)用来跟踪、记录每个链接的信息(目前仅支持IP协议的连接跟踪)。
- 每个链接由“tuple”来唯一标识,这里的“tuple”对不同的协议会有不同的含义,例如对tcp,udp
- 来说就是五元组: (源IP,源端口,目的IP, 目的端口,协议号),对ICMP协议来说是: (源IP, 目
- 的IP, id, type, code), 其中id,type与code都是icmp协议的信息。链接跟踪是防火墙实现状态检
- 测的基础,很多功能都需要借助链接跟踪才能实现,例如NAT、快速转发、等等。*/
- struct nf_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];//正向和反向的连接元组信息。
- /* 这是一个位图,是一个状态域。在实际的使用中,它通常与一个枚举类型ip_conntrack_status(位于include/linux/netfilter_ipv4/ip_conntrack.h,Line33)进行位运算来判断连接的状态。其中主要的状态包括:
- IPS_EXPECTED(_BIT),表示一个预期的连接
- IPS_SEEN_REPLY(_BIT),表示一个双向的连接
- IPS_ASSURED(_BIT),表示这个连接即使发生超时也不能提早被删除
- IPS_CONFIRMED(_BIT),表示这个连接已经被确认(初始包已经发出) */
- /* 可以设置由enum ip_conntrack_status中描述的状态 */
- /* Have we seen traffic both ways yet? (bitset) */
- unsigned long status;//该连接的连接状态
- /* Timer function; drops refcnt when it goes off. */
- struct timer_list timeout; //连接垃圾回收定时器 连接跟踪的超时时间
- possible_net_t ct_net;
- /* all members below initialized via memset */
- u8 __nfct_init_offset[0];
- /*结构ip_conntrack_expect位于ip_conntrack.h,这个结构用于将一个预期的连接分配给现有的连接,也就是说本连接是这个master的一个预期连接*/
- /* If we were expected by an expectation, this will be it */
- struct nf_conn *master;//如果该连接是期望连接,指向跟其关联的主连接
- #if defined(CONFIG_NF_CONNTRACK_MARK)
- u_int32_t mark;
- #endif
- #ifdef CONFIG_NF_CONNTRACK_SECMARK
- u_int32_t secmark;
- #endif
- /* Extensions */ /*指向扩展结构,该结构中包含一些基于连接的功能扩展处理函数 */
- struct nf_ct_ext *ext;
- /* Storage reserved for other modules, must be the last member */
- union nf_conntrack_proto proto; /*存储特定协议的连接跟踪信息 也就是不同协议实现连接跟踪的额外参数 */
- };
- //其中最主要的就是tuplehash(跟踪连接双方向数据)和status(记录连接状态)
- 在status中可以设置的标志,由下面的enum ip_conntrack_status描述,它们可以共存;
- /* Connection state tracking for netfilter. This is separated from,
- but required by, the NAT layer; it can also be used by an iptables
- extension. */
- enum ip_conntrack_info {
- /* Part of an established connection (either direction). 表示这个数据包对应的连接在两个方向都有数据包通过,
- 并且这是ORIGINAL初始方向数据包(无论是TCP、UDP、ICMP数据包,
- 只要在该连接的两个方向上已有数据包通过,就会将该连接设置为IP_CT_ESTABLISHED状态。不会根据协议中的标志位进行判断,
- 例如TCP的SYN等)。但它表示不了这是第几个数据包,也说明不了这个CT是否是子连接。*/
- IP_CT_ESTABLISHED,
- /* Like NEW, but related to an existing connection, or ICMP error
- (in either direction). 表示这个数据包对应的连接还没有REPLY方向数据包,当前数据包是ORIGINAL方向数据包。
- 并且这个连接关联一个已有的连接,是该已有连接的子连接,?
- 磗tatus标志中已经设置了IPS_EXPECTED标志,该标志在init_conntrack()函数中设置)。但无法
- 判断是第几个数据包(不一定是第一个)*/
- IP_CT_RELATED,
- /* Started a new connection to track (only
- IP_CT_DIR_ORIGINAL); may be a retransmission.
- 表示这个数据包对应的连接还没有REPLY方向数据包,当前数据包是ORIGINAL方向数据包,该连接不是子连接。但无法判断是
- 第几个数据包(不一定是第一个*/
- IP_CT_NEW,
- /* >= this indicates reply direction这个状态一般不单独使用,通常以下面两种方式使用 */
- IP_CT_IS_REPLY,
- /* 表示这个数据包对应的连接在两个方向都有数据包通过,并且这是REPLY应答方向数据包。但它表示不了这是
- 第几个数据包,也说明不了这个CT是否是子连接。*/
- IP_CT_ESTABLISHED_REPLY = IP_CT_ESTABLISHED + IP_CT_IS_REPLY,
- /*这个状态仅在nf_conntrack_attach()函数中设置,用于本机返回REJECT,例如返回一个ICMP目的不可达报文,
- 或返回一个reset报文。它表示不了这是第几个数据包
- */
- IP_CT_RELATED_REPLY = IP_CT_RELATED + IP_CT_IS_REPLY,
- /* No NEW in reply direction. */
- /* Number of distinct IP_CT types. */
- IP_CT_NUMBER,
- /* only for userspace compatibility */
- #ifndef __KERNEL__
- IP_CT_NEW_REPLY = IP_CT_NUMBER,
- #endif
- };
- #define NF_CT_STATE_INVALID_BIT (1 << 0)
- #define NF_CT_STATE_BIT(ctinfo) (1 << ((ctinfo) % IP_CT_IS_REPLY + 1))
- #define NF_CT_STATE_UNTRACKED_BIT (1 << (IP_CT_NUMBER + 1))
- /* Bitset representing status of connection. */
- enum ip_conntrack_status {
- /* It's an expected connection: bit 0 set. This bit never changed */
- IPS_EXPECTED_BIT = 0,//表示该连接是个子连接
- IPS_EXPECTED = (1 << IPS_EXPECTED_BIT),
- /* We've seen packets both ways: bit 1 set. Can be set, not unset. */
- IPS_SEEN_REPLY_BIT = 1,//表示该连接上双方向上都有数据包了
- IPS_SEEN_REPLY = (1 << IPS_SEEN_REPLY_BIT),
- /* Conntrack should never be early-expired.
- TCP:在三次握手建立完连接后即设定该标志。UDP:如果在该连接上的两个方向都有数据包通过,则再有数据包在该连接上通过时?
- 就设定该标志。ICMP:不设置该标志
- */
- IPS_ASSURED_BIT = 2,
- IPS_ASSURED = (1 << IPS_ASSURED_BIT),
- /* Connection is confirmed: originating packet has left box
- 表示该连接已被添加到net->ct.hash表*/
- IPS_CONFIRMED_BIT = 3,
- IPS_CONFIRMED = (1 << IPS_CONFIRMED_BIT),
- /* Connection needs src nat in orig dir. This bit never changed.
- 在POSTROUTING处,当替换reply tuple完成时, 设置该标记*/
- IPS_SRC_NAT_BIT = 4,
- IPS_SRC_NAT = (1 << IPS_SRC_NAT_BIT),
- /* Connection needs dst nat in orig dir. This bit never changed.
- 在PREROUTING处,当替换reply tuple完成时, 设置该标记*/
- IPS_DST_NAT_BIT = 5,
- IPS_DST_NAT = (1 << IPS_DST_NAT_BIT),
- /* Both together. */
- IPS_NAT_MASK = (IPS_DST_NAT | IPS_SRC_NAT),
- /* Connection needs TCP sequence adjusted. */
- IPS_SEQ_ADJUST_BIT = 6,
- IPS_SEQ_ADJUST = (1 << IPS_SEQ_ADJUST_BIT),
- /* NAT initialization bits. 在POSTROUTING处,已被SNAT处理,并被加入到bysource链中,设置该标记*/
- IPS_SRC_NAT_DONE_BIT = 7,
- IPS_SRC_NAT_DONE = (1 << IPS_SRC_NAT_DONE_BIT),
- IPS_DST_NAT_DONE_BIT = 8,//在PREROUTING处,已被DNAT处理,并被加入到bysource链中,设置该标记
- IPS_DST_NAT_DONE = (1 << IPS_DST_NAT_DONE_BIT),
- /* Both together */
- IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE | IPS_SRC_NAT_DONE),
- /* Connection is dying (removed from lists), can not be unset.
- 表示该连接正在被释放,内核通过该标志保证正在被释放的ct不会被其它地方再次引用。有了这个标志,当某个连接要被删
- 除时,即使它还在net->ct.hash中,也不会再次被引 用*/
- IPS_DYING_BIT = 9,
- IPS_DYING = (1 << IPS_DYING_BIT),
- /* Connection has fixed timeout.
- 固定连接超时时间,这将不根据状态修改连接超时时间。通过函数nf_ct_refresh_acct()修改超时时间时检查该标志*/
- IPS_FIXED_TIMEOUT_BIT = 10,
- IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT),
- /* Conntrack is a template
- 由CT target进行设置(这个target只能用在raw表中,用于为数据包构建指定ct,并打上该标志),用于表明这个ct是由CT target创建*/
- IPS_TEMPLATE_BIT = 11,
- IPS_TEMPLATE = (1 << IPS_TEMPLATE_BIT),
- /* Conntrack is a fake untracked entry */
- IPS_UNTRACKED_BIT = 12,
- IPS_UNTRACKED = (1 << IPS_UNTRACKED_BIT),
- /* Conntrack got a helper explicitly attached via CT target. */
- IPS_HELPER_BIT = 13,
- IPS_HELPER = (1 << IPS_HELPER_BIT),
- };
- /* Connections have two entries in the hash table: one for each way */
- struct nf_conntrack_tuple_hash {
- struct hlist_nulls_node hnnode;
- struct nf_conntrack_tuple tuple;
- };
- nf_ct_ext用于实现对连接跟踪的扩展;
- /* Extensions: optional stuff which isn't permanently in struct. */
- struct nf_ct_ext {
- struct rcu_head rcu;
- u16 offset[NF_CT_EXT_NUM];
- u16 len;
- char data[0];
- };
nf_conntrack_tuple 的分析:
- /* The protocol-specific manipulable parts of the tuple: always in
- * network order
- */
- union nf_conntrack_man_proto {
- /* Add other protocols here. */
- __be16 all;
- struct {
- __be16 port;
- } tcp;
- struct {
- __be16 port;
- } udp;
- struct {
- __be16 id;
- } icmp;
- struct {
- __be16 port;
- } dccp;
- struct {
- __be16 port;
- } sctp;
- struct {
- __be16 key; /* GRE key is 32bit, PPtP only uses 16bit */
- } gre;
- };
- /* The manipulable part of the tuple. */
- struct nf_conntrack_man {
- union nf_inet_addr u3; /* 三层识别信息 */
- union nf_conntrack_man_proto u;/* 四层识别信息 */
- /* Layer 3 protocol 三层协议号 */
- u_int16_t l3num;
- };
- /* This contains the information to distinguish a connection.
- 该结构包含源目的信息用来区分一条连接 */
- struct nf_conntrack_tuple {
- struct nf_conntrack_man src;/* 源, */
- /* These are the parts of the tuple which are fixed. */
- struct { /* 目的,不可操作? */
- union nf_inet_addr u3;
- union {
- /* Add other protocols here. */
- __be16 all;
- struct {
- __be16 port;
- } tcp;
- struct {
- __be16 port;
- } udp;
- struct {
- u_int8_t type, code;
- } icmp;
- struct {
- __be16 port;
- } dccp;
- struct {
- __be16 port;
- } sctp;
- struct {
- __be16 key;
- } gre;
- } u;
- /* The protocol. 协议*/
- u_int8_t protonum;
- /* The direction (for tuplehash) */ /* 方向(tuplehash使用) */
- u_int8_t dir;
- } dst;
- };
Netfilter将每一个数据包转换成tuple,再根据tuple计算出hash值,这样,就可以使用nf_conntrack_hash[hash_id]找到hash表中链表的入口,并组织链表
linux nf_conntrack 连接跟踪机制的更多相关文章
- linux nf_conntrack 连接跟踪机制 3-hook
conntrack hook函数分析 enum nf_ip_hook_priorities { NF_IP_PRI_FIRST = INT_MIN, NF_IP_PRI_CONNTRACK_DEFRA ...
- linux nf_conntrack 连接跟踪机制 2
连接跟踪初始化 基础参数的初始化:nf_conntrack_standalone_init 会调用nf_conntrack_init_start 完成连接跟踪基础参数的初始化, hash slab 扩 ...
- Netfilter&iptables:如何理解连接跟踪机制?
如何理解Netfilter中的连接跟踪机制? 本篇我打算以一个问句开头,因为在知识探索的道路上只有多问然后充分调动起思考的机器才能让自己走得更远.连接跟踪定义很简单:用来记录和跟踪连接的状态. 问:为 ...
- Netfilter之连接跟踪实现机制初步分析
Netfilter之连接跟踪实现机制初步分析 原文: http://blog.chinaunix.net/uid-22227409-id-2656910.html 什么是连接跟踪 连接跟踪(CONNT ...
- [转]nf_conntrack: table full, dropping packet 连接跟踪表已满,开始丢包 的解决办法
nf_conntrack: table full, dropping packet 连接跟踪表已满,开始丢包 的解决办法 中午业务说机器不能登录,我通过USM管理界面登录单板的时候发现机器没有僵 ...
- linux内核netfilter连接跟踪的hash算法
linux内核netfilter连接跟踪的hash算法 linux内核中的netfilter是一款强大的基于状态的防火墙,具有连接跟踪(conntrack)的实现.conntrack是netfilte ...
- linux下epoll实现机制
linux下epoll实现机制 原作者:陶辉 链接:http://blog.csdn.net/russell_tao/article/details/7160071 先简单回顾下如何使用C库封装的se ...
- Linux信号(signal) 机制分析
Linux信号(signal) 机制分析 [摘要]本文分析了Linux内核对于信号的实现机制和应用层的相关处理.首先介绍了软中断信号的本质及信号的两种不同分类方法尤其是不可靠信号的原理.接着分析了内核 ...
- 2017-2018-1 20155222 《信息安全系统设计基础》第10周 Linux下的IPC机制
2017-2018-1 20155222 <信息安全系统设计基础>第10周 Linux下的IPC机制 IPC机制 在linux下的多个进程间的通信机制叫做IPC(Inter-Process ...
随机推荐
- CSS精灵图与字体图标
CSS精灵图与字体图标 1. 精灵图 当用户访问一个网站时,需要向服务器发送请求,网页上的每张图像都要经过一次请求才能展现给用户.然而,一个网页中往往会应用很多小的背景图像作为修饰,当网页中的图像过多 ...
- spring-boot-route(十六)使用logback生产日志文件
日志是一个系统非常重要的一部分,我们经常需要通过查看日志来定位问题,今天我们一起来学习一下Spring Boot的日志系统.有很多同学习惯性的在生产代码中使用System.out来输出日志,这是不推荐 ...
- day28 Pyhton 面向对象 继承
1.昨日回顾 类的命名空间 静态属性\动态属性(方法) 对象的命名空间 #对象的属性 #类指针:对象能够通过这个类指针找到类 #静态属性:属于类,多个对象共享这个资源 #尽量用类名来操作静态属性 #对 ...
- keccak和sha3的区别
keccak应用 在以太坊中,用keccak哈希算法来计算公钥的256位哈希,再截取这256位哈希的后160位哈希作为地址值. keccak和sha3的区别 sha3由keccak标准化而来,在很多场 ...
- 三色二叉树 ---伪树形dp
题目描述 一棵二叉树可以按照如下规则表示成一个由0.1.2组成的字符序列,我们称之为"二叉树序列S": 0 该树没有子节点 1S1 该树有一个子节点,S1为其二叉树序列 1S1S2 ...
- centos8平台使用journalctl管理systemd-journald日志
一,systemd-journald的作用 1,什么是systemd-journald? systemd-journald 是 systemd 自带的日志系统,是一个收集并存储各类日志数据的系统服务. ...
- vue知识点16
1. 数组用下标改变,或者对象增加属性,这样的改变数据 是不能触发视图更新的,要用 Vue.set(对象,属性,值) 或this.$set(对象,属性,值) 2. this.$forceUpdat ...
- Anderson《空气动力学基础》5th读书笔记 第3记——流动类型
一.连续介质与自由分子流动 分子之间相互碰撞的平均距离定义为平均自由程 .如果平均自由程的数量级远小于飞行器的尺寸时,此时,分子对物体的碰撞如此频繁以至于物体无法分辨出单个的分子碰撞,这时,对物体 ...
- C++学习---单链表的构建及操作
#include <iostream> using namespace std; typedef struct LinkNode { int elem;//节点中的数据 struct Li ...
- 一文秒懂!Python字符串格式化之format方法详解
format是字符串内嵌的一个方法,用于格式化字符串.以大括号{}来标明被替换的字符串,一定程度上与%目的一致.但在某些方面更加的方便 1.基本用法 1.按照{}的顺序依次匹配括号中的值 s = &q ...