iptables原理: 包过滤型的防火墙

      Firewall:防火墙,是一个隔离工具,能够对报文进行规则匹配,主要工作于主机或者网络边缘,对于匹配到报文进行相应的处理。所以其工作的范围又分为两类:

主机防火墙:对进出本主机的数据包进行规制匹配,并作出相应的处理动作。

网络防火墙:对流经本网络的数据包进行规制匹配,并作出相应的处理动作,工作在网络出口处,一般作为网关防火墙。

防火墙的的匹配规则顺序:自上而下按顺序进行匹配,对于匹配到的规则则按相应的处理动作进行处理,如果没有一条规则能匹配到则按默认规则进行处理,比如RETURN(返回调用链),默认存在。所以说对于同种规则大范围的规则应该放最上面,然后往下越来越严格。


iptables:

     真正工作的并不是iptables,而是netfilter,是存在于内核中的一个模块,实现防火墙的功能,而iptables只是管理netfilter的一个工具。

iptables的功能:

五链:prerouting、input、output、forward、postrouting       即五个钩子函数,链还可以自定义

四表:filter、mangle、nat、raw

         filter:主要是过滤,对应的链为input、output、forward

         mangle:拆解报文,做出修改,并重新封装报文,对应的链为prerouting、input、output、forward、postrouting

         nat:网络地址转换,实现地址或者端口的伪装,对应的链为prerouting、postrouting、output

         raw:主要关闭nat表上启用的追踪功能,对应的链为prerouting、output

注意:在高并发的服务器上,比如前端httpd服务器,是需要关闭追踪功能的,因为追踪表有大小,如果超出了表的大小的话就会出现tcp连接超时,新的请求会请求不进来,虽然可以增大追踪表的容量,但会消耗更多的资源,而且效率也会降低。

报文在主机内的流向图:

       wKioL1ch-eWz40AoAAAX_W0K9f0820.png

报文的流向:

      1、报文进入本机--->prerouting--->input--->用户空间--->output-->postrouting

      2、报文流入本机--->prerouting--->forward--->postrouting

报文进入本机时,会先判断报文的是否是发给本机的,如果是则进入iput,然后进入内核空间,如果不是则通过forward链进行转发,最后判断应该从哪个网卡流出前往下一跳。

注意:当主机作为网络防火墙时,应用的就是forward链,所以需要开启转发功,把/proc/sys/net/ipv4/ip_forward改成1即可,这只是临时生效,想要永久生效得写进内核参数文件中

[root@localhost ipv4]# vim /etc/sysctl.conf 
# Controls IP packet forwarding
net.ipv4.ip_forward = 1
[root@localhost ipv4]# /sbin/sysctl -p          //让参数立即生效

表的优先级示意图:   对比相同的链,raw>mangle>net>filter

wKiom1cjRZLQd-KcAAJAJICrX2k267.png


iptables的规则:  根据规定的匹配条件来匹配报文,一旦匹配成功则按照规则定义的处理动作进行处理

       组成部分:匹配条件和处理动作

       匹配条件:基本匹配条件、扩展匹配条件

       处理动作:基本处理动作、扩展处理动作、自定义处理动作

iptables的基本命令:      

      iptables [-t table] {-A|-C|-D} chain rule-specification

      

        iptables [-t table] -I chain [rulenum] rule-specification

        

        iptables [-t table] -R chain rulenum rule-specification

        

        iptables [-t table] -D chain rulenum

        

        iptables [-t table] -S [chain [rulenum]]

        

        iptables [-t table] {-F|-L|-Z} [chain [rulenum]] [options...]

        

        iptables [-t table] -N chain

        

        iptables [-t table] -X  [chain]

        

        iptables [-t table] -P chain target

        

        iptables [-t table] -E old-chain-name new-chain-name


表管理:

        -t tables:指明哪个表,raw,mangle,nat,filter,如果不加-t 指明表示默认是filter表


链管理:

        -N:表示新建一条自定义规则链

        -X:表示删除一条规则链

        -P:表示修改默认策略,对于filter表而言,其默认策略为:ACCEPT、REJECT、DROP

        -E:表示重命名一条未被调用的自定义链,只要referneces为0。

规则管理:

        -A:表示追加一条规则

        -I :表示插入一条规则,可以指明插入位置,如果不指明则默认是第一条

        -D:表示删除一条规则,需指明规则的序列号
        -R:表示替换指定链上的规则,也需要指明规则的序列号

        -F:表示清空规则,可以指定清空哪条规则链上的规则

        -Z:置零,主要清空规则链上经过的包和字节数                 

                      iptables的每条规则都有两个计数器:

         (1) 由本规制匹配到的报文的个数;

         (2) 由本规制匹配到的所有报文的大小之和;

规则的查看:

        -L:列出指定链上的所有规则

        -n:以数字格式显示地址和端口号

        -v:显示详细信息

        -x:显示计数器的精确值

        --line-numbers:显示规则的序列号


处理动作:

    -j targetname [per-target-options]

        ACCEPT:接受

        DROP  :丢弃

        REJECT:拒绝

        RETURN:返回调用链;

        REDIRECT:端口重定向;

        LOG:记录日志;

        MARK:做防火墙标记;

        DNAT:目标地址转换;

        SNAT:源地址转换;

        MASQUERADE:地址伪装;

        自定义链:

注意:在写规则时,需要考虑以下几方面:

            1、要实现哪种功能:需要添加在哪个表上

            2、报文流径的路径:需要添加在哪个链上

         规则的检查次序:          

          1、同类规则(访问同一应用),匹配范围小的放上面

          2、不同类规则(访问不同应用),匹配到报文频率较大的放上面

          3、将那些可由一条规则标书的多个规则合并为一个

          4、设置默认策略

                   白名单(先允许特定访问,其他全部拒绝)

                   黑名单(先拒绝特定访问,其他全部允许)

匹配条件:     

        基本匹配条件:无需加载任何模块,由iptables/netfilter自行提供;

        [!] -s, --source  address[/mask][,...]:检查报文中的源IP地址是否符合此处指定的地址或范围;

        [!] -d, --destination address[/mask][,...]:检查报文中的目标IP地址是否符合此处指定的地址或范围;

        [!] -p, --protocol protocol :限制协议,一般只限制tcp、udp、icmp

        [!] -i, --in-interface name:数据报文流入的接口;只能应用于数据报文流入的环节,只能应用于PREROUTING,INPUT和FORWARD链;

        [!] -o, --out-interface name:数据报文流出的接口;只能应用于数据报文流出的环节,只能应用于FORWARD、OUTPUT和POSTROUTING链;

    扩展匹配条件:分为隐式扩展和显示扩展

         隐式扩展:不需要手动加载扩展模块;因为它们是对协议的扩展,所以,但凡使用-p指明了协议,就表示已经指明了要扩展的模块;

 不需要-m选项指明加载扩展选项,前提要使用-p选项可匹配何种协议

tcp:

[!] --source-port, --sport port[:port]:匹配报文的源端口;可以是端口范围;

[!] --destination-port,--dport port[:port]:匹配报文的目标端口;可以是端口范围;

[!] --tcp-flags  mask  comp:检查报文中mask指明的tcp标志位,而要这小标志位comp中必须为1

            --tcp-flags  SYN,ACK,FIN,RST  SYN      :表示要检查的标志位为SYN,ACK,FIN,RST四个,其中SYN必须为1,余下的必须为0;

    --tcp-flags  SYN,ACK,FIN,RST  ack,fin  :表示要检查ack,fin

        [!] --syn:用于匹配第一次握手,相当于”--tcp-flags  SYN,ACK,FIN,RST  SYN“;

]# iptables -A INPUT -s 0/0 -d 10.0.1.2 -p tcp --dport 80 --tcp-flags SYN,ACK,FIN,RST SYN  -j ACCEPT
]# iptables -A INPUT -d 0/0 -s 10.0.1.2 -p tcp --sport 80 -j ACCEPT

        udp:

[!] --source-port, --sport port[:port]:匹配报文的源端口;可以是端口范围;

[!] --destination-port,--dport port[:port]:匹配报文的目标端口;可以是端口范围;

]# iptables -A INPUT -s 0/0 -d 10.0.1.2 -p udp --dprot 53 -j ACCEPT

icmp:

[!] --icmp-type [type]

           0: 回显应答   ping应答

   8: 回显请求   ping请求

]# iptables -A INPUT -d 172.18.250.76 -p icmp --icmp-type 8 -j ACCEPT
]# iptables -A OUTPUT -s 172.18.250.76 -p icmp --icmp-type 0 -j ACCEPT

    显示扩展:必须由-m选项来指定加载模块

     1、multiport,以离散方式定义多个端口匹配,最多只能定义15个         

                [!] --source-ports,--sports port[,port|,port:port]...:指定多个源端口;

                [!] --destination-ports,--dports port[,port|,port:port]...:指定多个目标端口;

        [!] --ports port[,port|,port:port]...:指明多个端口;

]# iptables -A INPUT -d 172.18.250.76 -p tcp -m multiport --dports 80,8080,10050 -j ACCEPT

       2、iprange扩展:指明连续的IP地址范围,但一般不指整个网络   

                [!] --src-range from[-to]:源IP地址;

        [!] --dst-range from[-to]:目标IP地址;

]# iptables -A INPUT -d 172.18.250.76 -p tcp --dport 80 -m iprange --src-range 172.18.1.0-172.18.10.0 -j ACCEPT

    3、string扩展:对报文中的应用层数据做字符串匹配,这条规则得放在OUTPUT链上

        --algo {bm|kmp}:字符串匹配检测算法;

        bm:Boyer-Moore

            kmp:Knuth-Pratt-Morris

        [!] --string pattern:要检测的字符串模式;

        [!] --hex-string pattern:要检测的字符串模式,16进制格式;

]# iptables -A OUTPUT -s 172.18.250.76 -p tcp --dport 80 -m string --algo bm --string "Hello"  -j DROP

    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...]:匹配一周中的哪些天

        --kerneltz:使用内核上的时区,而非默认的UTC;

]# iptables -A INPUT -d 172.18.250.76 -p tcp --dport 80 -m time --timestart 8:30 --timestop 18:00 ! --weekdays 1 -j ACCEPT

     5、connlimit扩展:根据客户端的IP做并发IP连接数的匹配                

                   --connlimit-upto n:连接的数量小于等于n时匹配;

           --connlimit-above n:连接的数量大于n时匹配;

]# iptables -A INPUT -d 172.18.250.76 -p tcp --dport 22 -m connlimit --connlimit-above 5 -j DROP

    6、limit扩展:根据令牌桶算法对报文的速率进行匹配          

        --limit rate[/second|/minute|/hour|/day] :每秒/分/时/天请求的个数

        --limit-burst number:突发速率个数

]# iptables -A INPUT -d 172.18.250.76 -p icmp --icmp-type 8 -m limit --limit 3/s --limit-burst 5 -j ACCEPT

        7、state扩展,是conntrack的子集,用于对报文的状态做连接追踪,根据”连接追踪机制“去检查连接的状态;            

                 conntrack机制:追踪本机上的请求和响应之间的关系;状态有如下几种:

     NEW:新发出请求;连接追踪模板中不存在此连接的相关信息条目,因此,将其识别为第一次发出的请求;

     ESTABLISHED:NEW状态之后,连接追踪模板中为其建立的条目失效之前期间内所进行的通信状态;

     RELATED:相关联的连接;如ftp协议中的数据连接与命令连接之间的关系;

     INVALID:无效的连接,无法识别的连接

     UNTRACKED:未进行追踪的连接,

            [!] --state state 

]# iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
]# iptables -A INPUT -s 0/0 -d 172.18.250.76 -p tcp --dport 80 -m state --state NEW -j ACCEPT

     对于协议连接的会把连接状态记录在一张表里,在/proc/sys/net/nf_conntrack里,可以调整该表的大小,可通过调整/proc/net/ nf_conntrack_max的值,对于连接超时的状态对从表里进行删除,但一旦表满载的话,会导致后续的tcp连接超时。

     对于不同的协议的连接追踪时长也不同,可以通过/proc/sys/net/netfilter文件查看。


解决tcp连接超时的办法:

     1、加大nf_conntrack_max的值     

]# vim /etc/sysctl.conf
net.ipv4.nf_conntrack_max = 393216
net.ipv4.netfilter.nf_conntrack_max = 393216

     2、降低nf_conntrack条目的超时时长

]# vim /etc/sysctl.conf
net.ipv4.netfilter.nf_conntrack_tcp_timeout_established = 300
net.ipv4.netfilter.nf_conntrack_tcp_timeout_time_wait = 120
net.ipv4.netfilter.nf_conntrack_tcp_timeout_close_wait = 60
net.ipv4.netfilter.nf_conntrack_tcp_timeout_fin_wait = 120

     如何开放被动模式的ftp服务?   

            对于ftp的连接追踪需要加载ftp模块

]# modprobe  nf_conntrack_ftp
]# iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
]# iptables -A INPUT -d 172.18.250.76 -p tcp --dport 21 -m state --state NEW -j ACCEPT
]# iptables -A OUTPUT -s 172.18.250.76 -p tcp --dport 21 -m state --state ESTABLISHED -j ACCEPT

   如何保存编写好的iptables?

[root@localhost ipv4]# service iptables save
[root@localhost ipv4]# chkconfig iptables on

 FORWARD链:

           前提准备:

                    一台内网虚拟机:10.0.1.22/24,网关设置为10.0.1.2

                    一台转发虚拟机:172.18.250.76,10.0.1.2/24

                    一台外网虚拟机:172.18.250.77

开启核心转发功能:

[root@localhost ipv4]# vim /etc/sysctl.conf 
# Controls IP packet forwarding
net.ipv4.ip_forward = 1
[root@localhost ipv4]# /sbin/sysctl -p          //让参数立即生效

测试能否ping通:   

]# ping 10.0.1.2
PING 10.0.1.2 (10.0.1.2) 56(84) bytes of data.
64 bytes from 10.0.1.2: icmp_seq=1 ttl=64 time=11.0 ms
]# ping 172.18.250.76
PING 172.18.250.76 (172.18.250.76) 56(84) bytes of data.
64 bytes from 172.18.250.76: icmp_seq=1 ttl=64 time=1.96 ms

注意:如果内网虚拟机没有设置网关为10.0.1.2的话,是ping不同172.18.250.76的。

]# ping 172.18.250.76
PING 172.18.250.77 (172.18.250.77) 56(84) bytes of data.    //这次没设置网关

 这是因为内网虚拟机不知道改把报文发送给谁,没网关就不能跨网进行通信,只能在本地局域网通信

]# ping 172.18.250.77
PING 172.18.250.77 (172.18.250.77) 56(84) bytes of data.  //恢复网关后ping外网虚拟机

在外网服务器上抓包:

[root@localhost rules.d]# tcpdump -i eno16777736 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eno16777736, link-type EN10MB (Ethernet), capture size 65535 bytes
15:53:34.430441 IP 10.0.1.22 > 172.18.250.77: ICMP echo request, id 262, seq 48, length 64
15:53:34.430597 IP 172.18.250.77 > 10.0.1.22: ICMP echo reply, id 262, seq 48, length 64

这时可以看到报文已经到达了172.18.250.77,也返回了ping应答,但是内网虚拟机接受不到,是因为外网虚拟机会在本地找10.0.1.22的主机,或者通过设定的路由条目返回给其他10.0.1.22的主机。所以内网虚拟机接受不到。只要添加一个路由条目,指定到达10.0.1.0的网络通过172.18.250.76

[root@localhost rules.d]# route add -net 10.0.1.0/24 gw 172.18.250.76
4]# ping 172.18.250.77
PING 172.18.250.77 (172.18.250.77) 56(84) bytes of data.
64 bytes from 172.18.250.77: icmp_seq=453 ttl=63 time=1.98 ms   //添加完就可以通了

以上都是在iptables没任何规则测试的。。。

把FORWARD的策略改成DROP后:

    设置内网可以ping外网,外网不能Ping内网:

]# iptables -A FORWARD -s 10.0.1.22 -p icmp --icmp-type 8 -j ACCEPT 
]# iptables -A FORWARD -d 10.0.1.22 -p icmp --icmp-type 0  -j ACCEPT

    设置外网可以Ping内网:

]# iptables -A FORWARD -s 172.18.0.0/16 -d 10.0.1.22 -p icmp --icmp-type 8  -j ACCEPT
]# iptables -A FORWARD -d 172.18.0.0/16 -s 10.0.1.22 -p icmp --icmp-type 0  -j ACCEPT


处理动作:

    LOG:开启日志记录功能,要放在reject或drop,accept处理动作之前                

                    --log-level level       日志级别  error、warn

    --log-prefix prefix     日志行前缀

]# iptables -A FORWARD -s 10.0.1.0/24 -p tcp --dport 80 -m state --state NEW -j LOG --log-prefix "new connctions: "
]# iptables -A FORWARD -s 10.0.1.0/24 -p tcp --dport 80 -m state --state NEW -j ACCEPT

    RETURN:返回调用者,默认是存在

]# iptables -N web
]# iptables -A web -s 10.0.1.0/24 -p tcp --dport 80 -m state --state NEW -j ACCEPT
]# iptables -I web -m state --state ESTABLISHED -j ACCEP
]# iptables -A FORWARD -p tcp -j web                  //调用web链
]# iptables -A FORWARD -s 10.0.1.0/24 -p tcp --dport 22 -m state --state NEW -j ACCEPT
              //没写返回调用者,依然能远程登录外网
]# iptables -A web -j RETURN  //返回调用者

    REDIRECT:端口重定向   应用在PREROUTING上重定向

                --to-ports port

]# iptables -t nat -A PREROUTING -d 172.18.250.77 -p tcp --dport 80 -j REDIRECT --to-ports 8080

         SNAT:源地址转换 (主机是客户端,向外访问) 在POSTROUTING链实现转换

         修改IP报文中的源IP地址

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

               请求:修改源IP,如果修改则由管理员定义

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

                --to-source ipaddr

       --random: 端口随机

]# iptables -t nat -A POSTROUTING -s 10.0.1.0/24 -j SNAT --to-source 172.18.250.76

    MASQUERADE:   应用在动态拨号获得IP地址的,POSTROUTING,需要消耗额外的资源,静态地址不建议

                当源地址为动态获取的地址时,MASQUERADE可自行判断要转换为的地址

    --to-ports port[-port]

]# iptables -t nat -A POSTROUTING -s 10.0.1.0/24 -j MASQUERADE

            DNAT:目标地址转换 (主机是服务器,外网访问进来),在PREROUTING链实现转换

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

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

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

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

                        --to-destination [ipaddr[-ipaddr]][:port[-port]]

        支持目标端口转换

]# iptables -t nat -A PREROUTING  -d 172.18.250.76 -p tcp --dport 80 -j DNAT --to-destination 10.0.1.22		       
]# iptables -t nat -A PREROUTING  -d 172.18.250.76 -p tcp --dport 80 -j DNAT --to-destination 10.0.1.22:8080   //请求的是80  但转换成真实的8080端口