Linux防火墙iptables管理与应用

Firewall

工作于网络(网络防火墙)或主机(主机防火墙)的边缘(通信报文的进出口),对于进出本网络或主机的报文根据事先定义的检查规则作匹配检测,对于能够被规则匹配到的报文作出相应处理

发展历程: ipfw-->ipchains-->iptables

iptables/netfilter

  • netfilter: 是kernel代码
    hooks function
    iptables: cli,是命令行程序
  • rules utility

netfilter有5个钩子:路由前,路由后,input输入队列,output输出队列,forward转发队列
netfilter:有5个钩子函数
prerouting,input,forward,output,postrouting

报文流向:
流入本机:prerouting --> input ==> 用户空间进程;
流出本机:用户空间进程==> output --> postrouting;
转发:prerouting --> forward --> postrouting;

iptables有五个内置规则链(名称需大写)

PREROUTING
INPUT
FORWARD
OUTPUT
POSTROUTING

自定义链:要手动添加关联关系钩子函数上才起作用

五个内置规则分别对应的iptables在linux系统中作用的五个位置
PREROUTING 对应 从网卡进入到内核空间中
INPUT 对应 从内核空间到用户空间
FORWARD 对应 从一个网卡转发到另一个网卡
OUTPUT 对应 从用户空间到内核空间
POSTROUTING 对应 从内核空间到网卡

内置规则链逻辑图

iptables自身内置的四种功能表

  • filter:实现过滤,防火墙
  • nat:network address translation,相当于mangle中的一部分功能,(修改ip层地址,传输层地址);主要完成源和目标IP、源和目标端口的修改;
  • mangle:实现拆解报文,按需修改之后,重新封装
  • raw:关闭在nat表上启用的连接追踪机制

表和链的对应关系

表<==>链

  • filter表对应:INPUT, FORWARD, OUTPUT链
    过滤功能要在以上3个钩子上进行;
  • mangle表对应:PREROUTING, INPUT, FORWARD, OUTPUT, POSTROUTING链
  • nat表对应:PREROUTING, OUTPUT, POSTROUTING,INPUT链
  • raw表对应:PREROUTING, OUTPUT链
    都能实现地址转换

同一链上的不同的表的规则的应用优先级:由高到底
raw>mangle>nat>filter

数据包过滤匹配流程

报文到达本机,到达prerouting链,有三种功能,raw,mangle,nat;--> 路由选择
如果到内部input链有两功能,mangle,filter

iptables规则

组成部分:根据规则的匹配条件尝试匹配报文,对匹配成功的报文根据规则定义的处理动作作出处理;

规则要添加在链上,才生效;添加在自定义上不会自动生效;

  • 内置链:每个内置链对应于一个钩子函数;
  • 自定义链:用于对内置链进行扩展或补充,可实现更灵活的规则组织管理机制;
    只有钩子调用自定义链时,才生效;

链上的规则次序,即为检查的次序;因此,隐含一定的应用法则;
(1)同类规则(访问同一应用),匹配范围小的放上面
(2)不同类的规则(访问不同的应用),匹配到报文频率较大的放在上面;
(3)将那些可由一条规则描述的多个规则合并起来;
(4)设置默认策略;

添加规则的考量点:
(1)要实现何种功能:判断添加规则至哪个表上;
(2)确定报文流经的位置;判断添加规则至哪个链上;
功能确定了使用的钩子就确定了;
尽量定义在最开始处;

iptables命令

高度模块化,由诸多扩展模块实现其检查条件或处理动作的定义
/usr/lib64/xtables/
IPV6:libip6t_
IPV4:libipt_,libxt_

在centos7系统上,学习,建议:
systemctl stop firewalld.service
systemctl disable firewalld.service
在centos6系统上,学习建议:
service iptables stop
chkconfig iptables off

iptables格式:iptables [-t table] COMMAND chain [rulenum] [-m machename [per-match-options]] [-j targetname [per-target-options] [options]

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

rule-specification = [matches...] [target]
match = -m matchname [per-match-options]
target = -j targetname [per-target-options]

-t tables:指定表,不指定的话,默认为filter;
raw, mangle, nat, [filter]

[root@promote ~]# iptables -t nat -L
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         

SUBCOMMAND:实现增、删、改、查
链管理:
-N:新增一条自定义链;
-X:delete,删除自定义的空链;先清除规则,才能删除链;
-P:policy,设置链的默认策略;
①ACCEPT:接受;
②DROP:丢弃;不响应;
③REJECT:拒绝;

-E:rename,重命名自定义的未被引用的链;(引用计数为0)

规则管理:
-A:append,追加,默认为最后一个;
-I:insert,默认插入,默认为第一个;
-D:delete,删除,两种格式,指定规则或指定规则条数;
(1)rule specification
(2)rule number
-R:replace替换,类似-D,指明替换哪一条;rule number
-F:flush,清空规则表,冲刷规则,可冲表上的一条链,也冲掉一个表上的所有链,也可指明冲掉哪条链上的哪条规则;
-Z:zero,置0;给iptables计数器置0;

iptables的每条规则,都有两个计数器:
(1)有本规则匹配到的所有的packets
(2)由本规则匹配到的所有packets大小之和
-S:列出规则selected,以iptables-save命令的格式显示链上的规则;
可重定向保存规则;相当于iptables-save命令;

查看:
-L:list,列出规则;
-n:numeric,以数字格式显示地址和端口;禁止反解端口号对应的服务名;
-v:verbose,显示详细信息;支持-vv,-vvv
-x:exactly,显示计数器的精确值而非单位换算后的结果;
每一条iptables规则都有两个计数器,一个是被本规则记录匹配的报文个数,第二个被本规则记录匹配到的所有报文的大小,数值大时自动显示换算单位,但结果不准确;
--line-numbers:显示链上的规则的编号;

[root@promote ~]# iptables -L -n --line-numbers
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination         
1    ACCEPT     udp  --  0.0.0.0/0            0.0.0.0/0            udp dpt:53
2    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:53
3    ACCEPT     udp  --  0.0.0.0/0            0.0.0.0/0            udp dpt:67
4    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:67
5    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
6    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
7    INPUT_direct  all  --  0.0.0.0/0            0.0.0.0/0           

这就是为什么-D删除规则条目时,有两种方式,一是指明规则编号,二是指明具体规则;

组合使用:-nvL,L要写在后面;

[root@promote ~]# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     udp  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            udp dpt:53
    0     0 ACCEPT     tcp  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:53
    0     0 ACCEPT     udp  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            udp dpt:67
    0     0 ACCEPT     tcp  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:67
   50  3796 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    0     0 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0           
    3   429 INPUT_direct  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    3   429 INPUT_ZONES_SOURCE  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    3   429 INPUT_ZONES  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate INVALID
    3   429 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited

常见用法

iptables -nL 查看防火墙设置;没指明任何表,查看filter,在3个链上INPUT,FORWARD,OUTPUT;
iptables -t nat -nL 查看nat表,可出现在4个链上PREROUTING,INPUT,OUTPUT,POSTROUTING;
注意:在centos6系统上,nat表不能在INPUT上;

iptables -t mangle -nL 查看mangle表,可出现5个链;

iptables -t raw -nL 查看raw表,可出现2个链;其中policy ACCEPT叫默认策略;

iptables -E testchain mychain 重命名自定义链为mychain;

iptables -X mychain 只能删除空链;

iptables -t filter -P FORWARD DROP 设定FORWARD默认策略,过滤为丢弃转发,-t filter可省略;
注意:使用远程连接时,不能把input改为drop否则无法连接;

iptables -P INPUT DROP 设置INPUT默认策略;
iptables -P OUTPUT DROP 设置OUTPUT默认策略;

iptables -nL INPUT 查看指定某个链上的规则;

iptables -nvL 查看详细信息,可显示可易读的单位;
iptables -nvxL 查看详细信息,且显示单位为字节;
iptables -nvxL --line-number 显示规则编号;
iptables -nvvxL --line-number 显示更详细信息;
iptables -nvvvxL --line-number 显示更多更详细信息;

iptables -S 显示添加的规则命令;
iptables -S INPUT

匹配条件:matches

rpm -ql iptables 查看安装后生成的文件
其中:
以小写字母.so结尾的一般为matches模块;例如:/usr/lib64/xtables/libxt_addrtype.so
以大写字母.so结尾的一般为target模块;例如:/usr/lib64/xtables/libipt_REJECT.so

写每一条规则时,怎么处理的叫做target,指明匹配条件叫做matches;纯小写字母模块是用来扩展匹配条件的,纯大写字母的模块是用来扩展怎么处理的;

基本匹配:netfilter自带的匹配机制

[!] -s, --source address[/mask][,...]:指明原地址(范围)匹配;叹号表示取反;
[!] -d, --destination address[/mask][,...]:目标地址匹配;
[!] -i, --in-interface name:限制报文流入的接口,只能用于PREROUTING,INPUT,FORWARD链上;用于前半段;
[!] -o, --out-interface name:限制报文流出的接口,只能用于OUTPUT,FORWARD,POSTROUTING链上;用于后半段;
[!] -p{tcp|udp|icmp}:限制协议;

用法

此时在本机地址为172.18.11.114,在远程主机172.18.11.111不能ping通,ssh链接也无法登录;
iptables -A INPUT -s 172.18.0.0/16 -j ACCEPT 指定原IP地址可入栈,目标地地址不限制;
iptables -A OUTPUT -d 172.18.0.0/16 -j ACCEPT 指定目标IP地址可出栈,源地址不限制,肯定为本机地址;
此时172.18.11.111可ping通本地主机

设置仅172.18.11.112能连接本机;
iptables -A INPUT -s 172.18.11.112 -d 172.18.11.114 -j ACCEPT 设置入栈放行;
iptables -A OUTPUT -d 172.18.11.112 -s 172.18.11.114 -j ACCEPT 设置出栈放行;
此时,只有172.18.11.112能ping同本地主机;

设置处理除了172.18.11.112不能连接本机,其它主机均可连接;
iptables -A INPUT ! -s 172.18.11.112 -d 172.18.11.114 -j ACCEPT
iptables -A OUTPUT ! -d 172.18.11.112 -s 172.18.11.114 -j ACCEPT
此时,只有172.18.11.112不能连接本地主机;

设置仅允许172.18网段的tcp连接本机
iptables -A INPUT -s 172.18.0.0/16 -d 172.18.11.114 -p tcp -j ACCEPT
iptables -A INPUT -s 172.18.0.0/16 -d 172.18.11.114 -p tcp -j ACCEPT
此时,在172.18.11.111主机不能ping通本机,但可以ssl本机;

注意:ping不通不能说明不能访问,每一种协议都有专用的扩展;可扩展的内容就是协议中的部分字段;

使用at设置定时计划任务定义2小时后,清空规则把所有策略改为accept,以防自己设定规则后,被禁止登陆;

扩展匹配:经由扩展模块引入的匹配机制,使用: -m matchname

扩展匹配分为两类:

  • 隐式扩展:可以不使用-m选项专门加载相应模块;前提是要使用-p选项可匹配何种协议;
    [!] -p {tcp|upd|icmp}:限制协议;每个协议都有专用的扩展条件;
  • 显示扩展:明确指定扩展,使用-m指明扩展模块;
隐式扩展:使用-p或--Protocol

[!] -p,--protocol PROTOCOL PROTOCOL;
协议:tcp,udp,icmp,icmpv6,esp(有效载荷协议),ah(验证头协议),sctp(流控协议),mh或all

tcp:隐含指明了-m tcp
[!] --source-port,--sport port[:port]:匹配报文中的tcp首部的源端口,可以是端口范围;
: port表示为从0开始到指定的端口;
port :表示为从指定端口开始到最大端口;
[!] --destination-port,--dport port[:port]:匹配报文中的tcp首部的目标端口,可以是端口范围;
[!] --tcp-flags mask comp:检查报文中mask指明的tcp标志位,而要这些标准位comp中必须为1;

例如:
--tcp-flags syn,fin,ack,rst syn 表示检查tcp第一次握手中的4个标志位,syn必须为1,其它3个必须为0;
--tcp-flags syn,fin,ack,rst ack,fin 表示检查tcp四次断开中,请求断开的报文,4个标志位,ack,fin必须为1,其它2个必须为0;

[!] --syn:用于匹配第一次握手,相当于“--tcp-flags syn,fin,ack,rst syn”

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 回显应答
8/0: echo request ping请求

注意:如果要设置默认DROP的策略,建议只开放指定主机IP地址ssh服务,以便能远程登录;
例如:
yum -y install httpd vsftpd telnet-server samba
开启以上安装的服务

用法

放行本地主机ssh服务,任意主机可远程登录本机
iptables -A INPUT -s 0/0 -d 172.18.11.114 -p tcp --dport 22 -j ACCEPT 入栈规则,-s 0/0可省略默认为所有地址;
iptables -A OUTPUT -s 172.18.11.114 -d 0/0 -p tcp --sport 22 -j ACCEPT 出栈规则;
iptables -P INPUT DROP 默认策略设为禁止访问;所有服务禁止访问本机;
浏览器不能访问172.18.11.114网页;

开放本机80端口
iptables -A INPUT -d 172.18.11.114 -p tcp --dport 80 -j ACCEPT 入栈规则;
iptables -A OUTPUT -s 172.18.11.114 -p tcp --sport 80 -j ACCEPT 出栈规则;
浏览器可访问172.18.11.114网页;

DNS服务器中的udp协议:
本机为DNS服务器时,开放给所有主机服务,此时本机为服务器端,入栈的是客户端请求,目标端口为本机53,响应时出栈为本机53端口;当解析不了时,还有迭代方式去查询顶级DNS服务器等,此时本机为客户端,出栈为本机随机端口,目标端口为别人的53端口,入栈时源端口是别人的53,目的端口为本机随机端口;在这2种场景中,写规则时的入栈和出栈是不同的;要添加4条规则;因为有2条入栈,2条出栈;

ping命令中的ICMP协议:
其中:
00 协议类型和代码:表示ping应答;
80 协议类型和代码:表示ping请求;

本机被ping时,别人的请求时,icmp协议类型,入栈为8,出栈是0;
本机ping别人时,icmp协议类型,出栈是8,入栈是0;
允许自己png别人,禁止别人ping自己:
iptables -A OUTPUT -s 172.18.11.114 -d 0/0 -p icmp --icmp-type 8 -j ACCEPT 出栈设置
iptables -A INPUT -s 0/0 -d 172.18.11.114 -p icmp --icmp-type 0 -j ACCEPT 入栈设置

开放别人可ping自己:
iptables -A INPUT -d 172.18.11.114 -p icmp --icmp-type 8 -j ACCEPT 入栈设置
iptables -A OUTPUT -s 172.18.11.114 -p icmp --icmp-type 0 -j ACCEPT 出栈设置

显示扩展

multiport:多端口匹配
以离散方式定义多端口匹配,最多可以指定15个端口;

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

例如:显示扩展,多端口一条规则指明:开放22和80端口:
iptables -I INPUT -s 0/0 -d 172.18.11.114 -p tcp -m multiport --dports 22,80 -j ACCEPT
iptables -I OUTPUT -d 0/0 -s 172.18.11.114 -p tcp -m multiport --sports 22,80 -j ACCEPT

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

iptables -I INPUT -d 172.16.0.67 -p tcp --dport 23 -m iprange --src-range 172.16.0.60-172.16.0.70 -j ACCEPT
iptables -I ONPUT -s 172.16.0.67 -p tcp --sport 23 -m iprange --dst-range 172.16.0.60-172.16.0.70 -j ACCEPT

string:对报文中的应用层数据做字符串匹配检测;对内核版本要大于2.6.14
--algo {bm|kmp}:算法
(mbboyer-moore,kmp=knuth-pratt-morris)
[!] --string pattern:给定要检查的字符串模式;
[!] --hex-string pattern:给定要检查的字符串模式,十六进制;

注意:要把匹配严格的规则放在松散规则之上;如果target相同,松散的放上面,如果target不同,严格的规则放上面;

例如:禁止响应页面内容有test字样
iptables -I OUTPUT -s 172.18.11.114 -d 0/0 -p tcp --sport 80 -m string --algo bm --string "test" -j REJECT

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

例如:在工作时间内9:00-16:00,放行访问telnet服务
iptables -R INPUT 4 -d 172.18.11.114 -p tcp --dport 23 -m iprange --src-range 172.18.11.1-172.18.11.111 -m time --timestart 09:00:00 --timestop 16:00:00 --weekdays 1,2,3,4,5 -j ACCEPT

connlimit:根据每客户端做并发连接数限制,即每客户端最多发起的连接数量
--connlimit-upto n:连接数量小于等于n,则匹配;
--connlimit-abvoe n:连接数量大于n则匹配;

例如:限制每台主机访问telnet最大并发数为2个
iptables -A INPUT -s 0/0 -d 172.18.11.114 -p tcp --dport 23 -m connlimit --connlimit-upto 2 -j ACCEPT

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

限制本机某tcp服务接受新请求的速率:--syn,-m limit

例如:允许别人ping设置一分钟20包,突发值为3,表示一次ping需要3秒;
iptables -R INPUT 5 -d 172.18.11.114 -p icmp --icmp-type 8 -m limit --limit 20/minute --limit-burst 3 -j ACCEPT

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

状态 作用
INVALID 无法识别的连接
ESTABLISHED 连接追踪模板当中存在的记录的连接
NEW 连接追踪模板当中不存在的连接请求
RELATED 相关联的连接
UNTRACKED 未追踪的连接

模板记录占满时,再有请求会被超时处理;
通常前端负载均衡器通常不要开启连接追踪功能;

已经追踪到的并记录下来的连接(保存位置):/proc/net/nf_conntrack

例如:查看已追踪并记录到的连接信息;
cat /proc/net/nf_conntrack

连接追踪功能所能够记录最大连接数量:(可调整)
/proc/sys/net/nf_conntrack_max

调整内核参数,使用echo重定向,或使用syctemctl命令
例如:设置记录最大连接数为300000
systemctl -w net.nf_conntrack_max=300000
echo 300000 > /proc/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/有很多timeout文件中定义;

例如:允许172.18网段访问,本机的telnet,ssh,web服务

iptables -F 清空规则,默认均为拒绝访问
iptables -A INPUT -s 172.18.0.0/16 -d 172.18.11.114 -p tcp -m multiport --dports 22,23,80 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -d 172.18.0.0/16 -s 172.18.11.114 -p tcp -m multiport --sports 22,23,80 -m state --state ESTABLISHED -j ACCEPT

开放ping请求,让别人能ping进来

iptables -A INPUT -d 172.18.11.114 -p icmp --icmp-type 8 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -s 172.18.11.114 -p icmp --icmp-type 0 -m state --state ESTABLISHED -j ACCEPT

越匹配到报文规则的越要放前面;同类规则中匹配范围小的要放前面;

如何放行被动的ftp服务:
(1)内核加载nf_conntrack_ftp模块;
modprobe nf_conntrack_ftp
(2)放行命令连接
iptables -A INPUT -d 原ip服务器地址 -p tcp --dport 21 -m state --state NEW,ESTABLIEHED -j ACCEPT
iptables -A OUTPUT -s 原ip服务器地址 -p tcp --sport 21 -m state --state ESTABLIEHED -j ACCEPT
(3)放行数据连接
iptables -A INPUT -d 服务器原ip地址 -p tcp -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -s 服务器原ip地址 -p tcp -m state --state ESTABLISHED -j ACCEPT

处理动作(跳转目标)

-j targetname [per-target-optons]

简单target:ACCEPT,DROP

拓展target
REJECT:--reject-with type

target
RETURN 返回调用者;自定义链的最后一条定义
REDIRECT 端口重定向
LOG 日志
MARK 防火墙标记
DNAT 目标地址转换
SNAT 原地址转换
MASQERADE 地址伪装

查看帮助文档:man iptables-extensions

LOG:开启内核关于匹配到的报文日志记录规则
--log-level level
可用日志级别:emerg, alert, crit, error, warning, notice, info,debug
--log-prefix prefix 日志行前缀,最长29个字母;
说明对应的日志信息,是由谁产生的;
--log-ip-options
记录在tcp或ip报文首部中有可变长的可选项信息;

例如:
iptables -I FORWARD 2 -s 10.0.1.0/24 -p tcp -m multiport --dports 80,22,23,21 -m state --state NEW -j LOG --log-prefix "new connctions: "

注意:target为log日志规则时,应添加在accept、drop、reject规则之前;所以先做日志,再做其它的规则;

例如:
iptables -I FORWARD 2 -s 10.0.1.0/24 -p tcp -m multiport --dports 80,22,23,21 -m state --state NEW -j LOG --log-prefix "new connctions: "
iptables -vnL
有访问80的web服务时,可查看日志记录;
tail /var/log/messages

RETUREN:返回调用者;隐含的;

例如:
iptables -A web -j RETURN

例如:

iptables -F
iptables -N web  创建自定义链
iptables -vnL
iptables -A web -s 10.0.1.0/24 -p tcp --dport 80 -j ACCEPT  添加web链规则,允许本地主机访问web服务
iptables -I web 1 -m string --algo kmp --string "old" -j REJECT  插入第1条web链,包含了old字符串的页面禁止访问
只要状态是ESTABLISHED应放行;
iptables -I web 2 -p tcp -m state --state ESTABLISHED -j ACCEPT 插入web链第2条,放行状态是ESTABLISHED;

此时,内网用户访问web服务:不能访问
curl httpd://172.18.11.111
是不能访问的,因为自定义链不会直接生效的,只有被调用才生效;
iptables -A FORWARD -p tcp -j web 在forward链上调用web自定义链;
此时,内网用户就能访问web服务了;

再放行ssh服务:
iptables -A FORWARD -s 10.0.1.0/24 -p tcp --dport 22 -m state --state NEW -j ACCEPT 由内而外放行请求的报文,虽然没有放行响应的报文,但是在web自定义链上的规则已经放行了; 此时,内网主机访问ssh:ssh root@172.18.11.111` 成功访问;
在web链上默认的隐含了返回调用者;

显式指明返回调用者:
iptables -A web -j RETURN 表示web链匹配不到就返回调用者;

REDIRECT
端口重定向,只能用在nat表上的preroutingoutput链上,只有在入栈报文请求刚到达时,才有用,在其它场景都没有意义;能实现指明的端口完成映射;

--to-ports port 映射的指定端口

例如:
iptables -t nat -A PREROUTING -d 172.18.11.114 -p tcp --dport 80 -j REDIRECT --to-ports 8080

例如:
编辑11.111为web服务:修改端口为8080

vim /etc/httpd/conf/httpd.conf
Listen 8080

systemctl restart httpd.service

在web服务器上添加规则:端口映射(地址转换-->端口转换)

iptables -t nat -A PREROUTING -d 172.18.11.114 -p tcp --dport 80 -j REDIRECT --to-ports 80
iptables -t nat -D PREROUTING 1
iptables -t nat -A PREROUTING -d 172.18.11.114 -p tcp --dport 80 -j REDIRECT --to-ports 8080
访问浏览器172.18.11.111可浏览web服务

注意:假设启动了2个服务ngix使用80端口,httpd使用8080,添加以上规则时,ngix就没用了,不能对外提供服务;

MASQUERADE
仅用在POSTROUTING链

使用场景:只用于动态拨号获取ip地址场景中,替换(就无需使用)snat;事实上静态地址时,一样可以使用;

在ppoe拨号上网时,MASQUERADE会自动获取外网地址,并将原地址转换为获取的外网地址;因为,masquerade会额外消耗资源,如果是静态就无需使用;

例如:
在网关防火墙上设置规则:

iptables -t filter -F
iptables -t nat -F
iptables -t nat -A POSTROUTING -s 10.0.1.0/24 -j MASQUERADE
iptables -vnL

在内网1.22测试访问web服务11.111服务器
curl http://172.18.11.11
在11.111服务器查看日志:
tail /var/log/httpd/access_log
访问正常;

iptables规则的保存与恢复

保存:iptables-save > /PATH/TO/SOME_RULE_FILE
重载:iptables-restore < /PATH/FROM/SOME_RULE_FILE
-n,--noflush:不清除原有规则
-t,-test:仅分析生成规则集,但不提交

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

CentOS6
保存规则:service iptables save或:iptables-save > /etc/sysconfig/iptables
iptables-save > /PATH/TO/SOME_RELE_FILE
保存任意位置,但是系统不会自动加载;会把文件中原有规则覆盖;

重载规则:service iptables restart
会自动从/etc/sysconfig/iptables文件中重载规则;

配置文件:/etc/sysconfig/iptables-restore

CentOS7
iptables -S > /PATH/TO/SOME_RELE_FILE
iptables-save > /PATH/TO/SOME_RELE_FILE

例如:保存规则
iptables -S
iptables-save > /etc/sysconfig/iptables.v1
cat /etc/sysconfig/iptables.v1

例如:加载文件预存的规则
iptables-restore < /etc/sysconfig/iptables.v1

自动生效规则文件中的规则:2种方式
(1)把iptables命令放在脚本文件中,让脚本文件开机自动运行
放在/etc/rc.d/rc.local
例如:/usr/bin/iptables.sh

(2)用规则文件保存规则,开机自动重载命令;
在/etc/rc.d/rc.local写明:
iptables-restore < /PATH/TO/SOME_RELE_FILE

规则优化思路:使用自定义链管理特定应用的相关规则,模块化管理规则
(1)优先放行双向状态为ESTABLISHED的报文
(2)服务于不同类别的功能的规则,匹配到报文可能性更大的放前面
(3)服务于同一类别的功能的规则,匹配到条件较严格的放在前面
(4)设置默认策略:白名单机制

练习

iptables -N clean_in 创建自定义链
iptables -A clean_in -d 255.255.255.255 -p icmp -j DROP 丢弃目标地址为全1,ping包请求;
iptables -A clean_in -d 172.16.255.255 -p icmp -j DROP 丢弃172.16网段的主机ping包;
iptables -A clean_in -p tcp ! --syn -m state --state NEW -j DROP 协议为tcp,状态为new,不是tcp第一次握手都丢弃;
iptables -A clean_in -p tcp --tcp-flags ALL ALL -j DROP 协议为TCP标志位全部为1都丢弃;
iptables -A clean_in -p tcp --tcp-flags ALL NONE -j DROP 协议为TCP标志位全部为0都丢弃;
iptables -A clean_in -d 172.16.100.7 -j RETURN 目标地址为172.16.100.7就返回调用clean_in的链上
iptables -A INPUT -d 172.16.100.7 -j clean_in 在input链上目标地址为172.16.100.7就调用clean_in链;
iptables -A INPUT -i lo -j ACCEPT 在input链上放行流入本地接口的数据;
iptables -A OUTPUT -o lo -j ACCEPT 在output链上放行流出本地接口的数据;

iptables -A INPUT -i eth0 -m multiport -p tcp --dports 53,113,135,137,139,445 -j DROP
在input链上,tcp协议目标端口为53,113,135,137,139,445,流入eth0接口的数据都丢弃;
iptables -A INPUT -i eth0 -m multiport -p udp --dports 53,113,135,137,139,445 -j DROP
在input链上,udp协议目标端口为53,113,135,137,139,445,流入eth0接口的数据都丢弃;
iptables -A INPUT -i eth0 -p udp --dport 1026 -j DROP
在input链上,udp协议目标端口为1026,流入eth0接口的数据都丢弃;
iptables -A INPUT -i eth0 -m multiport -p tcp --dports 1433,4899 -j DROP
在input链上,udp协议目标端口为1433,4899,流入eth0接口的数据都丢弃;
iptables -A INPUT -p icmp -m limit --limit 10/second -j ACCEPT
在input链上,协议为icmp,限制为每秒10个;

网络防火墙实现

防火墙至少要有2个网卡,一个为内网网卡,一个接外网网卡

内网主机发报文时,经过防火墙内网卡时拆除mac封装,先到达prerouting链,如果报文目标IP地址不是本机,就不会进入input链,经本机转发进入到forward链后到达postrouting链通过外网卡发送出去;回应的报文进入外网网卡先到达prerouting链,经由forward链后到达postrouting通过内网卡发送给内网主机;

注意:prerouting、posting链等,跟网卡无关,只跟报文出入方向有关;

防火墙当做网络防火墙时,应把规则添加forward链上;
内网主机之间通信时,防火墙设置是不起作用的;只能靠内网的主机防火墙发挥作用;
防火墙当做主机防火墙时,应把规则添加input和output链上;

尽可能控制内网主机访问外网时,应把规则添加在forward链上,要考虑进、出两个方向的规则;添加了-s或-d就有了方向性;
一般状态是establish的都放行,只是在new在方向上限制;
如果内网服务器是对外提供服务的,对new状态是限制由外而内,只开放对外开放的协议和端口,而由内而外的可不限制端口、协议的放行出去;

所以一般当服务器端,设置规则时,只放行(由外而内的)有限服务的端口和协议,对客户端设置规则是通常放行所有请求,除非限制内网用户访问某些服务;

搭建网络环境,防火墙连接内网、外网

虚拟机添加网卡后,识别不到,修改centos7中的网卡名称为eth0:
添加网卡后,无法识别新网卡

centos7中网卡名修改为eth0
cd /etc/sysconfig
vim grub
在最长的那一行添加下面的句子
net.ifnames=0 biosdevname=0

grub2-mkconfig -o /boot/grub2/grub.cfg 重命名原来的网卡名字

cd /etc/sysconfig/network-scripts
mv ifcfg-enoXXXXXXXX ifcfg-eth0

修改ifcfg-eth0里边的NAME,DEVICE的名字都为eth0

NAME=eth0
DEVICE=eth0

reboot重启,并查看发现已经成我们想要的eth0

在centos6中,克隆虚拟机后eth0网卡无法识别问题:

解决方法:
修改/etc/udev/rules.d 下的 70-persistent-net.rules 文件,我们会发现下面两行:
PCI device 0x1022:0x2000(pcnet32)
SUBSYSTEM=="net",DRIVERS=="?*",ATTRS{address}=="00:0c:29:4c:46:01",NAME="eth0" 这行删除
Advanced Micro Devices [AMD] 79c970 [PCnet32 LANCE] (rule written by anaconda) SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:0c:29:ad:06:2a", ATTR{type}=="1", KERNEL=="eth*", NAME="eth1"
这行修改最后的eth1为eth0,然后保存退出,重启系统就可以了。

或者你觉得上面改的比较麻烦,你可以将上面带#的两行都删除,然后保存重启电脑,让系统全部重新获取网卡信息。

网络环境模型搭建完毕

内网主机:10.0.1.22/24
防火墙有2块网卡:
内网网卡eth1:10.0.1.1/24
外网网卡eth0:172.18.11.114/16
其它外网主机:172.18.11.111

查看核心转发功能,为0表示核心转发是关闭的

[root@promote ~]# cat /proc/sys/net/ipv4/ip_forward
0

此时,测试从内网主机1.22 ping 防火墙外网地址11.114,且防火墙核心转发是关闭,此时仍然能ping通,因为linux系统中同一主机的网卡之间是互通的,ip地址属于内核不属于网卡;只要内网主机1.22的网关指向了防火墙的1.1,那么1.1所在主机的所有地址,1.22可以ping通防火墙上的所有地址;其实这不叫转发这是默认法则;如果1.22没有把网关指向1.1,只能ping通1.1,ping不同11.114了;1.22是通过网关1.1转发的;没有网关就不能非本地通信;

如果防火墙没有打开核心转发,1.22不能ping通外网地址11.111;

在1.22主机ping11.111
在11.111抓包,只抓icmp的ping包
tcpdump -i eno16777736 icpm
此时ping不通,而且也抓不到icmp的包;

打开防火墙的核心转发后,再测试是否能ping通

[root@promote ~]# echo 1 > /proc/sys/net/ipv4/ip_forward
[root@promote ~]# cat /proc/sys/net/ipv4/ip_forward
1

此时在11.111抓到了ping包,但在1.22显示ping不通;

应该在11.111主机上加一条路由:route add -net 10.0.1.0/24 gw 172.18.11.114
此时,1.22主机ping通11.111主机;

演示在防火墙上添加iptables规则

在防火墙关闭转发:iptables -P FORWARD DROP
此时,1.22主机ping不通11.111主机;

若要内网主机能ping通外网主机,当反之则不允许;
iptables -A FORWARD -s 10.0.1.0/24 -d 0/0 -p icmp --icmp-type 8 -j ACCEPT 放png包出去但没放进返回的包

可在,外网11.111主机抓包
tcpdump -i eno16777736 -nn icmp 有1.22请求11.111,有11.111响应1.22;

也可在本地1.22主机,虚拟机按ctrl+alt+f2再打开一个控制台吗,抓包;
tcpdump -i eno16777736 -nn icmp 有1.22请求11.111,没响应;

也可在防火墙主机的内网网卡、外网网卡上分别抓包;
tcpdump -i eth0 -nn icmp 收到1.22请求11.111,也收到11.113响应1.22
tcpdump -i eth1 -nn icmp 仅收到1.22请求11.111,没响应;

打开从内网主机能ping通外网主机;
在防火墙主机只添加一条放进来外网ping包的规则;
iptables -A FORWARD -s 0/0 -d 10.0.1.0/24 -p icmp --icmp-type 0 -j ACCEPT
此时从内网主机能ping通外网主机,放开了仅内网能ping外网主机的规则,可抓包验证;
但仍然不能从外网主机ping通内网主机;即11.111ping不通1.22;
可在防火墙主机外网网卡上抓包,能抓到进来的包;
tcpdump -i eth0 -nn icmp

如果要实现内网主机能ping外网主机互通,则还有添加2条规则,即:
放行从外到内的icmp请求类型为8的,从内到外icmp响应类型为0的即可;

使用基于状态追踪设定规则时,如果只允许内网ping出去,就可把之前设定的两条规则合并;

iptables -F
iptables -A FORWARD -m state --state ESTABLISHED -j ACCEPT
iptables -A FORWARD -s 10.0.1.0/24 -p icmp --icmp-type 8 -m state --state NEW -j ACCEPT
此时,内网主机1.22能ping通11.111

当外网主机11.111为web、vsftp服务器时,要允许内网主机访问外网的服务器;
在防火墙主机设置规则:

iptables -F
iptables -A FORWARD -m state --state ESTABLISHED -j ACCEPT
iptables -A FORWARD -s 10.0.1.0/24 -p tcp --dport 80 -m state --state NEW -j ACCEPT  仅放行出去的请求

此时内网主机能访问外网web服务器了

curl httpd://172.18.11.111

iptables -A FORWARD -s 10.0.1.0/24 -p tcp --dport 21 -m state --state NEW -j ACCEP 此时,放行的是vsftp的命令连接,响应通过上面的ESTABLISHED也没问题,但数据连接在被动模式下,没有放行只有在related状态放行才行;数据连接只有第一次请求是related的,而且要识别related而不是new要先装载iptables的模块,即ftp连接追踪的模块;

装载iptables的追踪ftp的连接追踪模块
modprobe nf_conntrack_ftp

在被动模式下,服务器发请求,第一次请求为related的,所以是从外网到内网的为related;
替换第一条规则:iptables -R FORWARD 1 -m state --state ESTABLISHED,RELATED -j ACCEPT

此时在内网主机测试服务ftp服务
lftp 172.18.11.111 能访问

在centos7系统上保存规则:
iptables-save > /etc/sysconfig/iptables.v2

重启后规则消失,要想开机自动运行,添加:

vim /etc/rc.d/rc.local
iptables-restore < /etc/sysconfig/iptables.v2

在centos6系统上保存规则:service iptables save
要想开机自动运行:chkconfig iptables on

在centos7系统上用的是firewalld服务,要手动控制firewalld;
在实际中,防火墙可能不止有2个网卡,甚至更多;

一般来讲,本地用户允许new状态的出去访问互联网,而本地服务器向外提供服务,则不允许new状态出去,除非是DNS服务器或服务器使用yum源;

NAT 防火墙

NAT:Network Address Translation 只有启用NAT功能必须启用链接追踪机制contract;
最初是为了安全隐藏ip地址,后来被用来ipv4地址不够用时引用了NAT;

SNAT:source NAT

修改ip报文中的源IP地址;只能用在POSTROUTINGINPUT链上、自定义链(但也只能被POSTROUTING、INPUT链调用)上;

使用场景:让本地网络中的主机可使用统一地址与外部通信,从而实现地址伪装;即转换客户端地址,一般代理本地私网主机到互联网;

请求:由内网主机发起,修改源IP,如果修改则由管理员定义;
响应:修改目标IP,由nat自动根据会话表中追踪机制实现相应修改;

原地址转换:
本地内网用户访问外网服务器时,在本地网关上进行原地址转换,把内网用户请求报文中原地址转换为网关的公网地址与外界通信,外网服务器响应内网用户时,进行目标地址转换,只不过响应报文中不需要用户参与,网关根据追踪会话表自动完成目标地址转换,转发给内网用户;

DNAT:destinaton NAT

修改ip报文中的目标IP地址;仅用在PREROUTINGOUTPUT链 上;

使用场景:让本地网络中的服务器使用统一的地址向外提供服务,但隐藏了自己的真实地址,还可实现负载均衡;即转换服务器端地址,把本地私网主机放在互联网上当服务器;

请求:由外网主机发起,修改其目标地址,由管理员定义;
响应:修改原地址,但有nat自动根据会话表中的追踪机制实现对应修改;

目标地址转换:
外网用户访问本地内网中向外提供服务的主机时,本地网关会进行目标地址转换,把目标地址改为内网的服务器地址,内网服务器响应外网用户时,在本地网关上完成源地址转换,只不过响应报文中不需要用户参与,根据追踪会话表自动完成源地址转换;

本地为客户端使用原地址转换;
本地为服务器使用目标地址转换;

PNAT:port NAT

实现端口转换,而REDIRECT能专门实现端口转换机制,而DNAT完成目标端口转换,响应报文时能自动进行源端口转换;

  • SNAT:本地是客户端,远程是服务器,在网关上应该发生在(路由后)POSTROUTING,即离开本机时、INPUT链;
  • DNAT:本地是服务器,远程是客户端,在网关上应该发生在(路由前)PREROUTING链,即进入本机时;

SNAT实现

只能用在postrouting和input链上**

--to-source [ipaddr[-paddr]] 指明原地址、源端口(但源端口一般为随机端口),可指定地址范围;
--random 随机分配端口;

但在centos6系统上较老版本内核和较老版本的iptables上SNAT不能用在input链上;
所以centos6系统上,nat表只包含3个链:OUTPUT、PREROUTING、POSTROUTING;
而centos7系统上,nat表包含4个链:INPUT、OUTPUT、PREROUTING、POSTROUTING;

在内网1.22主机请求外网web服务
curl http://172.18.11.111 可访问外网web访问

可在外网web主机查看日志
tail /var/log/httpd/message
可看到内网请求web时,源地址为1.22,目标地址为11.111;mac地址会不断变化的;

为内网用户访问外网在防火墙设置SNAT:
iptables -t nat -A POSTROUTING -s 10.0.1.0/24 -j SNAT --to-source 172.18.11.114
如果防火墙有多个外网地址可设为地址范围;如下:
iptables -t nat -A POSTROUTING -s 10.0.1.0/24 -j SNAT --to-source 172.18.11.114-172.18.11.117

iptables -t nat -vnL
iptables  -vnL

在内网1.22上ping外网172.18.11.111
可在172.18.11.111抓包:

tcpdump -i eno16777736 -nn icmp
IP 172.18.11.114 > 172.18.11.111: ICMP echo request
IP 172.18.11.111 > 172.18.11.114: ICMP echo reply

再打开内网10.0.1.22的一个控制台(crtl+alt+f2)抓包:

tcpdump -i eth0 -nn icmp
IP 10.0.1.22 > 172.18.11.111: ICMP echo request
IP 172.18.11.111 > 10.0.1.22: ICMP echo reply

还可在网关防火墙抓包:
外网网卡抓包:

tcpdump -i eth0 -nn icmp
IP 172.18.11.114 > 172.18.11.111: ICMP echo request
IP 172.18.11.111 > 172.18.11.114: ICMP echo reply

内网网卡抓包:

tcpdump -i eth1 -nn icmp
IP 10.0.1.22 > 172.18.11.111: ICMP echo request
IP 172.18.11.111 > 10.0.1.22: ICMP echo reply

还可在内网主机测试80端口:
curl http://172.18.11.111
在11.111服务器上查看日志:

tail /var/log/httpd/access_log
172.18.11.114 - - [28/Apr/2016:19:13:03 +0800] "GET / HTTP/1.1" 200 36 "-" "curl/7.29.0"

要禁止内网用户访问ssh服务,22端口:
在网关防火墙设置规则:
iptables -t filter -A FORWARD -s 10.0.1.0/24 -p tcp --dport 22 -j REJECT
此时在内网主机连接ssh服务被拒绝访问,但其它服务扔可访问;
ssh root@172.18.11.111 如果规则使用drop则不会立即显示拒绝,而会滞留在连接状态;

DNAT实现

仅用于nat表的PREOUTINGOUTPUT链上或用在自定义链上(但也只能被POSTROUTING、INPUT链调用);

--to-destination [ipaddr[-ipaddr]][:port[-port]] 指明目标地址、目标端口,也可是范围;

目标端口转换时,做端口映射是很常见的:

如果内网1.22为向外提供服务,外网11.111为客户端要访问1.22:
在网关防火墙设置规则:
先确保网关防火墙没有监听80端口;但可向外宣称提供80服务,实际是由内网1.22提供服务;

ss -tnl
iptables -t nat -F POSTROUTING 指明清除nat表上的postrouting链上的规则;
iptables -t nat -A PREROUTING -s 0/0 -d 172.18.11.114 -p tcp --dport 80 -j DNAT --to-destination 10.0.1.22

表示只有目标地址11.114、目标端口为80时,转换目标地址为10.0.1.22目的端口没改;
iptables -t nat -vnL

使用外网主机访问网关防火墙172.18.11.114:
可在浏览器输入172.18.11.114
显示成功;

内网主机提供的服务端口跟网关防火墙声称的提供服务的端口不一样时:做端口映射
比如外网用户访问的是80,但可以在内网服务主机使用其它端口提供服务;

在1.22主机编辑httpd的配置文件,修改监听端口为8090:

vim /etc/httpd/conf/httpd.conf
Listen 8090按需          

在网关防火墙设置规则:

iptables -t nat -F
iptables -t nat -A PREROUTING -s 0/0 -d 172.18.11.114 -p tcp --dport 80 -j DNAT --to-destination 10.0.1.22:8090
iptables -t nat -vnL

此时,使用外网主机访问网关防火墙11.114:
可在浏览器输入172.18.11.114
显示成功;

在DNAT,内网服务器看到的原地址没变仍为外网主机11.111;
可验证,在11.111主机:
curl http://172.18.11.114
在内网服务器1.22查看web日志:
tail -1 /var/log/httpd/access_log
tcpdump -i eth0 -nn tcp port 8090

在外网主机11.111上访问网关防火墙11.114的ssh服务,端口还仍然是网关防火墙自己;
ssh root@172.18.11.114

在防网关火墙添加规则:
iptables -t nat -A PREROUTING -s 0/0 -d 172.18.11.114 -p tcp --dport 22 -j DNAT --to-destination 10.0.1.22
此时,在外网主机11.111上访问网关防火墙11.114的ssh服务,被转给了内网10.22主机;
ssh root@172.18.11.114
这样,内网主机服务可随意指定端口,对外发布服务;

在防网关火墙添加规则:
iptables -t nat -A PREROUTING -s 0/0 -d 172.18.11.114 -p tcp --dport 0 -j DNAT --to-destination 10.0.1.22
此时,把目的端口设为0,外网11.111再访问11.114的web服务或ssh服务都被拒绝;在特殊场景中不会是此效果,例如,用到负载均衡器的lvs场景时,会把11.114上的所有端口,统统转到内网主机服务器上;

推荐阅读更多精彩内容