一、iptables简介


iptables 的前身叫ipfirewall (内核1.x时代),这是一个从freeBSD上移植过来的,能够工作在内核当中的,对数据包进行检测的一款简易访问控制工具。但是 ipfirewall工作功能极其有限(它需要将所有的规则都放进内核当中,这样规则才能够运行起来,而放进内核,这个做法一般是极其困难的)。当内核发 展到2.x系列的时候,软件更名为ipchains,它可以定义多条规则,将他们串起来,共同发挥作用,而现在,它叫做iptables,可以将规则组成一个列表,实现绝对详细的访问控制功能。

iptables和netfilter的关系是一个很容易让人搞不清的问题。很多的知道iptables却不知道 netfilter。其实iptables只是Linux防火墙的管理工具而已,位于/sbin/iptables。真正实现防火墙功能的是 netfilter,它是Linux内核中实现包过滤的内部结构。



二、iptables基础


规则(rules)其实就是网络管理员预定义的条件,规则一般的定义为“如果数据包头符合这样的条件,就这样处理这个数据包”。规则存储在内核空间的信息 包过滤表中,这些规则分别指定了源地址、目的地址、传输协议(如TCP、UDP、ICMP)和服务类型(如HTTP、FTP和SMTP)等。当数据包与规 则匹配时,iptables就根据规则所定义的方法来处理这些数据包,如放行(accept)、拒绝(reject)和丢弃(drop)等。配置防火墙的 主要工作就是添加、修改和删除这些规则。



三、iptables传输数据包的过程


① 当一个数据包进入网卡时,它首先进入PREROUTING链,内核根据数据包目的IP判断是否需要转送出去。 
② 如果数据包就是进入本机的,它就会沿着图向下移动,到达INPUT链。数据包到了INPUT链后,任何进程都会收到它。本机上运行的程序可以发送数据包,这些数据包会经过OUTPUT链,然后到达POSTROUTING链输出。 
③ 如果数据包是要转发出去的,且内核允许转发,数据包就会如图所示向右移动,经过FORWARD链,然后到达POSTROUTING链输出。

又爱又恨的iptables_路由表



四、iptables的规则和链


上图中的五个位置也被称为五个钩子函数(hook functions),也叫五个规则链。

1.PREROUTING (路由前)

2.INPUT (数据包流入口)

3.FORWARD (转发管卡)

4.OUTPUT(数据包出口)

5.POSTROUTING(路由后)

 这是netfilter规定的五个规则链,任何一个数据包,只要经过本机,必将经过这五个链中的其中一个链。

iptables包含4个表,5个链。其中表是按照对数据包的操作区分的,链是按照不同的Hook点来区分的,表和链实际上是netfilter的两个维度。     

(1)4表:

   filter,nat,mangle,raw,默认表是filter(没有指定表的时候就是filter表)

    filter:一般的过滤功能

    nat:用于nat功能(端口映射,地址映射等)

    mangle:用于对特定数据包的修改

    raw:有限级最高,设置raw时一般是为了不再让iptables做数据包的链接跟踪处理,提高性能

(2)5链:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING。

    PREROUTING:数据包进入路由表之前

    INPUT:通过路由表后目的地为本机

    FORWARDING:通过路由表后,目的地不为本机

    OUTPUT:由本机产生,向外转发

    POSTROUTING:发送到网卡接口之前。


(3)规则表:
1.filter表——三个链:INPUT、FORWARD、OUTPUT
作用:过滤数据包  内核模块:iptables_filter.
2.Nat表——三个链:PREROUTING、POSTROUTING、OUTPUT
作用:用于网络地址转换(IP、端口) 内核模块:iptable_nat
3.Mangle表——五个链:PREROUTING、POSTROUTING、INPUT、OUTPUT、FORWARD
作用:修改数据包的服务类型、TTL、并且可以配置路由实现QOS内核模块:iptable_mangle(别看这个表这么麻烦,咱们设置策略时几乎都不会用到它)
4.Raw表——两个链:OUTPUT、PREROUTING
作用:决定数据包是否被状态跟踪机制处理  内核模块:iptable_raw


(4)规则链:
1.INPUT——进来的数据包应用此规则链中的策略
2.OUTPUT——外出的数据包应用此规则链中的策略
3.FORWARD——转发数据包时应用此规则链中的策略
4.PREROUTING——对数据包作路由选择前应用此链中的规则
(记住!所有的数据包进来的时侯都先由这个链处理)
5.POSTROUTING——对数据包作路由选择后应用此链中的规则
(所有的数据包出来的时侯都先由这个链处理)

又爱又恨的iptables_iptables_02(5)规则表之间的优先顺序:

raw——mangle——nat——filter



五、iptables的命令管理



命令格式:iptables [-t table] SUBCOMMAND chain [matches...] [target]    

如图示

   又爱又恨的iptables_iptables_03

   又爱又恨的iptables_防火墙_04

详细介绍:


(1)链管理
    -N: new,新增一条自定义链;
    -X:delete,删除自定义的空链;
    -P:policy,设置链的默认策略;
         ACCEPT:接受
         DROP:丢弃
         REJECT:拒绝
    -E:rename,重命名自定义的未被引用(引用计数为0)的链;


(2)规则管理
    -A:append,追加,默认为最后一个;
    -I:insert,插入,默认为第一个;
    -D:delete,删除
        (1) rule specification
        (2) rule number
    -R:replace,替换
    -F:flush,清除规则
    -Z:zero,置0;
        iptables的每条规则都有两个计数器:
             (1) 由本规则匹配到的所有的packets;
             (2) 由本规则匹配到的所有的bytes;
    -S:selected,以iptables-save命令的格式显示链上的规则;


例:虚拟机ip地址为192.168.1.108,已安装httpd服务,编写一条规则让所有主机不可访问

[root@bogon ~]# iptables -t filter -A INPUT -d 192.168.1.108 -p tcp --dport 80 -j REJECT

此时再通过浏览器就不能访问apache测试页面了

再编写一条规则,让192.168.1.X网段内的主机可以访问

[root@bogon ~]# iptables -t filter -D INPUT 1 #先删除之前的规则
[root@bogon ~]# iptables -t filter -I INPUT -s 192.168.1.0/24 -d 192.168.1.108 -j ACCEPT #添加规则
[root@bogon ~]# iptables -nvL --line-number #查看
Chain INPUT (policy ACCEPT 3 packets, 840 bytes)
num   pkts bytes target     prot opt in     out     source               destination         
1       72  5308 ACCEPT     all  --  *      *       192.168.1.0/24       192.168.1.108       

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 51 packets, 5708 bytes)
num   pkts bytes target     prot opt in     out     source               destination

修改本规则,让本网段内的不能访问apache测试页面

[root@bogon ~]# iptables -t filter -R INPUT 1 -s 192.168.1.0/24 -d 192.168.1.108 -j REJECT

(3)查看
    -L: list,列出规则
    -n:numeric,以数字格式显示地址和端口;
    -v:verbose,详细信息;-vv, -vvv
    -x:exactly,显示计数器的精确值而非单位换算后的结果;
    --line-numbers:显示链上的规则的编号;           
    组合:-nvL

[root@bogon ~]# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

    
匹配条件
(4)基本匹配:netfilter自带的匹配机制
    [!] -s, --source address[/mask][,...]:原地址匹配
    [!] -d, --destination address[/mask][,...]:目标地址匹配
    [!] -i, --in-interface name:限制报文流入的接口,只能用于PREROUTING,INPUT及FORWARD;
    [!] -o, --out-interface name:限制报文流出的接口,只能用于OUTPUT,FORWARD及POSTROUTING;

(5)扩展匹配:经由扩展模块引入的匹配机制,-m matchname
    隐式扩展:可以不用使用-m选项专门加载响应模块;前提是要使用-p选项可匹配何种协议;

        tcp、udp、icmp

    显式扩展:必须由-m选项专门加载响应模块;
        multiport
        iprange
        string
        time
        connlimit
        limit
        state


(5.1)隐式扩展
    [!]  -p, --protocol PROTOCOL PROTOCOL:
    协议:tcp, udp, icmp, icmpv6, esp, ah, sctp, mh or "all"
                    
    tcp: 隐含指明了“-m tcp”,有专用选项:
    [!] --source-port,--sport  port[:port]:匹配报文中的tcp首部的源端口;可以是端口范围;
    [!] --destination-port,--dport port[:port]:匹配报文中的tcp首部的目标端口;可以是端口范围;
    [!] --tcp-flags mask comp:检查报文中mask指明的tcp标志位,而要这些标志位comp中必须为1;
        --tcp-flags  syn,fin,ack,rst  syn
        --tcp-flags  syn,fin,ack,rst  ack,fin
    [!] --syn:
        --syn相当于“--tcp-flags  syn,fin,ack,rst  syn”;tcp三次握手的第一次                      
    udp:隐含指明了“-m udp”,有专用选项:
    [!] --source-port,--sport  port[:port]:匹配报文中的udp首部的源端口;可以是端口范围;
    [!] --destination-port,--dport port[:port]:匹配报文中udp首部的目标端口;可以是端口范围
                        
    icmp:隐含指明了“-m icmp”,有专用选项:
    [!] --icmp-type {type[/code]|typename}
        type/code:
            0/0:echo reply   别人可以ping自己
            8/0:echo request 自己可以ping别人    

例:将虚拟机192.168.1.108设置为,自己可以ping别人,而别人不能ping自己

对于ping这个协议,进来的为8(ping),出去的为0(响应).我们为了达到目的,需要8出去,允许0进来

[root@bogon ~]# iptables -t filter -A INPUT -d 192.168.1.108 -p icmp --icmp-type 8 -j DROP #设置别人ping自己的数据包不能通过
[root@bogon ~]# iptables -t filter -A OUTPUT -s 192.168.1.108 -p icmp --icmp-type 0 -j ACCEPT #设置自己ping别人的数据包可以通过

               

       
(5.2)显式扩展          
5.2.1 multiport:多端口匹配
    以离散方式定义多端口匹配,最多可以指定15个端口;          
    [!] --source-ports,--sports port[,port|,port:port]...
    [!] --destination-ports,--dports port[,port|,port:port]...
    [!] --ports port[,port|,port:port]...

 [root@bogon ~]# iptables -I INPUT -s 0/0 -d 192.168.1.108 -p tcp  -m multiport --dports 22,80 -j ACCEPT #允许所有主机访问192.168.1.108的22和80端口
 [root@bogon ~]# iptables -I OUTPUT -d 0/0 -s 192.168.1.108 -p tcp  -m multiport --sports 22,80 -j ACCEPT #允许192.168.1.108的主机可以通过22和80端口发送数据包

5.2.2 iprange:指明一段连续的ip地址范围做为源地址或目标地址匹配;
    [!] --src-range from[-to]:源地址范围
    [!] --dst-range from[-to]:目标地址范围

 [root@bogon ~]# iptables -A INPUT -p tcp -m iprange --src-range 192.168.0.100-192.168.0.105 --dport 22 -j ACCEPT #匹配一组ip地址192.168.0.100-192.168.0.105

                
5.2.3 string:对报文中的应用层数据做字符串匹配检测;
        --algo {bm|kmp}:指明算法
            (bm = Boyer-Moore, kmp = Knuth-Pratt-Morris)
    [!] --string pattern:给定要检查的字符串模式;
    [!] --hex-string pattern:给定要检查的字符串模式;
                

[root@bogon ~]# iptables -I OUTPUT -s 192.168.1.108 -d 0/0 -p tcp --sport 80 -m string --algo bm --string "old" -j REJECT #有"old"字符串的拒绝访问

                
5.2.4 time:根据收到报文的时间/日期与指定的时间/日期范围进行匹配;         
    --datestart YYYY[-MM[-DD[Thh[:mm[:ss]]]]]:起始日期时间;
    --datestop YYYY[-MM[-DD[Thh[:mm[:ss]]]]]:结束日期时间; 
    --timestart hh:mm[:ss]:起始时间;
    --timestop hh:mm[:ss]:结束时间;    
    [!] --monthdays day[,day...]:匹配一个月中的哪些天;
    [!] --weekdays day[,day...]:匹配一个周中的哪些天; 

[root@bogon ~]# iptables -A INPUT -d 192.168.1.108 -p tcp --dport 23 -m iprange --src-range 192.168.1.1-192.168.1.100 -m time --timestart 09:00:00 --timestop 18:00:00 --weekdays 1,2,3,4,5 -j ACCEPT #让192.168.1.1-192.168.1.100网段内的在工作日的09-18点可以通过23号端口访问192.168.1.108

                
5.2.5 connlimit:根据每客户端主机做并发连接数限制,即每客户端最多可同时发起的连接数量;
    --connlimit-upto n:上限是多少。连接的数量小于等于n时匹配

    --connlimit-above n:下限是多少。最小连接数;           

[root@bogon ~]# iptables -A INPUT -s 0/0 -d 192.168.1.108 -p tcp --dport 23 -m connlimit --connlimit-upto 2 -j ACCEPT #每台主机的最大连接数为2个

                
5.2.6 limit:基于令牌桶算法对报文的速率做匹配;           
    --limit rate[/second|/minute|/hour|/day]
    --limit-burst number        

[root@bogon ~]# iptables -R INPUT 3 -d 192.168.1.108 -p icmp --icmp-type 8 -m limit --limit 20/minute --limit-burst 3 -j ACCEPT #表示,每分钟组多可以有20个ping请求。开始时有3个请求。

5.2.7 state:是conntrack的子集,用于对报文的状态做连接追踪;      
    [!] --state state     

是一种显式扩展,用于检测会话之间的连接关系的,有了检测我们可以实现会话间功能的扩展

什么是状态检测?对于整个TCP协议来讲,它是一个有连接的协议,三次握手中,第一次握手,我们就叫NEW连接,而从第二次握手以后的,ack都为1,这是正常的数据传输,和tcp的第二次第三次握手,叫做已建立的连接(ESTABLISHED),还有一种状态,比较诡异的,比如:SYN=1 ACK=1 RST=1,对于这种我们无法识别的,我们都称之为INVALID无法识别的。还有第四种,FTP这种古老的拥有的特征,每个端口都是独立的,21号和20号端口都是一去一回,他们之间是有关系的,这种关系我们称之为RELATED。

一共有5种状态:
    INVALID:无法识别的连接;
    ESTABLISHED:连接追踪模板当中存在记录的连接;
    NEW:连接追踪模板当中不存的连接请求;
    RELATED:相关联的连接;
    UNTRACKED:未追踪的连接;

[root@bogon ~]# iptables -A INPUT -s 192.168.1.0/24 -d 192.168.1.108 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT #允许192.168.1.X网络内的主机通过22号端口,状态为NEW,ESTABLISHED,即新建的,已建立过连接的。
[root@bogon ~]# iptables -R OUTPUT 1 -m state --state ESTABLISHED -j ACCEPT #允许状态为ESTABLISHED的数据包通过

    已经追踪到的并记录下来的连接:
        /proc/net/nf_conntrack
                    
    连接追踪功能所能够记录的最大连接数量(可调整):
        /proc/sys/net/nf_conntrack_max
                    
         sysctl -w net.nf_conntrack_max=300000
         echo  300000 > /proc/sys/net/nf_conntrack_max
                    
conntrack所能够追踪的连接数量的最大值取决于/proc/sys/net/nf_conntrack_max的设定;已经追踪到的并记录下来的连接位于/proc/net/nf_conntrack文件中,超时的连接将会被删除;当模板满载时,后续的新连接有可能会超时;解决办法:
    (1) 加大nf_conntrack_max的值;
    (2) 降低nf_conntrack条目的超时时长;
    不同协议的连接追踪时长:/proc/sys/net/netfilter/



(6)处理动作:
    -j targetname [per-target-options]
        ACCEPT, DROP, REJECT
        RETURN:返回调用的链
        REDIRECT:端口重定向
        LOG:日志
        MARK:防火墙标记
        DNAT:目标地址转换
        SNAT:源地址转换
        MASQERADE:地址伪装


规则的检查次序:规则在链接上的次序即为其检查时的生效次序;因此,其优化使用有一定法则;

    (1) 同类规则(访问同一应用),匹配范围小的放前面;用于特殊处理;

    (2) 不同类的规则(访问不同应用),匹配范围大的放前面;

    (3) 应该将那些可由一条规则描述的多个规则合并为一;

    (4) 设置默认策略;

规则的有效期限:

    iptables命令添加的规则,手动删除之前,其生效期限为kernel的生命周期;



七、SNAT和DNAT的实现


SNAT: source NAT 源地址转换

    修改IP报文中的源IP地址;

    让本地网络中的主机可使用统一地址与外部主机通信,从而实现地址伪装;

        请求:由内网主机发起,修改源IP,如果修改则由管理员定义;

        响应:修改目标IP,由nat自动根据会话表中追踪机制实现相应修改;

DNAT: destination NAT 目的地址转换

    修改IP报文中的目标IP地址;

    让本地网络中服务器使用统一的地址向外提供服务(发布服务),但隐藏了自己的真实地址;

        请求:由外网主机发起,修改其目标地址,由管理员定义;

        响应:修改源地址,但由nat自动根据会话表中的追踪机制实现对应修改;


SNAT: POSTROUTING(要在POSTROUTING链上添加规则)

DNAT: RPEROUTING(要在PREROUTING链上添加规则)


SNAT和DNAT诞生的本意是想隐藏本机ip的,但是无心插柳柳成荫,由于我们现在IP地址十分紧俏,已经分配完了,这就导致我们必须要进行地址转换,来节约我们仅剩的一点IP资源。如何通过iptables实现NAT的地址转换呢?

现在大部分家庭使用的上网模式就是源地址转换模式,即多台内网主机-->路由器。共用一个外网地址。

1.SNAT基于源地址的转换

基于原地址的转换一般用在我们的许多内网用户通过一个外网的口上网的时候,这时我们将我们内网的地址转换为一个外网的IP,我们就可以实现连接其他外网IP的功能。

所以我们在iptables中就要定义到底如何转换:

定义的样式:

比如我们现在要将所有192.168.10.0网段的IP在经过的时候全都转换成172.18.100.1这个假设出来的外网地址:

[root@bogon ~]# iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -j SNAT --to-source 172.16.100.1


这样,只要是来自本地网络的试图通过网卡访问网络的,都会被统统转换成172.16.100.1这个IP.

那么,如果172.16.100.1不是固定的怎么办?

我们都知道当我们使用联通或者电信拨号上网的时候,一般它都会在每次你开机的时候随机生成一个外网的IP,意思就是外网地址是动态变换的。这时我们就要将外网地址换成 MASQUERADE(动态伪装):它可以实现自动寻找到外网地址,而自动将其改为正确的外网地址。所以,我们就需要这样设置:

       

 [root@bogon ~]# iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -j MASQUERADE

这里要注意:地址伪装并不适用于所有的地方。

 

2.DNAT目标地址转换

对于目标地址转换,数据流向是从外向内的,外面的是客户端,里面的是服务器端通过目标地址转换,我们可以让外面的ip通过我们对外的外网ip来访问我们服务器不同的服务器,而我们的服务却放在内网服务器的不同的服务器上。


服务器为内网192.168.10.18,假设有一个外网ip为172.16.100.2

    如何做目标地址转换呢?:

[root@bogon ~]# iptables -t nat -A PREROUTING -d 172.16.100.2 -p tcp --dport 80 -j DNAT --to-destination 192.168.10.18

    目标地址转换要做在到达网卡之前进行转换,所以要做在PREROUTING这个位置上


八、控制规则的存放以及开启


注意:你所定义的所有规则,当你重启的时候都会失效,要想能够开机生效,需要使用一个命令将它保存起来

    1.service iptables save 命令

        它会保存在/etc/sysconfig/iptables这个文件中

    2.iptables-save 命令

        iptables-save > /etc/sysconfig/iptables 

    3.iptables-restore 命令

开机的时候,它会自动加载/etc/sysconfig/iptabels

如果开机不能加载或者没有加载,而你想让一个自己写的配置文件(假设为iptables.2)手动生效的话(可以将此写入到一个脚本中,开机自动执行一次即可/etc/rc.d/rc.local/iptables.sh):

iptables-restore < /etc/sysconfig/iptables.2

则完成了将iptables中定义的规则手动生效

 

 


九、总结



    iptables是一个非常重要的工具,它是每一个防火墙上几乎必备的设置,也是我们在做大型网络的时候,为了很多原因而必须要设置的。学好iptables,可以让我们对整个网络的结构有一个比较深刻的了解,同时,我们还能够将内核空间中数据的走向以及linux的安全给掌握的非常透彻。

    由于时间仓促和能力问题,可能有不正之处,请大家不吝赐教,共同学习,进步!