七、 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)相关推荐

  1. Linux netfilter源码分析(6)

    六. 扩展的match 6.1 do_match函数  ip_tables.c do_match通过IPT_MATCH_ITERATE宏来调用, IPT_MATCH_ITERATE是在ipt_do_t ...

  2. Linux netfilter源码分析(4)

    四.nf_hook_ops 钩子的注册 在filter表的初始化函数static int __init init(void)中除了有一个nf_register_hook函数注册一个tables外,还由 ...

  3. Linux netfilter源码分析(5)

    五. ipt_do_table()函数,数据包的过滤   5.1          ipt_entry 相关结构  ip_tables.h ipt_entry结构前面有过了,再看一遍 struct i ...

  4. Linux netfilter源码分析(2)

    二.ipt_table数据结构和表的初始化 2.1  include/linux/netfilter_ipv4/ip_tables.h   struct  ipt_table 表结构 struct i ...

  5. Linux netfilter源码分析(3)

    三.ipt_table表的注册   init()函数初始化时调用了ipt_register_table函数进行表的注册   3.1  ip_tables.c 表的注册 ipt_register_tab ...

  6. Netfilter源码分析

      Netfilter源码分析(1)(ZT) 收藏 <script type="text/javascript"></script> 一.主函数 init为 ...

  7. linux内存源码分析 - 内存压缩(同步关系)

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 概述 最近在看内存回收,内存回收在进行同步的一些情况非常复杂,然后就想,不会内存压缩的页面迁移过程中的同步关系也 ...

  8. Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7)【转】...

    原文地址:Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.c ...

  9. Linux内核源码分析—从用户空间复制数据到内核空间

    Linux内核源码分析-从用户空间复制数据到内核空间 本文主要参考<深入理解Linux内核>,结合2.6.11.1版的内核代码,分析从用户空间复制数据到内核空间函数. 1.不描述内核同步. ...

最新文章

  1. mvc ajax_返回数据
  2. 2022年软件测试工具大全(自动化、接口、性能、安全、测试管理)
  3. MySQL联合查询语法内联、左联、右联、全联
  4. EEGLAB处理脑电视频教程 part1-3
  5. php高性能sqllite,简洁的PHP操作SQLite类
  6. c语言可移植性较差吗,c陷阱与缺陷--可移植性缺陷
  7. Makefile赋值符号的使用——= := ?= +=
  8. 《Linux菜鸟入门2》LVM
  9. [转] android学习和广告平台赚钱
  10. 从智能门锁,看3D视觉的安全性突围
  11. APK反编译工具使用教程
  12. Seafile搭建以及onlyoffice在线办公
  13. 《大型网站技术架构》《K8S进阶实战》等书籍!送45本!
  14. 小米笔记本Pro ubuntu 18.04安装显卡驱动
  15. Palindrome Numer
  16. SOA服务颗粒度(粗粒度、细粒度)与解耦
  17. 比 Redis 还快,更省内存,惊爆了!
  18. OpenCV-图像色温
  19. 自动驾驶--定位技术
  20. ClickHouse在工业互联网场景的OLAP平台建设实践

热门文章

  1. 数据分箱6——分箱结果进行WOE转化
  2. python旋转matplotlib绘制的三维图
  3. 用c语言实现循环神经网络,浅谈LSTM循环神经网络
  4. 利用开放定址法实现散列表的创建、插入、删除、查找操作_散列表和IO
  5. 接待员如何向客人upsell_如何提升自我做好客户服务与管理?
  6. ajax请求数据 ztree_ajax 异步获取数据填充到表格显示(ajax) 文档(Options API) DataTables中文网...
  7. 计算机的发展英语600词,程序员必备的600个英语词汇
  8. Codeforces 446C. DZY Loves Fibonacci Numbers【斐波那契+线段树】
  9. linux中 ls |wc -l
  10. Splay伸展树入门(单点操作,区间维护)附例题模板