作为ipchains的后继者,iptables具有更加优越的特性,良好的可扩展功能、更高的安全性以及更加紧凑、工整、规范的代码风格。

在2.6的内核中默认维护了三张表(其实是四张,还有一个名为raw的表很少被用到,这里不对其进行分析介绍了):filter过滤表,nat地址转换表和mangle数据包修改表,每张表各司其职。

我们对这三张表做一下简要说明:

1)、filter表

该表是整个过滤系统中真正起“过滤”作用的地方。所有对数据包的过滤工作都在这个表里进行,也就是说用户如果需要对某种类型的数据包进行过滤拦截,那么最好在这个表中进行操作。filter表会在NF_IP_LOCAL_IN、NF_IP_FORWARD和NF_IP_LOCAL_OUT三个hook点注册钩子函数,也就是说所有配置到filer表中的规则只可能在这三个过滤点上进行设置。

2)、nat表

主要用于DNAT和SNAT和地址伪装等操作。用于修改数据包的源、目的地址。目前版本的内核中nat表监视四个hook点:NF_IP_PRE_ROUTING、NF_IP_LOCAL_IN/OUT、NF_IP_POST_ROUTING。但在真正的实际应用中,我们一般仅需要在nat表的PREROUTING和POSTROUTING点上注册钩子函数。该表有个特性:只有新连接的第一个数据包会经过这个表,随后该连接的所有数据包将按照第一个数据包的处理动作做同样的操作,这种特性是由连接跟踪机制来实现的。

3)、mangle表

该表主要用于对数据包的修改,诸如修改数据包的TOS、TTL等字段。同时该表还会对数据包打上一些特殊的标签以便结合TC等工具,实现诸如Qos等功能。该表监视所有的hook点。

IT界有位大牛(具体是哪个我记不太清楚了)曾给程序下的定义是:程序=数据结构+算法。可见数据结构在整个程序设计过程中的重要性了。我本人也比较赞同这种说法。我们今天主要探究一下通过用户空间的iptables所配置到内核中的每条规则到底是个啥样子。

在 Netfilter 中规则是顺序存储的,一条rule规则主要包括三个部分:

  • ipt_entry:标准匹配结构,主要包含数据包的源、目的IP,出、入接口和掩码等;
  • ipt_entry_match:扩展匹配。一条rule规则可能有零个或多个ipt_entry_match结构;
  • ipt_entry_target:一条rule规则有且仅有一个target动作。就是当所有的标准匹配和扩展匹配都符合之后才来执行该target。

结构体struct ipt_entry{}的定义在include/linux/netfilter_ipv4/ip_tables.h文件里。其结构图如下:

上面这几个结构体的成员属性基本上已经做到了“见名知意”,而且内核源码也对它们做了充分的注解。这里只对最后一个属性elem做一下说明,其定义为unsigned char elems[0]。大家可能觉得有些奇怪,怎么定了一个大小为零的数组呢?而且有些面试官曾经就这样的定义还向面试者发问过呢。这种方式定义的数组叫柔性数组,又叫可变长数组。为了不至于冲淡本文主题,这里给出一个关于柔性数组的链接,这位大牛已经将的很清楚了,大家可以去拜读拜读:http://blog.csdn.net/supermegaboy/article/details/4854939。更多详细的内容可以去研读C99标准。

我们将看到内核中大量的在运用柔性数组,包括我们即将要介绍的这两个结构体:

这两个双胞胎兄弟一眼望去还以为它们是同一个东西,但事实并非如你所想的那样。其中ipt_entry_match{}表示防火墙规则的匹配部分;ipt_entry_target{}表示防火墙规则的动作处理部分。大家先忽略掉它们左边那条烦人的提示部分union,后面我会详细介绍的,现在请跟我一样尽情地无视它们吧。

这里我们还注意到,这两个家伙分别都拖了一条小尾巴:ipt_match{}和ipt_target{}。对于前面我们提到过的标准匹配,它只会去检查数据包的IP地址,源目的接口,掩码等通用信息,不会用到ipt_entry_match{}。对于以模块形式存在的扩展匹配,如iprange模块,ipp2p模块等,它们就得实现自己的ipt_match{}结构。也就是说,如果你要开发一个新的match模块,那么就必须去实例化一个ipt_match{}结构体对象,并实现该结构体中相应的成员属性(其实主要都是一些些函数指针成员,你必须实现相应的函数体),然后将该ipt_match{}对象挂在你的ipt_entry_match{}结构的match属性里就OK了,就这么简单。

同样的,我们来说一下ipt_target{}结构体。对于target(我这里就不翻译了,那个叫“动作”的翻译太难听了,后面我都用英文表述)也分为标准target和扩展target。标准target就是那些ACCEPT、DROP、REJECT等等之类的处理方式;扩展target就是那些诸如DNAT、SNAT等以模块形式存在的target了。对于标准的target,它是不需要ipt_target{}结构的,即ipt_entry_target{}中的target属性为NULL;而对于我们自己扩展target是需要我们自己手工去实现ipt_target{}对象,并完成相关回调函数的编写。对于ipt_target{}结构体中target回调函数的编写有一点要注意:该函数必须向Netfilter框架返回IPT_CONTINUE、或者诸如NF_ACCEPT、NF_DROP之类的值。开发细节我会在后续动手实践章节一一向大家说明。

结构体ipt_entry_match{}定义在include/linux/netfilter/x_tables.h文件中。

结构体ipt_entry_target{}也定义在include/linux/netfilter/x_tables.h文件中。

结构体ipt_match{}定义在include/linux/netfilter/ip_tables.h文件中。

结构体ipt_target{}也定义在include/linux/netfilter/ip_tables.h文件中。

匹配match:

上面我们说过,match分为两种:基本match,又叫标准match;扩展match。

n  标准match:

标准匹配主要用于匹配由struct ipt_ip{}所定义的数据包的特征项。标准匹配的内核数据结构就是我们上面所看到的ipt_match{}定义在include/linux/netfilter/ip_tables.h。在所有的表中我们最后真正所用到的match结构为ipt_entry_match{},它和ipt_match{}的关系我也将其画出来了,如上所示。

既然说到这里,那我就再啰嗦一点。对于ipt_entry_match{}的结构大家可能也留意到了它内部结构有个union成员,同时它还区分了user和kernel两种情况。我们刚刚在上面所讨论的ipt_match{}结构是内核中用来表示match的数据类型,在用户空间我们用的是iptables_match{}结构(定义在iptables.tar.gz源码包中的include/iptables.h头文件中)来表示match的。

也就是说,内核空间和用户空间在注册和维护match时使用的是各自的match结构,ipt_match{}和iptables_match{},但是当某个具体的match被应用到防火墙规则里时,它们两个必须统一成ipt_entry_match{},这才是防火墙规则中真正用到的match结构。

至于iptables_match{}和ipt_match{}是如何完美地统一到ipt_entry_match{}结构中的,我们在后面再来详细分析。

n  扩展match:

扩展match通常以插件或模块的形式存在。当我们在用户空间通过iptables命令设置规则时如果用到了-m  ‘name’ 参数时,那么此时‘name就是一个扩展匹配模块。前面我们也说过,如果你需要开发一个新的match模块,那么就必须去实例化一个ipt_match{}结构体对象,并实现其中的重要回调函数(如match()函数),最后通过xt_register_match()接口将你的ipt_match{}对象注册到Netfilter中去就可以了。实战篇我们讲解如何开发一个新match的全过程。

动作target:

根据上面的两幅图我们可以看到ipt_entry_match{}和ipt_entry_target{}的结构基本如出一辙,那么它们也就存在着很多非常相似的地方了。在所有的表中关于target的使用,我们既可以用ipt_standard_target{}又可以用ipt_entry_target{},这是为什么呢?后面再解释。这两个结构体的关系如下图所示:

怎么样很简单吧,就多了一个verdict变量而已。说了半天,那么target到底是用来干什么的呢?说白了,target主要用来处理:当某条规则中的所有match都被数据包匹配后该执行什么样的动作来处理这个报文,最后将处理后结果通过verdict值返回给Netfilter框架

同样的target也分内核空间和用户空间两种结构。在内核空间中,我们所说的target由ipt_target{}表示,定义在include/linux/netfilter/ip_tables.h文件中;在用户空间中,所使用的是iptables_target{}结构,该结构定义在iptables源码包里的iptables.h头文件中。同样地,ipt_target{}iptables_target{}最后也完美地统一到了ipt_entry_target{}里。

iptables的-j参数后面即可跟诸如ACCEPT、DROP这些动作,也可以跟一条用户自定义链表的名字。我们都知道iptables中的规则链(chain)其实就是某个hook点上所有规则的集合。除了系统内建的链外,用户还可以创建自定义的新链。在iptables中,同一个链里的规则是顺序存放的。内建链的最后一条规则的target是链的policy策略,而用户自定义链中是没有policy这么一说。用户自定义链的最后一条规则的target是NF_RETURN,遍历过程将返回原来的链中。当然,规则中的target也可以指定跳转到某个用户创建的自定义链上,这时这条规则的target就是ipt_standard_target{}类型,并且这个target的verdict值大于0。如果在用户自定义链上没有找到任何匹配的规则的话,遍历过程将返回到原来调用这条用户自定链的链里去匹配下一条规则。

这里还需要注意一点:target也分为标准target扩展target,前面简单提过一些。它和标准的match以及扩展match还是有些区别:

标准的target,即ipt_standard_target{}里可以根据verdict的值再划分为内建的动作或者跳转到自定义链中。简单了说,标准的target就是内核内建的一些处理动作或其延伸。

扩展的target,则完全是由用户定义的处理动作。如果ipt_target.target()函数是空的,那就是标准target,因为它不需要用户再去提供新的target函数了;反之,如果有target函数那就是扩展的target。

如果我们要开发自己的target,那么也只需要实例化一个ipt_target{}对象,并填充其内部相关的回调函数,然后调用xt_register_target()将其注册到Netfilter框架即可。

规则rule:

其实每张table表中最后真正用于表示其内部所有规则的结构体是ipt_standard{},定义在include/linux/netfilter_ipv4/ip_tables.h文件中。最后在我们几张表里,如filter表,nat表里真正用的规则结构为ipt_standard{}。它和我们前面介绍的ipt_entry{}的关系如下:

未完,待续...

(三)洞悉linux下的Netfilteriptables:内核中的rule,match和target相关推荐

  1. 洞悉linux下的Netfilteriptables

    原网址:http://blog.chinaunix.net/uid-23069658-id-3160506.html (一)洞悉linux下的Netfilter&iptables:什么是Net ...

  2. 洞悉linux下的Netfilteriptables:什么是Netfilter?

    转自:http://blog.chinaunix.net/uid-23069658-id-3160506.html (一)洞悉linux下的Netfilter&iptables:什么是Netf ...

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

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

  4. linux内核snat分析,(十)洞悉linux下的Netfilteriptables:网络地址转换原理之SNAT

    gaopeiliang:怎么搞的,关键的数据怎么丢了那,,出现的问题是 从ppp0上走出的数据,正确的SNAT出去了,同时也得到了响应,但是数据却没有转发到eth1上,看来看去好像是回来的数据包没有被 ...

  5. (十)洞悉linux下的Netfilteramp;iptables:网络地址转换原理之SNAT

    源地址转换:SNAT SNAT 主要应用于下列场景: 这种情况下,我们只有一个公网地址A,而又有三台主机需要同时上网,这时就需要SNAT了.它的主要作用是将那些由私网发来的数据包skb的源地址改成防火 ...

  6. 脚本同步mysql数据_windows下数据库文件使用脚本同步到linux下的mysql数据库中

    1.背景 windows server 2008 下 每天会有 *.sql数据文件 需要上传到linux 中的mysql数据库中 而运维人员是在 windows server 下使用 xshell 连 ...

  7. linux单步调试方法,linux下gdb单步调试(中).doc

    linux下gdb单步调试(中) linux下gdb单步调试(中) linux下gdb单步调试(中) 一.设置断点( BreakPoint ) 我们用 break 命令来设置断点.正面有几点设置断点的 ...

  8. linux用户密码转换为明文,Linux运维知识之linux下抓取内存中明文密码mimipenguin

    本文主要向大家介绍了Linux运维知识之linux下抓取内存中明文密码mimipenguin,通过具体的内容向大家展现,希望对大家学习Linux运维知识有所帮助. 下载地址:https://githu ...

  9. linux列举网卡,linux下快速列出局域网中所有主机名(计算机名)的脚本

    linux下快速列出局域网中所有主机名(计算机名)的脚本,脚本,主机名,网中,站长站,命令 linux下快速列出局域网中所有主机名(计算机名)的脚本 易采站长站,站长之家为您整理了linux下快速列出 ...

  10. linux下上传系统中文件到gitHub

    linux下上传系统中文件到gitHub 一: 1系统下生成公钥 #ssh-keygen 一路回车即可 2对公钥进行复制 #cat .shh/id_rsa.pub 3将公钥复制到github中 首先要 ...

最新文章

  1. 【译】为什么要写super(props)
  2. 在GridView内访问特定控件
  3. MySQL为关联表添加数据
  4. 电脑主板主要外部接口
  5. 一文看懂数据挖掘:哪一种方法最好?都需要哪些技术?
  6. 进程在linux系统中原理,Linux系统原理知识 进程切换的概念介绍
  7. 【嵌入式Linux】嵌入式Linux应用开发基础知识之输入系统应用编程
  8. 使用qq邮箱服务器来实现laravel的邮件发送
  9. 小学的题 大学的解法
  10. 【ZOJ4110】Strings in the Pocket (马拉车算法+分析)
  11. JavaScript高级程序设计:基本概念思维导图
  12. JavaWeb新闻发布系统案例4
  13. 思科模拟器 --- 路由器单臂路由配置
  14. python xlsm_Excel中的xls、xlsx、xlsm混合文件,看我如何用Python统一处理!
  15. python装饰器和异常处理_装饰器异常处理-面向对象编程-Python教程自动化开发_Python视频教程...
  16. Reporting报表开发知识汇总[个人原创]
  17. python小工具—图片转为字符txt
  18. 项目实战之aiguibin-protal-gateway集成门户
  19. cad怎么去除drawing1_cad2014首次运行时总会多启动一个叫“Drawing1”的窗口,这个怎么去掉?...
  20. 开式蓄冷罐与闭式蓄冷罐_一罐将其全部统治:Arquillian + Java 8

热门文章

  1. mysql批量插入优化
  2. 20150109--面向对象+对象传值-01
  3. 大数据项目之dmp用户画像
  4. 在UNITY中按钮的高亮用POINT灯实现,效果别具一番风味
  5. 亚马逊股价继续大涨 首度突破每股800美元
  6. 关于远程访问tomcat问题的总结
  7. L2TP-***通用原理取证及在华为防火墙上的实施
  8. QuickFlowDesigner教程(4)如何用代码控制活动操作人
  9. sqlserver2000分页
  10. 推荐:“创建MOSS2007自定义字段类型实例”