为了保证安全,人们想了很多的办法;防火墙、杀毒软件、***检测系统、***防御系统等等可以说方式不少。其中,防火墙是唯一的防范于未然、将威胁扼杀于摇篮之中的一种常用方法,其他的方法都是发现安全威胁之后所采取的措施。所以可见防火墙的重要性。防火墙的实现可以包括两大类方式:硬件防火墙和软件防火墙。但是现在纯硬件防火墙造价太过昂贵,而且使用局限性也非常大,所以基于软件实现的防火墙几乎是主流,即便是所谓的硬件防火墙中也多是以软件程序来定制规则和驱动规则执行的。因此软件防火墙是非常常见的防火墙类型。在linux系统中,参考BSD系统的安全机制构建了防火墙系统,在linux 2.0中引入了ipfw的概念,但并不清晰;后来,linux 2.2中定义了ipchain,但功能仍不够完善;直到linux 2.4,在内核中定义了netfilter组件,并且在用户空间中应用iptables工具进行规则定义。至此,Linux系统中的防火墙解决方案变得完整了。在进一步的完善后,确立了iptables/netfilter的防火墙体系规范。

  也就是说,新的防火墙体系是由两部分组成的,即:位于内核空间中的netfilter组件以及位于用户空间中的iptables工具。

  在内核中的netfilter组件中,为了更精确的行使防火墙的功能,定义了五个HOOK点,分别为:

  NF_IP_PRE_ROUTING

  NF_IP_LOCAL_IN

  NF_IP_FORWARD

  NF_IP_LOCAL_OUT

  NF_IP_POST_ROUTING。

  这五个HOOK点分别用与之对应的函数实现。但是不管是HOOK点还是HOOK函数,都是内核里面的东东,用户是无法直接去操作的,因此人们想出了一个办法:在HOOK点上绑定规则。于是就产生了跟五个HOOK点像对应的五条规则链。规则链,顾名思义,就是绑定一系列规则的一个逻辑单元。他们分别是:PREROUTING、INPUT、FORWARD、OUTPUT、POSTROUTING。为了能够更好的描述规则和功能之间的关系,人们有在逻辑上定义了四张表,即:raw表、mangle表、nat表和filter表。四张逻辑表所包含的链如下:

  filter:INPUT、FORWARD、OUTPUT

  nat:PREROUTING、INPUT(CentOS7中引入)、OUTPUT、POSTROUTING

  mangle:PREROUTING、INPUT、FORWARD、OUTPUT、POSTROUTING

  raw:PREROUTING、OUTPUT

  注意:四张表的规则生效优先级从高到低依次为:raw、mangle、nat、filter。

  想要书写规则,最方便的方式就是使用用户空间中的工具——iptables了,接下来我们来重点讨论一下iptables工具的使用方法

# iptables [-t table] COMMAND CHAIN [rule_num] RULE_CONDITION -j TARGET


table:

  如果省略table不写,则默认修改filter表的规则;如果想要修改其他表的规则,必须将该表名显式给出方可。

COMMAND:

  链管链类的命令
   -P:设置链的默认规则
   -F:清空指定链的所有规则,如果没有指定链,则清空该表中所有链上的规则设置。    
   -N:创建自定义链
   -X:删除自定义的空链
   -E:修改自定义链的名称
   -Z:清空各个链上的计数器
    计数器共有两个:
     统计匹配的数据包的个数
     统计匹配的数据包的总的字节数   

  规则管理类的命令
   -A:向指定表的指定链中追加规则
   -I #:向指定表的指定链中插入规则,默认插入规则成为第一条
   -D #:删除指定表中指定链上的指定编号的规则
   -R:替换指定表中指定链上的规则
  查看的命令
   -L:查看指定表中指定链上的已配置的规则
    --line-numbers
    -n,--numeric:数字化显示所有的主机名和端口号
    -v,--verbose:显示更加详细的信息,-vv
    -x,--exactly:显示精确值,不要做单位换算;


CHAIN:

  PREROUTING、INPUT、FORWARD、OUTPUT、POSTROUTING之一。注意:选择的链必须在逻辑功能上与所选择的表能够对应起来,否则就会报错

rule_num:

  规则编号,有些链管理类或规则管理类操作命令,在书写的时候为了保证其执行结果更加精确,需要指定规则编号。

TARGET:
  ACCEPT:允许转发,接受
  DROP:拒绝转发,丢弃
  REJECT:拒绝转发,同时告知拒绝转发的原因
  REDIRECT:重定向数据流向
  LOG:做日志记录
  SNAT:源地址转换
  DNAT:目的地址转换
  MASQUERADE:过载,地址伪装,端口地址复用
  MARK:打标记,做标记,FWM

其中,ACCEPT、DROP、REJECT和LOG一般都会在选择了filter表之后的动作中使用;SNAT、DNAT、REDIRECT和MASQUERADE一般都会在选择了nat表之后的动作中使用;MAKR一般会在mangle表之后为数据做防火墙标记而使用;


CONDITION:
  通用匹配
  -s:匹配源地址,省略此选项,即匹配所有的源IP地址。地址可以写成:
    1.IP:192.168.100.1
    2.NETWOEK:192.168.100.0/24
  -d:匹配目标地址,省略此选项,即匹配所有的目标IP地址。地址可以写成:
    1.IP:192.168.100.1
    2.NETWOEK:192.168.100.0/24
  -p:协议
    通常包括tcp、udp、icmp
  -i:input-interface,入站接口,一般只能与INPUT链和PREROUTING链使用;
    -i eth0
  -o:output-interface,出站接口,一般只能与OUTPUT链和POSTROUTING链使用;
    -o eth1
    如果不给出这两个选项,则默认匹配所有的入站和出站接口

  扩展匹配
   隐含扩展
    -p {tcp|udp|ip|icmp}:
     tcp|udp两个选项
      [!] --source-port,--sport port[:port]:源端口号。
      [!] --destination-port,--dport port[:port]:目标端口号。

      端口号可以是:
       port:单一端口
       port: :不小于指定的端口号的所有连续端口
       :port :不大于指定的端口的所有连续端口
       port1:port2:区间内的所有连续端口
            
     tcp其他的选项:
      --tcp-flags:匹配检查TCP首部中的标志位
      --tcp-flags mask comp
       mask:在匹配的过程中必须检查的标志位的列表
       comp:在匹配的过程中必须置1的标志位的列表
     例子:
      --tcp-flags SYN,ACK,FIN,RST SYN  =  --syn

     icmp协议
      --icmp-type
       0:echo-reply(pong)
       8:echo-request(ping)

例:
只是放行从192.168.100.0/24中的主机到192.168.100.1的SSH通信,并且只允许192.168.100.1主机ping通其他主机,其余的到达192.168.100.1主机的网络访问都不被允许。

# iptables -A INPUT -s 192.168.100.0/24 -d 192.168.100.1 -p tcp --dport 22 -j ACCEPT
# iptables -A INPUT -d 192.168.100.1 -p icmp --icmp-type 0 -j ACCEPT
# iptables -A INPUT -j DROP
# iptables -A OUTPUT -s 192.168.100.1 -d 192.168.100.0/24 -p tcp --sport 22 -j ACCEPT
# iptables -A OUTPUT -s 192.168.100.1 -p icmp --icmp-type 8 -j ACCEPT
# iptables -A OUTPUT -j DROP

   显式扩展(-m 模块名称)
    1.离散多端口指定模块
     -m multiport
      --source-ports,--sports:指定离散的源端口
      --destination-ports,--dports:指定离散的目的端口
      --ports:指定离散的端口,可以匹配源端口,也可以匹配目的端口
例:
允许192.168.100.1主机上的ssh、http和samba服务被访问:

# iptables -A INPUT -d 192.168.100.1 -p tcp -m multiport --dports 22,80,135,137,139,445 -j ACCEPT
# iptables -A INPUT -j DROP
# iptables -A OUTPUT -s 192.168.100.1 -p tcp -m multiport --sports 22,80,135,137,139,445 -j ACCEPT
# iptables -A OUTPUT -j DROP

    2.来自同一客户端得并发连接数显示
     -m connlimit:(连接数限制)
      --connlimit-upto #:规定同一客户端ip地址能够发起的并行连接的上限
      --connlimit-above #:规定同一客户端ip地址能够发起的并行连接的上限
例:
主机192.168.100.1允许每台客户端主机通过telnet最多能建立两个连接:

# iptables -A INPUT -d 192.168.100.1 -p tcp --dport 23 -m connlimit --connlimit-upto 2 -j ACCEPT
# iptables -A INPUT -j DROP

    3.利用令牌桶机制来限制服务器能够处理的请求连接的上限
     -m limit    
      --limit num/{second|minute|hour|day}:限制单位时间内的访问次数
      --limit-burst number:限制第一次突发性访问量
例:
主机192.168.100.1允许每台客户端主机每分钟ping通10次,第一次不允许超过8个:

# iptables -A INPUT -d 192.168.100.1 -p icmp --icmp-type 8 -m limit --limit 10/minute -j ACCEPT
# iptables -A INPUT -d 192.168.100.1 -p icmp --icmp-type 8 -m limit --limit-burst 8 -j ACCEPT
# iptables -A INPUT -j DROP

    4.对于字符串内容进行限制
     -m string
      --algo {bm|kmp}
      --string "string"
例:
主机192.168.100.1的网站服务提供的web页面中不允许包含“admin”字符串:

# iptables -A INPUT -d 192.168.100.1 -p tcp -m multiport --dports 22,80 -j ACCEPT
# iptables -A INPUT -j DROP
# iptables -A OUTPUT -s 192.168.100.1 -p tcp --sport 80 -m string --string "admin" --algo kmp -j DROP
# iptables -A OUTPUT -s 192.168.100.1 -p tcp -m multiport --sports 22,80-j ACCEPT
# iptables -A OUTPUT -j DROP

    5.指定报文的合法到达的时间;
     -m 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...]
例:
服务器192.168.100.1只允许在工作日的工作时间被客户端访问:

# iptables -I INPUT -d 192.168.100.1 -m time --timestart 09:00:00 --timestop 18:00:00 --weekdays Mon,Tue,Wed,Thu,Fri -j ACCEPT
# iptables -A INPUT -j DROP

    6.限制连续的不可划分子网的一段IP地址范围
     -m iprange
      --src-range from[-to]
      --dst-range from[-to]
例:
只允许IP地址范围在192.168.100.3-192.168.100.50之间的客户端可以通过ssh远程连接到服务器192.168.100.1:

# iptables -A INPUT -m iprange --src-range 192.168.100.3-192.168.100.50 -d 192.168.100.1 -p tcp --dport 22 -j ACCEPT
# iptables -A INPUT -j DROP
# iptables -A OUTPUT -s 192.168.100.1 -p tcp --sport 22 -j ACCEPT
# iptables -A OUTPUT -j DROP

    7.连接状态模块
     -m state
      --state {NEW|ESTABLISHED|RELATED|INVALID|UNTRACKED}
       NEW:还没有进行任何的通信,第一次发送数据的状态
       ESTABLISHED:第一次发送数据成功以后的状态
       RELATED:关联状态,衍生状态
       INVALID:无效状态,不可识别状态
       UNTRACKED:未追踪的连接;
例:允许192.168.100.1主机上的ssh、ftp、http服务被192.168.100.0/24网段内的主机访问,同时FTP可以使用被动连接模式传输数据。

# iptables -A INPUT -s 192.168.100.0/24 -d 192.168.100.1 -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A INPUT -s 192.168.100.0/24 -d 192.168.100.1 -p tcp -m multiport --dports 21,22,80 -m state --state NEW -j ACCEPT
# iptables -A INPUT -j DROP
# iptables -A OUTPUT -s 192.168.100.1 -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A OUTPUT -j DROP

LOG——只是记录日志而并不涉及到数据的过滤的TARGET
  --log-level number{0-7}
  --log-prefix prefix(29 characters)

# iptables -I INPUT -s 192.168.100.0/24 -d 192.168.100.1 -p tcp --dport 22 -j LOG --log-prefix (:iptables:)

filter表过滤规则优化方案:
  对于主机防火墙来说:
   (1) 可安全放行当前服务器主机上所有入站及出站,且状态为ESTABLISHED和RELATED的连接;
   (2) 服务于同一类功能的规则,匹配条件范围越小的放前面,范围大的放后面;
   (3) 服务于不同类功能的规则,匹配报文可能性较大的放前面,可能性较小的放后面;
   (4) 设置默认策略;
    a) 最后一条规则设定为默认阻止所有数据包流入或流出服务器(推荐);
    b) 设置规则链的默认策略为阻止所有数据包流入或流出;
  对于网络防火墙来说:
   除了上述的规则外,还需要格外的注意FORWARD链的规则:
   (1) 注意区分内网军事化区域、内网非军事化区域以及外部网络;
   (2) 所有来自内部非军事化区域和外部网络的状态为NEW的报文统统拒绝;
   (3) 内网军事化区域可以访问内网非军事化区域和外部网络中的服务器的各种服务;
   (4) 内网非军事化区域中的服务器上的特定网络服务允许被外部网络访问。


  为了能够保存已经书写好的防火墙规则,提供了/etc/rc.d/init.d/iptables脚本,该脚本的功能不是将iptables当作服务启动,而是方便的帮助管理员加载已经定义好的规则和所需要加载的扩展模块。
一般我们可以使用下述命令来进行规则的保存和恢复:

  在CentOS6中:

#  service iptables save
#  service iptables restore|restart

也可以实用下述命令:

# iptables-save > /PATH/TO/SOME_RULE_FILE
# iptables-restore < /PATH/FROM/SOME_RULE_FILE

在CentOS7中,只能使用后面的两行命令来保存和恢复规则。


nat表
nat表中虽然可以包括PREROUTING、POSTROUTING、OUTPUT和INPUT(在CentOS7中新增),但最常用的还是PREROUTING链和POSTROUTING链。
  PREROUTING:DNAT
   内部网络中的服务器可以被互联网中或其他外部网络中的主机访问。
  POSTROUTING:SNAT
   内部客户端主机能够接入到互联网或其他外部网络,访问其中的主机。


目标地址转换——DNAT动作
  这个目标只在nat表中的PREROUTING链和OUTPUT链以及被这些主链调用的自定义链上有效。
  常用选项:--to-destination [ipaddr[-ipaddr]][:port[-port]]
例:
将内部的地址为192.168.100.1的服务器的地址发布为172.16.0.1:

# iptables -t nat -A PREROUTING -d 172.16.0.1 -p tcp --dport 80 -j DNAT --to-destination 192.168.100.1:80

源地址转换——SNAT动作
  这个目标只在nat表中的POSTROUTING链和INPUT(CentOS7中)链以及被这些主链调用的自定义链上有效。
  常用选项:--to-source [ipaddr[-ipaddr]][:port[-port]]
例:
允许内部网络192.168.100.0/24连接外部网络:

# iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -j SNAT --to-source 172.16.0.1
//静态源地址转换
# iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -j MASQUERADE
//动态源地址转换,无需指定,自动根据接口上生效的IP地址进行地址转换


端口重定向——REDIRECT动作
  这个目标只在nat表中的PREROUTING链和OUTPUT链以及被这些主链调用的自定义链上有效。
  常用选项:--to-ports port[-port]   
例:
如果有客户机访问到服务器的172.16.0.1地址的80端口时,转换为8088端口继续访问:

# iptables -t nat -A PREROUTING -d 172.16.0.1 -p tcp --dport 80 -j REDIRECT --to-port 8088