iptables 不是真正的防火墙,可以把它理解成一个客户端代理,用户通过iptables这个代理,将用户的安全设定执行到对应的“安全框架“,这个”安全框架“才是真正的防火墙,叫做 netfilter
netfilter(包过滤)是Linux内核中的一个数据包处理模块,具有如下功能:
虽然我们使用 service iptables start
或 systemctl start iptablse
来启动iptables,但是iptables并没有守护进程,所以并不能算是一个真正意义上的服务,而应该算是内核提供的功能
我们知道Linux中为了安全分成了用户空间和内核空间两个部分,报文需要进入用户空间前会先经过内核空间,而要想达到”防火“的功能,就需要在内核空间中设置”关卡“,所有进出的报文都需要通过这些关卡,匹配规则后,符合放行条件的才能放行,符合阻拦条件的则需要被阻拦,于是就出现了 input
和 output
关卡,而这些关卡在iptables中被称为”链CHAIN”
事实上上述描述的场景并不完善,因为收到的报文访问的目标地址可能并不是主机,而是其他服务器,当本机的内核支持核心转发 IP_FORWARD
时(明明是台电脑却只能卑微的当个路由器),我们可以将报文转发给其他服务器,这时候就会出现其他的”关卡“,他们就是”路由决策前“、”转发“、”路由决策后“
所以根据上图,我们能想象出某些场景中报文的流向:
为什么这些”关卡“被称作”链“呢?iptables通过定义规则来实现不同的功能,而这些规则就写到了关卡中,防火墙的作用就在于对经过某个关卡的报文进行匹配”规则“,然后执行相应的”动作“;而每个关卡上可能不止有一条规则,而是有很多条规则,当我们将这些规则按一定的顺序串起来时,就形成了”链“,如下图所示。所以把”关卡“称为”链”会更加合适
iptables通过定义规则来实现不同的功能,iptables中有四张表将这些功能分类,而要实现功能就要将规则(rules)写进这些表中,如放行(accept)、拒绝(reject)、丢弃(drop)等,而这四张表分别是:
事实上,某些“链”中注定不会包含某类“规则”,就像某些“关卡”天生就不具备某些功能一样。比如A关卡是防空的,只能打击空中的敌人;B关卡是陆军,没有防空能力;C关卡比较牛逼,既可以防空又可以防陆;D关卡最屌,海陆空全防
从表的角度来看:
需要注意的是,当报文经过一条链时,会将当前链上所有的规则匹配一遍,但是匹配的时候总归要有顺序,应该一条条匹配,所以还有一个表优先级的问题(由高到低):
raw --> mangle --> nat --> filter
结合上述所有描述,我们可以将报文通过防火墙的流程总结为下图:
规则:根据指定的匹配条件来尝试匹配每一个流经的报文,一旦匹配成功则由规则后面执行的处理动作进行处理
语法:iptables [-t TABLE] SUBCOMMAND CHAIN [!] CRITERIA -j TARGET
-F [CHAIN]
:flush,清空某条链的所有规则-P [CHAIN]
:policy,定义链的默认动作-N CNAME
:new,添加自定义链-X CNAME
:删除自定义链,需要满足:自定义链没有被任何规则引用,即自定义链的引用计数为0;自定义链中没有任何规则,即自定义链为空-E CNAME NEWCNAME
:edit,修改自定义链的名字-Z [CHAIN]
:zero,清空链上的统计信息-A
:append,将规则追加到链最后-I
:insert,将规则插入到指定位置,需要给定序号-D
:delete,将链上的规则删除,需要给定序号-R
:replace,对链上的规则修改,需要给定序号-L [CHAIN]
:默认列出所有链上的规则
-n
:不做域名解析-v
:显示详细信息-vv
:更详细-vvv
:再详细–line-numbers
:显示规则序号即不需要指明具体模块名就能使用的匹配条件
-s
:source,源IP-d
:destination,目的IP-p
:protocol,协议,有ip、tcp、udp、icmp等-i
:input interface,报文的流入接口-o
:output interface,报文的流出接口需要指明具体的模块名,条件作为模块的选项
隐式匹配:如果在通用匹配上使用了 -p
选项指明协议,则 -m
可有可无
–dport
:目的端口–sport
:源端口–tcp-flags LIST1 LIST2
–tcp-flags sys,ack,fin,rst syn
:相当于 –syn
,也就是三次握手的第一次握手–syn
:用来匹配tcp会话第一次握手iptables -A INPUT -p tcp -s 172.16.100.0/24 --dport 22 -j ACCEPT
:放行172.16.100.0/24网段的所有主机对22端口的访问(ssh)–sport
–dport
–icmp-type
:指定匹配icmp报文类型
0
:echo reply8
:echo request显示匹配:显示指定使用iptables的具体模块进行匹配
用法:-m 模块名 [模块选项]
multiport
:多端口扩展
–sports PORT1[,PORT2…]
–dports PORT1[,PORT2…]
–ports PORT1[,PORT2,…]
iptables -A INPUT -d 10.1.1.1 -p tcp -m multiport --dports 22,80,443 -j ACCEPT
:放行10.1.1.1对22、80、443端口的访问iprange
:多ip扩展
–src-range IP[-IP2]
–dst-range IP[-IP2]
iptables -A INPUT -d 10.1.1.1 -p tcp --dport 22 -m iprange --src-range 192.168.1.1-192.168.1.100 -j ACCEPT
time
:指定匹配时段
–datestart YYYY\[-MM]\[-DD][-hh[-:mm[:ss]]]
–datestop
–timestart
–timestop
–weekdays DAY1[,DAY2…]
–mouthdays
iptables -A INPUT -p tcp --dport 80 -m time --timestart 9:00 --timestop 19:00 -j DROP
iptables -A INPUT -p tcp --dport 80 -m time --weekdays Mon,Tue -j DROP
connlimit
:限制同时并发连接数
–connlimit-above N
–connlimit-mask N
:不可单独使用,与上一个选项配合使用,用于针对”某个IP段内的一定数量的IP“进行连接数量限制(IP段内所有IP共享限制)iptables -A INPUT -p tcp --dport 22 -m connlimit --connlimit-above 6 -j REJECT
iptables -I INPUT -p tcp --dport 22 -m connlimit --connlimit-above 10 --connlimit-mask 27 -j REJECT
limit
:限制发包速率
–limit n/[minute|second|hour|day]
–limit-burst
:”令牌桶“算法,指定令牌桶中令牌的最大数量,相当于进程池state
:基于连接追踪模板(nf_conntrack),用于记录各连接以及相关状态,基于ip实现,与tcp协议无关
NEW
:新建立的连接,连接追踪模板无相应记录,客户端第一次发出的请求ESTABLISHED
:NEW之后进入模板中直到状态被删除之前的过程RELATED
:相关联的连接,如ftp的被动模式(20,21)INVALIED
:无法识别的状态string
:匹配字符串
–algo
:指定对应的匹配算法,可用的算法为bm、kmp等,此选项为必选选项–string
:指定需要匹配的字符串iptables -t nat -A POSTROUTING -s 内网网段 -j SNAT --to-source 需转换成的源地址
iptables -t nat -A POSTROUTING -s 内网网段 -o 出接口 -j MASQUERADE
iptables -t nat -A PREROUTING -d 100.1.1.1 -p tcp --dport 80 -j DNAT --to-destination 192.168.1.1
iptables save
要求
# 修改ip地址
ip addr add 172.16.10.1/24 dev ens33
# 修改默认路由
ip route add default via 172.16.10.2 dev ens33
# 重启网络
systemctl restart network
# 添加一个子接口
ifconfig eth0:0 172.16.10.2 netmask 255.255.255.0
# 关闭selinux
setenforce 0
# 清空filter表默认配置
iptables -F
# 为主机A配置SNAT
iptables -A POSTROUTING -t nat -s 172.16.10.0/24 -o eth0 -j MASQUERADE
# 为主机A配置DNAT
iptables -A PREROUTING -t nat -d 192.168.159.144 -p tcp --dport 2222 -j DNAT --to-destination 172.16.10.1:22
# 开启核心转发
echo 1 > /proc/sys/net/ipv4/ip_forward
[root@inside ~]# ping 192.168.159.1
PING 192.168.159.1 (192.168.159.1) 56(84) bytes of data.
64 bytes from 192.168.159.1: icmp_seq=1 ttl=127 time=0.714 ms
64 bytes from 192.168.159.1: icmp_seq=2 ttl=127 time=0.648 ms
64 bytes from 192.168.159.1: icmp_seq=3 ttl=127 time=0.525 ms
64 bytes from 192.168.159.1: icmp_seq=4 ttl=127 time=0.563 ms
^C
--- 192.168.159.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3002ms
rtt min/avg/max/mdev = 0.525/0.612/0.714/0.077 ms
C:\Users\Ti>ssh [email protected] -p 2222
The authenticity of host '[192.168.159.144]:2222 ([192.168.159.144]:2222)' can't be established.
ECDSA key fingerprint is SHA256:9T6E0aufwGnBm7L16GFC9+FFWimqK7uOeRwX4d0nCh4.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[192.168.159.144]:2222' (ECDSA) to the list of known hosts.
[email protected]'s password:
Last login: Mon May 11 22:20:23 2020 from 172.16.10.2
[root@inside ~]# ip ad sh
1: lo: mtu 65536 qdisc noqueue state UNKNOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:73:3a:9e brd ff:ff:ff:ff:ff:ff
inet 172.16.10.1/24 brd 172.16.10.255 scope global ens33
valid_lft forever preferred_lft forever
inet6 fe80::8646:ee5f:9334:9c2f/64 scope link
valid_lft forever preferred_lft forever
[root@inside ~]#
参考文章,讲的非常具体并且有具体实验:iptables