Linux netfilter源码分析(7)
七、 target 匹配
7.1 ipt_target和ipt_entry_target结构 ip_tables.h
ipt_target和ipt_match结构类似:
struct ipt_target
{
struct list_head list;
const char name[IPT_FUNCTION_MAXNAMELEN];
/* 在使用本Match的规则注入表中之前调用,进行有效性检查,如果返回0,规则就不会加入iptables中 */
int (*checkentry)(const char *tablename,
const struct ipt_entry *e,
void *targinfo,
unsigned int targinfosize,
unsigned int hook_mask);
/* 在包含本Target的规则从表中删除时调用,与checkentry配合可用于动态内存分配和释放 */
void (*destroy)(void *targinfo, unsigned int targinfosize);
/* target的模块函数,如果需要继续处理则返回IPT_CONTINUE(-1),否则返回NF_ACCEPT、NF_DROP等值,它的调用者根据它的返回值来判断如何处理它处理过的报文*/
unsigned int (*target)(struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const void *targinfo,
void *userdata);
/* 表示当前Target是否为模块(NULL为否) */
struct module *me;
};
ipt_entry_target和ipt_entry_match也几乎一模一样:
struct ipt_entry_target
{
union {
struct {
u_int16_t target_size;
char name[IPT_FUNCTION_MAXNAMELEN];
} user;
struct {
u_int16_t target_size;
struct ipt_target *target;
} kernel;
u_int16_t target_size;
} u;
unsigned char data[0];
};
看上去target和match好像没有区别,但当然,一个是条件,一个是动作,接着往下看是不是真的一样
之前有两个地方出现了ipt_target,一次是在ipt_do_table()函数里,当匹配到match后开始匹配target,另一次是在check_entry()里,检查完match后开始检查target
先看前一个
7.2 ipt_standard_target结构 ip_tables.h
再看一次ipt_do_table这个函数,前面匹配match的部分略过,从匹配match成功的地方开始:
ipt_do_table( )
{
……… /* 略去 */
if (ip_packet_match(ip, indev, outdev, &e->ip, offset)) {
struct ipt_entry_target *t;
if (IPT_MATCH_ITERATE(e, do_match,
*pskb, in, out,
offset, &hotdrop) != 0)
goto no_match;
/* 这里开始说明匹配match成功了,开始匹配target */
ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1);
/* ipt_get_target获取当前target,t是一个ipt_entry_target结构,这个函数就是简单的返回e+e->target_offset
每个entry只有一个target,所以不需要像match一样遍历,直接指针指过去了*/
t = ipt_get_target(e);
IP_NF_ASSERT(t->u.kernel.target);
/* 这里都还是和扩展的match的匹配很像,但是下面一句
有句注释:Standard target? 判断当前target是否标准的target?
而判断的条件是u.kernel.target->target,就是ipt_target结构里的target函数是否为空,而下面还出现了ipt_standard_target结构和verdict变量,好吧,先停下,看看ipt_standard_target结构再说 */
if (!t->u.kernel.target->target) {
int v;
v = ((struct ipt_standard_target *)t)->verdict;
if (v < 0) {
…… /* 略去 */
}
ipt_standard_target的定义:
struct ipt_standard_target
{
struct ipt_entry_target target;
int verdict;
};
也就比ipt_entry_target多了一个verdict(判断),请看前面的nf_hook_slow()函数,里面也有verdict变量,用来保存hook函数的返回值,常见的有这些
#define NF_DROP 0
#define NF_ACCEPT 1
#define NF_STOLEN 2
#define NF_QUEUE 3
#define NF_REPEAT 4
#define RETURN IPT_RETURN
#define IPT_RETURN (-NF_MAX_VERDICT - 1)
#define NF_MAX_VERDICT NF_REPEAT
我们知道chain(链)是某个检查点上检查的规则的集合。除了默认的chain外,用户还可以创建新的chain。在iptables中,同一个chain里的规则是连续存放的。默认的chain的最后一条规则的target是chain的policy。用户创建的chain的最后一条规则的target的调用返回值是NF_RETURN,遍历过程将返回原来的chain。规则中的target也可以指定跳转到某个用户创建的chain上,这时它的target是ipt_stardard_target,并且这个target的verdict值大于0。如果在用户创建的chain上没有找到匹配的规则,遍历过程将返回到原来chain的下一条规则上。
事实上,target也是分标准的和扩展的,但前面说了,毕竟一个是条件,一个是动作,target的标准和扩展的关系和match还是不太一样的,不能一概而论,而且在标准的target里还可以根据verdict的值再划分为内建的动作或者跳转到自定义链
简单的说,标准target就是内核内建的一些处理动作或其延伸
扩展的当然就是完全由用户定义的处理动作
再看if (!t->u.kernel.target->target) 就明白了,如果target函数是空的,就是标准target,因为它不需要用户再提供target函数了,而反之是就是扩展的target,那么再看ipt_do_table()吧,还是只看一部分,否则眼花。
if (!t->u.kernel.target->target) {
/* 如果target为空,是标准target */
int v;
v = ((struct ipt_standard_target *)t)->verdict;
if (v < 0) {
/*v小于0,动作是默认内建的动作,也可能是自定义链已经结束而返回return标志*/
if (v != IPT_RETURN) { /*如果不是Return,则是内建的动作*/
verdict = (unsigned)(-v) - 1;
break;
}
e = back;
/* e和back分别是当前表的当前Hook的规则的起始偏移量和上限偏移量,即entry的头和尾,e=back */
back = get_entry(table_base,back->comefrom);
continue;
}
/* v大于等于0,处理用户自定义链,如果当前链后还有规则,而要跳到自定义链去执行,那么需要保存一个back点,以指示程序在匹配完自定义链后,应当继续匹配的规则位置,自然地, back点应该为当前规则的下一条规则(如果存在的话)
至于为什么下一条规则的地址是table_base+v, 就要去看具体的规则是如何添加的了 */
if (table_base + v!= (void *)e + e->next_offset) {
/* 如果还有规则 */
/* Save old back ptr in next entry */
struct ipt_entry *next= (void *)e + e->next_offset;
next->comefrom= (void *)back - table_base;
/* set back pointer to next entry */
back = next;
}
e = get_entry(table_base, v);
} else {
/* 如果是扩展的target,则调用target函数,返回值给verdict */
verdict = t->u.kernel.target->target(pskb,
in, out,
hook,
t->data,
userdata);
/*Target函数有可能已经改变了stuff,所以这里重新定位指针*/
ip = (*pskb)->nh.iph;
datalen = (*pskb)->len - ip->ihl * 4;
/*如果返回的动作是继续检查下一条规则,则设置当前规则为下一条规则,继续循环,否则,就跳出循环,因为在ipt_do_table函数末尾有return verdict;表明,则将target函数决定的返回值返回给调用函数nf_iterate,由它来根据verdict决定数据包的命运*/
if (verdict == IPT_CONTINUE)
e = (void *)e + e->next_offset;
else
/* Verdict */
break;
}
Linux netfilter源码分析(7)相关推荐
- Linux netfilter源码分析(6)
六. 扩展的match 6.1 do_match函数 ip_tables.c do_match通过IPT_MATCH_ITERATE宏来调用, IPT_MATCH_ITERATE是在ipt_do_t ...
- Linux netfilter源码分析(4)
四.nf_hook_ops 钩子的注册 在filter表的初始化函数static int __init init(void)中除了有一个nf_register_hook函数注册一个tables外,还由 ...
- Linux netfilter源码分析(5)
五. ipt_do_table()函数,数据包的过滤 5.1 ipt_entry 相关结构 ip_tables.h ipt_entry结构前面有过了,再看一遍 struct i ...
- Linux netfilter源码分析(2)
二.ipt_table数据结构和表的初始化 2.1 include/linux/netfilter_ipv4/ip_tables.h struct ipt_table 表结构 struct i ...
- Linux netfilter源码分析(3)
三.ipt_table表的注册 init()函数初始化时调用了ipt_register_table函数进行表的注册 3.1 ip_tables.c 表的注册 ipt_register_tab ...
- Netfilter源码分析
Netfilter源码分析(1)(ZT) 收藏 <script type="text/javascript"></script> 一.主函数 init为 ...
- linux内存源码分析 - 内存压缩(同步关系)
本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 概述 最近在看内存回收,内存回收在进行同步的一些情况非常复杂,然后就想,不会内存压缩的页面迁移过程中的同步关系也 ...
- Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7)【转】...
原文地址:Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.c ...
- Linux内核源码分析—从用户空间复制数据到内核空间
Linux内核源码分析-从用户空间复制数据到内核空间 本文主要参考<深入理解Linux内核>,结合2.6.11.1版的内核代码,分析从用户空间复制数据到内核空间函数. 1.不描述内核同步. ...
最新文章
- mvc ajax_返回数据
- 2022年软件测试工具大全(自动化、接口、性能、安全、测试管理)
- MySQL联合查询语法内联、左联、右联、全联
- EEGLAB处理脑电视频教程 part1-3
- php高性能sqllite,简洁的PHP操作SQLite类
- c语言可移植性较差吗,c陷阱与缺陷--可移植性缺陷
- Makefile赋值符号的使用——= := ?= +=
- 《Linux菜鸟入门2》LVM
- [转] android学习和广告平台赚钱
- 从智能门锁,看3D视觉的安全性突围
- APK反编译工具使用教程
- Seafile搭建以及onlyoffice在线办公
- 《大型网站技术架构》《K8S进阶实战》等书籍!送45本!
- 小米笔记本Pro ubuntu 18.04安装显卡驱动
- Palindrome Numer
- SOA服务颗粒度(粗粒度、细粒度)与解耦
- 比 Redis 还快,更省内存,惊爆了!
- OpenCV-图像色温
- 自动驾驶--定位技术
- ClickHouse在工业互联网场景的OLAP平台建设实践
热门文章
- 数据分箱6——分箱结果进行WOE转化
- python旋转matplotlib绘制的三维图
- 用c语言实现循环神经网络,浅谈LSTM循环神经网络
- 利用开放定址法实现散列表的创建、插入、删除、查找操作_散列表和IO
- 接待员如何向客人upsell_如何提升自我做好客户服务与管理?
- ajax请求数据 ztree_ajax 异步获取数据填充到表格显示(ajax) 文档(Options API) DataTables中文网...
- 计算机的发展英语600词,程序员必备的600个英语词汇
- Codeforces 446C. DZY Loves Fibonacci Numbers【斐波那契+线段树】
- linux中 ls |wc -l
- Splay伸展树入门(单点操作,区间维护)附例题模板