在连接跟踪子系统之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. 全“芯”关注用户需求 AMD“超轻薄笔记本”杀出重围
  2. clisp语言中的包
  3. 如何分析java程序_如何利用 JConsole观察分析Java程序的运行,进行排错调优
  4. [转] 《完美程式设计指南》Effective Delphi
  5. 011_Raphael常用方法
  6. iOS: bundle name, bundle display name, bundle identifier...
  7. 牛客-无形的博弈【结论题,快速幂】
  8. python装饰器应用论文_Python装饰器的应用场景代码总结
  9. 有关ArrayList的toArray()方法的一些探究
  10. 生成.o linux,JaxoDraw下载 费曼图生成工具JaxoDraw for linux v2.1.0 官方安装版 下载-脚本之家...
  11. Adobe AIR教程:ANE面向IAP的测试和开发
  12. 敲一下enter键,完成iOS的打包工作
  13. kubernetes Pod驱逐机制
  14. python读取csv某一列 pandas_numpy和pandas实战:文件夹CSV文件中的第一列数据
  15. close函数 qt_QT5笔记:关闭应用程序和窗口的函数
  16. flex java oracle_flex+eclipse+tomcat+lcds+jdk+oracle安装步骤和配置
  17. VLSM子网掩码详解!!
  18. 深度学习模型DNN部署到安卓设备上全流程示例——{pytorch->onnx>ncnn->Android studio}
  19. Python数据分析案例06——现代人的婚育意愿调查分析(基于逻辑回归模型和问卷数据)
  20. git push --force

热门文章

  1. 燃烧的远征java(二)-开发环境:eclipse 的使用技巧收集
  2. 测试用例之因果图分析法
  3. 【HTML】图片标签(img)
  4. python如何打开excel表格_python怎么读取excel表格
  5. python --通过urlretrieve下载MP4文件
  6. GAMS系列分享13——综合能源系统——包含储能的单能源枢纽模型
  7. win10和win8双系统安装
  8. matlab r2021b校园正版软件安装过程的问题及解决方案记录
  9. 用实例配置 linux squid 代理服务器
  10. 高级语言与低级语言如何定义?解释型语言和编译型语言又如何区别?