在连接跟踪子系统之AF_INET协议族钩子函数
中有看到,在连接跟踪子系统的出口,第一个钩子是ipv4_conntrack_help()(以AF_INET协议族为例),之后才是对新连接的确认钩子。并且help钩子的逻辑就是调用连接跟踪信息块中的help()回调函数。这篇笔记就来看看连接跟踪子系统对helper的管理,相关代码文件为:

代码路径 说明
net/netfilter/nf_conntrack_helper.c helper框架管理实现文件
include/net/netfilter/nf_conntrack_helper.h helper头文件

1. helper定义

协议是否需要实现helper是可选的,如果需要实现,那么协议需要首先实例化struct nf_conntrack_helper对象,然后将其注册到系统中才行。helper定义如下:

struct nf_conntrack_helper
{struct hlist_node hnode;   /* Internal use. *///每个helper模块可以有一个名字const char *name;     /* name of the module */struct module *me;      /* pointer to self *///一个连接允许同时存在的最大期望连接数unsigned int max_expected;//属于该helper的期望连接的保活定时器超时时间unsigned int timeout;/* Tuple of things we will help (compared against server response) *///指明helper模块关心什么样的数据包。该字段很关键,它决定了新连接建立时//能否匹配到该helper对象struct nf_conntrack_tuple tuple;/* Function to call when data passes; return verdict, or -1 to invalidate. *///help()回调int (*help)(struct sk_buff *skb, unsigned int protoff,struct nf_conn *ct, enum ip_conntrack_info conntrackinfo);void (*destroy)(struct nf_conn *ct);int (*to_nlattr)(struct sk_buff *skb, const struct nf_conn *ct);
};

从helper对象的定义来看,helper和期望连接是紧密相关的。

此外,helper会使用连接跟踪的扩展部分,扩展部分保存的实际上是sturct nf_conn_help,该结构定义如下:

//当前内核版本有如下4个用户使用helper
union nf_conntrack_help {/* insert conntrack helper private data (master) here */struct nf_ct_ftp_master ct_ftp_info;struct nf_ct_pptp_master ct_pptp_info;struct nf_ct_h323_master ct_h323_info;struct nf_ct_sane_master ct_sane_info;
};
/* nf_conn feature for connections that have a helper */
struct nf_conn_help {//指向创建该扩展的helperstruct nf_conntrack_helper *helper;//help私有信息union nf_conntrack_help help;//一个连接可以用多个期望连接,这些同属一个连接的期望连接被组织成一个链表struct hlist_head expectations;//expectations链表的长度unsigned int expecting;
};

2. helper子模块初始化

helper是连接跟踪子系统必备的一个子模块,它在连接跟踪子系统的初始化过程中被初始化。

static DEFINE_MUTEX(nf_ct_helper_mutex);
static struct hlist_head *nf_ct_helper_hash __read_mostly;
//哈希桶大小
static unsigned int nf_ct_helper_hsize __read_mostly;
//哈希表中已保存helper对象的个数
static unsigned int nf_ct_helper_count __read_mostly;
static int nf_ct_helper_vmalloc;
//对于help类型扩展,连接跟踪信息块的扩展字段中真正保存的的struct nf_conn_help
static struct nf_ct_ext_type helper_extend __read_mostly = {.len   = sizeof(struct nf_conn_help),.align   = __alignof__(struct nf_conn_help),.id = NF_CT_EXT_HELPER,
};int nf_conntrack_helper_init(void)
{int err;//分配一个哈希表用于保存注册的helper模块nf_ct_helper_hsize = 1; /* gets rounded up to use one page */nf_ct_helper_hash = nf_ct_alloc_hashtable(&nf_ct_helper_hsize, &nf_ct_helper_vmalloc);if (!nf_ct_helper_hash)return -ENOMEM;//helper需要使用连接跟踪信息块的扩展字段,该扩展字段的实际内容由各个使用扩展的模块决定,//所以这里需要先注册一个扩展err = nf_ct_extend_register(&helper_extend);if (err < 0)goto err1;return 0;
...
}

对于扩展,见笔记连接跟踪子系统之extend,其中有以helper为例介绍的扩展的注册。

注意:helper子模块负责的是管理系统中所有已经注册的helper,为ftp这类用户使用helper提供便利,它本身并不注册任何的helper对象。

3. helper的注册

连接跟踪子系统对于helper提供的是一种框架上的支持,它仅仅是管理系统中已注册的helper对象,并且为helper在Netfilter中发挥作用提供一种执行机制,具体每个helper模块干些什么,框架并不操心。

所以,如果有协议要使用helper,必须先向连接跟踪子系统注册一个struct nf_conntrack_helper对象,通过该对象,说明自己想要处理的数据包(tuple成员)类型、以及匹配到该数据包后需要执行的help()回调。

int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
{//根据tuple计算哈希值unsigned int h = helper_hash(&me->tuple);BUG_ON(me->timeout == 0);//将helper模块添加到全局的哈希表中并递增已注册helper模块的个数mutex_lock(&nf_ct_helper_mutex);hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]);nf_ct_helper_count++;mutex_unlock(&nf_ct_helper_mutex);return 0;
}
EXPORT_SYMBOL_GPL(nf_conntrack_helper_register);

去注册是相反的操作,只不过它需要做更多的同步与检查工作,因为去注册时,当前可能有连接正在使用该helper模块,所以需要同步这些连接的状态。

4. helper的查找

在连接跟踪子系统之核心实现中有看到,连接跟踪子系统在检测到一个新的连接时,会通过调用init_conntrack()为其创建连接跟踪信息块。之前的博客并没有仔细分析其中关于期望连接和helper相关的处理逻辑,这里我们重点来看helper的处理,期望连接的处理见连接跟踪子系统之期望连接。

4.1 init_conntrack()

/* Allocate a new conntrack: we return -ENOMEM if classificationfailed due to stress.  Otherwise it really is unclassifiable. */
static struct nf_conntrack_tuple_hash * init_conntrack(const struct nf_conntrack_tuple *tuple,struct nf_conntrack_l3proto *l3proto, struct nf_conntrack_l4proto *l4proto,struct sk_buff *skb, unsigned int dataoff)
{struct nf_conn *ct;struct nf_conn_help *help;struct nf_conntrack_tuple repl_tuple;struct nf_conntrack_expect *exp;
...spin_lock_bh(&nf_conntrack_lock);//根据skb的tuple搜索期望连接链表,检查该新的连接是否是某个已有连接的期望连接exp = nf_ct_find_expectation(tuple);if (exp) {//新连接时某个连接的期望连接,见笔记"连接跟踪子系统之期望连接"...} else {//没有找到期望连接,检查系统中是否有helper模块想处理这种连接,//为什么这里要用Reply方向的tuple查找helper呢?struct nf_conntrack_helper *helper;//这里为什么是使用repl_tuple来查找helper,不理解!!!helper = __nf_ct_helper_find(&repl_tuple);if (helper) {//找到了处理该连接的helper对象,那么在连接信息块的扩展字段中添加一个help类型的扩展,//help类型的扩展的实际类型是struct nf_conn_help,这里返回分配的help对象,然后建//立help和helper之间的关系,因为通过连接跟踪信息块能够拿到的实际上是help对象help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);if (help)rcu_assign_pointer(help->helper, helper);}NF_CT_STAT_INC(new);}
...
}

4.2 查找helper:__nf_ct_helper_find()

根据参数指定的tuple,查找全局的helper哈希表nf_ct_helper_hash,返回对应的helper对象。

struct nf_conntrack_helper * __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple)
{struct nf_conntrack_helper *helper;struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) };struct hlist_node *n;unsigned int h;//如果当前系统中根本就没有注册的helper,当然也就没有helper对该连接感兴趣了if (!nf_ct_helper_count)return NULL;//根据tuple计算hash值h = helper_hash(tuple);//遍历哈希表中h对应的冲突链,寻找helper->tuple与入参tuple一致的helperhlist_for_each_entry_rcu(helper, n, &nf_ct_helper_hash[h], hnode) {//匹配原则就是检查L3协议地址、L3协议号、L4协议地址是否相等if (nf_ct_tuple_src_mask_cmp(tuple, &helper->tuple, &mask))return helper;}return NULL;
}
EXPORT_SYMBOL_GPL(__nf_ct_helper_find);

4.3 添加help扩展: nf_ct_helper_ext_add()

struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp)
{struct nf_conn_help *help;//调用extend子模块的接口添加一个help类型的扩展,见"连接跟踪子系统之extend"help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, gfp);if (help)INIT_HLIST_HEAD(&help->expectations);elsepr_debug("failed to add helper extension area");return help;
}
EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add);

5. help()回调的调用

以AF_INET协议族的help钩子函数为例,来看看help()回调函数是如何被执行的。help钩子以较低优先级工作在连接跟踪子系统的出口处。

static unsigned int ipv4_conntrack_help(unsigned int hooknum, struct sk_buff *skb,const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))
{struct nf_conn *ct;enum ip_conntrack_info ctinfo;const struct nf_conn_help *help;const struct nf_conntrack_helper *helper;//在入口处,skb应该已经找到了它的连接跟踪信息块ct = nf_ct_get(skb, &ctinfo);//没有ct,说明该skb没有被跟踪。或者skb属于一个特殊状态(不理解何时会是这个状态)。//这两种情况,不会对该skb执行help()回调if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)return NF_ACCEPT;//获取skb的help信息,该信息在连接跟踪的入口处就已经指定了(如果有的话)help = nfct_help(ct);if (!help)return NF_ACCEPT;/* rcu_read_lock()ed by nf_hook_slow */helper = rcu_dereference(help->helper);if (!helper)return NF_ACCEPT;//执行help()回调,回调函数的返回值将作为给Netfilter框架的返回值return helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb), ct, ctinfo);
}

连接跟踪子系统之helper相关推荐

  1. linux内核协议栈 netfilter 之连接跟踪子系统的L3 L4协议栈模块初始化与自定义注册

    目录 1 L3.L4协议跟踪初始化 nf_conntrack_proto_init() 1.1 L3协议管理 1.1.1 struct nf_conntrack_l3proto 1.1.2 L3协议注 ...

  2. linux 连接跟踪nf_conntrack 与 NAT和状态防火墙

    本文主要记录对于连接跟踪以及其主要应用的NAT和状态iptables的学习内容 连接跟踪 什么是连接跟踪? 连接跟踪是Linux内核中引入的nf_conntrack 模块所实现的功能,同时支持IPv4 ...

  3. netfilter连接跟踪(conntrack)详述

    1 连接跟踪来龙去脉 1.1 什么是连接跟踪 连接跟踪顾名思义是对网络连接跟踪,如果将网络比作 高速路 ,连接跟踪就像是高速路里的路上的检查站.摄像头一起的组合,可以记录下你在什么地方进的高速.什么地 ...

  4. linux进行端口跟踪,(五)洞悉linux下的Netfilteriptables:如何理解连接跟踪机制?【上】...

    其实PRE_ROUTING和LOCAL_OUT点可以看作是整个netfilter的入口,而POST_ROUTING和LOCAL_IN可以看作是其出口.在只考虑连接跟踪的情况下,一个数据包无外乎有以下三 ...

  5. 连接跟踪(connection tracking,conntrack,CT)

    连接跟踪(connection tracking,conntrack,CT) 原文连接:http://arthurchiao.art/blog/conntrack-design-and-impleme ...

  6. Linux nf_conntrack连接跟踪的实现

    连接跟踪,顾名思义,就是识别一个连接上双方向的数据包,同时记录状态.下面看一下它的数据结构: struct nf_conn {         /* Usage count in here is 1 ...

  7. linux视频教程 iptables 跟踪,linux – 了解iptables中的连接跟踪

    我在对iptables中的状态/连接跟踪做了一些澄清. >这两条规则有什么区别? iptables -A FORWARD -m state –state ESTABLISHED,RELATED ...

  8. TCP流嗅探和连接跟踪工具tcpick

    TCP流嗅探和连接跟踪工具tcpick 由于网络通信协议众多,TCP连接状态众多,所以TCP分析较为复杂.Kali Linux提供一款专用工具tcpick.该工具支持在线实时嗅探和离线文件嗅探.它可以 ...

  9. Linux Kernel TCP/IP Stack — L3 Layer — netfilter 框架 — conntrack(CT,连接跟踪)

    目录 文章目录 目录 CT CT CT(conntrack,connection tracking,连接跟踪),顾名思义,就是跟踪(并记录)连接的状态,是许多网络应用的基础.例如:iptables.L ...

  10. linux conntrack命令 路由连接 跟踪表 显示删除监听记录

    conntrack命令可以显示,删除和更新跟踪表现有状态条目,还可以监听流事件 1.安装: yum install -y conntrack 2.使用: 查看conntrack表记录 conntrac ...

最新文章

  1. linux下jboss的安装配置
  2. K-近邻算法之案例2:预测facebook签到位置
  3. iOS开发之自定义View的一些坑
  4. python程序员面试宝典 勘误_《前端面试江湖》勘误合集(二)
  5. latex sr 中一些对齐和表格问题及总结
  6. creo导入特征怎么实体化_Creo/Proe云图抄数牙刷抄数造型
  7. json java typeof_Json对象与Json字符串的转化、JSON字符串与Java对象的转换
  8. Xenserver console界面无法查看虚拟机的信息
  9. 3dmax 对模型做bool运算
  10. 偏微分方程数值解法pdf_天生一对,硬核微分方程与深度学习的联姻之路
  11. 优科无线并购Wi-Fi入网软件提供商Cloudpath Networks
  12. 在ABBYY FineReader中制作屏幕截图和识别文本
  13. 立方度量(Cubic Metric)
  14. 支付宝企业账户单笔支付到个人账户
  15. iOS开发小记:初次接入环信SDK3.0时遇到的问题及解决办法汇总
  16. Leetcode Day1---双指针法 || 27移除元素、977. 有序数组的平方、209. 长度最小的子数组
  17. 中国天气网天气预报API接口城市代码(XML格式,信息全)
  18. 四川大学c语言实验报告,四川大学-C语言程序设计精品课程申报网站
  19. python语法格式
  20. 随机过程| 特征函数篇

热门文章

  1. ewebeditor编辑器解析漏洞
  2. 基于C#的AE二次开发之GP工具的使用心得
  3. 自己动手编译NodeMCU固件
  4. 数据结构——克鲁斯卡尔(Kruskal)算法
  5. 在SQL Server 2000里设置和使用数据库复制
  6. 为什么需要等待2MSL
  7. 怎么清理c盘语言文件,怎么清理c盘空间 c盘空间不足
  8. 2017腾讯暑期实习生从笔试到面试总结(附带华为、阿里面试经历)
  9. quicktime for java,QuickTime是什么意思
  10. 山寨芯片大鳄终于来了MTK6577 A9双核全功能通讯平板(2012年芯片,低端以A9双核为代表)