前言
学习了netfilter的基础知识和一些iptables的常用选项,匹配条件的隐式扩展,显式扩展和处理动作后,可以动手操作一下iptables的规则编写。
实验环境
Centos7_64位系统,防火墙使用iptables;
先关闭Centos7的默认防火墙firewall,安装iptables。
[root@test2 ~]# systemctl stop firewalld
[root@test2 ~]# systemctl disable firewalld
[root@test2 ~]# yum install iptables-services
常用应用
先清除防火墙的默认规则。
[root@test2 ~]# iptables -F
[root@test2 ~]# iptables -nvL
Chain INPUT (policy ACCEPT 37 packets, 2612 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 14 packets, 1336 bytes)
pkts bytes target prot opt in out source destination
链的默认规则建议:iptables chain的默认规则是ACCEPT的,这样的好处在于不容易出现操作失误后永远地跟服务器失去联系,通常,默认规则设置在链中的最后一条比较妥当。
[root@test2 ~]# iptables -A INPUT -d 192.168.30.138 -p tcp --dport 22 -j ACCEPT #先设置允许ssh的连接
[root@test2 ~]# iptables -A INPUT -j REJECT #添加默认规则
[root@test2 ~]# iptables -A OUTPUT -s 192.168.30.138 -p tcp --sport 22 -j ACCEPT
[root@test2 ~]# iptables -A OUTPUT -j REJECT
[root@test2 ~]# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
636 46525 ACCEPT tcp -- * * 0.0.0.0/0 192.168.30.138 tcp dpt:22
816 70227 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 54 packets, 4174 bytes)
pkts bytes target prot opt in out source destination
71 8531 ACCEPT tcp -- * * 192.168.30.138 0.0.0.0/0 tcp spt:22
80 12072 REJECT all -- * * 192.168.30.138 0.0.0.0/0 reject-with icmp-port-unreachable
multiport
multiport能够在一条规则上指定多个端口,最多指定15个,连续的端口如20:22,只算两个,离散端口使用“,”分割
实例:在本机开放SSH服务和HTTPD服务
[root@test2 ~]# iptables -R INPUT 1 -d 192.168.30.138 -p tcp -m multiport --dports 22,80 -j ACCEPT #修改下第一条
[root@test2 ~]# iptables -R OUTPUT 1 -s 192.168.30.138 -p tcp -m multiport --sports 22,80 -j ACCEPT
[root@test2 ~]# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
247 16328 ACCEPT tcp -- * * 0.0.0.0/0 192.168.30.138 multiport dports 22,80
1572 134K REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
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
14 1336 ACCEPT tcp -- * * 192.168.30.138 0.0.0.0/0 multiport sports 22,80
80 12072 REJECT all -- * * 192.168.30.138 0.0.0.0/0 reject-with icmp-port-unreachable
开放自己对外ping测,但不开放外对内Ping测
icmp 8/0类型是icmp request请求
icmp 0/0类型是icmp reply报文
可以在INPUT禁止8/0报文,允许0/0报文,在OUTPUT上放开8/0报文,达到目的。
[root@test2 ~]# iptables -I INPUT 2 -d 192.168.30.138 -p icmp --icmp-type 0 -j ACCEPT #放开0类型报文,8类型报文被最后的规则过滤了
[root@test2 ~]# iptables -I OUTPUT 2 -s 192.168.30.138 -p icmp --icmp-type 8 -j ACCEPT #OUTPUT放开类型8的报文
ip_conntrack
ip_conntrack提供追踪功能,后来改称为nf_conntrack,由nf_conntrack模块提供。
只要一加载该模块,/proc/net/nf_conntrack文件中就会记录下追踪的连接状态。虽然会追踪TCP/UDP/ICMP的所有连接,但是在此文件中只保存tcp的连接状态。
[root@test2 ~]# tail /proc/net/nf_conntrack
ipv4 2 tcp 6 299 ESTABLISHED src=192.168.30.1 dst=192.168.30.138 sport=52408 dport=22 src=192.168.30.138 dst=192.168.30.1 sport=22 dport=52408 [ASSURED] mark=0 zone=0 use=2
ipv4 2 udp 17 11 src=192.168.1.170 dst=108.59.2.24 sport=59756 dport=123 src=108.59.2.24 dst=192.168.1.170 sport=123 dport=59756 mark=0 zone=0 use=2
ipv4 2 unknown 2 198 src=192.168.1.125 dst=224.0.0.251 [UNREPLIED] src=224.0.0.251 dst=192.168.1.125 mark=0 zone=0 use=2
nf_conntrack好处好多,但每一个监控和追踪的工具都是消耗性能的,而nf_conntrack也有其瓶颈所在。nf_conntrack也会消耗一定的资源,所以在设计的时候默认给出了其最大的追踪数量,最大追踪数量值由/proc/sys/net/netfilter/nf_conntrack_max文件决定。默认是31384个。这个值显然是无法满足较高并发量的服务器的,所以可以将其增大一些,否则追踪数达到了最大值后,后续的所有连接都将排队被阻塞,可能会因此给出警告。但是无论如何要明白的是追踪是会消耗性能的,所以该值应该酌情考虑。
state 显式扩展
该扩展是conntrack的子集,有4个状态(NEW、ESTABLISHED、RELATED、INVALID)这些状态跟TCP的状态机没关系,这4种状态对TCP,UDP,ICMP都是适用的,这些状态是数据包的状态,另外在NAT中,防火墙是不会去改变这些数据包的状态。
NEW状态
发送的第一个数据包状态即为NEW状态,如果在TCP中,为了建立连接而三次握手,就算不能成功建立,但第二个数据包状态已经不是NEW了
ESTABLISHED
无论是TCP\UDP\ICMP只要发送的第一个数据包穿过了防火墙,那么接下来双方的数据包状态就是ESTABLISHED
RELATED
相关联的连接,当前连接是一个新请求,但附属于某个已存在的连接,
RELATED状态和协议无关,只要数据包是因为本机先送出一个数据包而导致另一条连接的产生,那么这个新连接的所有数据包都属于RELATED状态的数据包。
INVALID
ESTABLISHED、NEW、RELATED状态的数据包,那么就一定是INVALID状态。是一个非法的状态,应当禁止
通常使用state状态来设置防火墙会大大提升效率
例如,对于本机对外访问,我们一般都可以考虑放行,对于响应报文我们只需要在INPUT上放行ESTABLISHED状态,就可以正常通信了;对于外部一些NEW状态进入INPUT链,我们可以明确指定放开哪些服务NEW状态通信,否则会匹配最后的拒绝规则;另外,为了防止反弹式木马,像一些恶意木马,利用本机已开放的端口,如80,去连接服务端;可以对这些端口在OUTPUT链上禁止NEW状态通过,因为通常,这些服务端口都是服务端口,不太可能主动去连接别人。
使用state优化规则
先把iptables的所有规则清空
[root@test2 ~]# iptables -F
在INPUT链上放通ESTABLISHED状态和 http和ssh的NEW状态。
[root@test2 ~]# iptables -A INPUT -p tcp -m multiport --dports 22,80 -m state --state=NEW -j ACCEPT
[root@test2 ~]# iptables -I INPUT -m state --state=ESTABLISHED -j ACCEPT
[root@test2 ~]# iptables -A INPUT -j REJECT
#OUTPUT链也放通ESTABLISHED 和NEW状态
[root@test2 ~]# iptables -A OUTPUT -m state --state=ESTABLISHED -j ACCEPT
[root@test2 ~]# iptables -I OUTPUT -m state --state=NEW -j ACCEPT
[root@test2 ~]# iptables -A OUTPUT -j REJECT
#为了防止反弹式木马,应该对80,22的NEW状态不允许通过
[root@test2 ~]# iptables -I OUTPUT -p tcp -m multiport --sports 22,80 -m state --state=NEW -j REJECT
NAT
服务器接受到的报文有两种不同的走向,第一种是走向用户空间的报文,另一种是走向其他网卡出去的报文,对于第二种,linux默认是不会帮忙转发的,但是打开了linux系统的核心转发功能,就能像路由器那样可以转发报文。
实验:利用linux做转发数据包
实验环境:3台linux,1台linux打开ip_forward,转发2台linux之间的报文
linux客户端:Centos6.9(192.168.30.128)SUSE(172.16.1.2)
linux网关服务器: Centos7,两张网卡(192.168.30.138)(172.16.1.1)
centos6主机:
![image_1cf79lougpkl1q1b1povjsu1rv79.png-38.9kB][1]
suse主机
![image_1cf79mrcs1aeud17gbt19jt1idp1m.png-27.8kB][2]
在centos7 上ping测双方都可以通信
[root@test2 ~]# ping 192.168.30.128
PING 192.168.30.128 (192.168.30.128) 56(84) bytes of data.
64 bytes from 192.168.30.128: icmp_seq=1 ttl=64 time=0.969 ms
[root@test2 ~]# ping 172.16.1.2
PING 172.16.1.2 (172.16.1.2) 56(84) bytes of data.
64 bytes from 172.16.1.2: icmp_seq=1 ttl=64 time=0.751 ms
64 bytes from 172.16.1.2: icmp_seq=2 ttl=64 time=0.317 ms
我现在没配置ip_forword,数据包默认是不能过去的
在Centos6上去ping测172.16.1.1,是可以通的
[root@test1 ~]# ping 172.16.1.1
PING 172.16.1.1 (172.16.1.1) 56(84) bytes of data.
64 bytes from 172.16.1.1: icmp_seq=1 ttl=64 time=0.557 ms
64 bytes from 172.16.1.1: icmp_seq=2 ttl=64 time=0.933 ms
64 bytes from 172.16.1.1: icmp_seq=3 ttl=64 time=0.906 ms
#在Centos7上抓包:
[root@test2 ~]# tcpdump -nn -i ens37 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens37, link-type EN10MB (Ethernet), capture size 262144 bytes
14:50:49.506112 IP 192.168.30.128 > 172.16.1.1: ICMP echo request, id 7187, seq 1, length 64
14:50:49.506162 IP 172.16.1.1 > 192.168.30.128: ICMP echo reply, id 7187, seq 1, length 64
14:50:50.521664 IP 192.168.30.128 > 172.16.1.1: ICMP echo request, id 7187, seq 2, length 64
14:50:50.521723 IP 172.16.1.1 > 192.168.30.128: ICMP echo reply, id 7187, seq 2, length 64
//虽然172.16.1.1是ens33网卡的地址,但整个tcp/ip协议栈都是由内核管理,所以,数据包并没有到达ens33的这块网卡,数据包在内核已经回复了。
#我在Centos6上去ping测172.16.1.2结果:
[root@test1 ~]# ping 172.16.1.2
PING 172.16.1.2 (172.16.1.2) 56(84) bytes of data.
^C
--- 172.16.1.2 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 4013ms
没有回复
并且在Centos7上抓包,ens37这张网卡能抓包ICMP的请求报文,但是ens33这张是不能抓到的,因为linux没有开启ip_forward功能,数据包直接被丢弃
#
#下面我在Centos7上开启转发功能,
[root@test2 ~]# echo "1" > /proc/sys/net/ipv4/ip_forward #开启转发功能
下面Centos6上ping,然后在Centos7上抓包,就能在ens33上看到被转发的数据包
[root@test2 ~]# tcpdump -nn -i ens33 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
14:58:21.294997 IP 192.168.30.128 > 172.16.1.2: ICMP echo request, id 12563, seq 1, length 64
14:58:21.295966 IP 172.16.1.2 > 192.168.30.128: ICMP echo reply, id 12563, seq 1, length 64
14:58:22.300825 IP 192.168.30.128 > 172.16.1.2: ICMP echo request, id 12563, seq 2, length 64
14:58:22.302045 IP 172.16.1.2 > 192.168.30.128: ICMP echo reply, id 12563, seq 2, length 64
网络防火墙
把linux的转发功能打开后,linux就可以充当一台路由器来使用,如果需要过滤数据包,例如我把Centos6当作内网的一台主机,SUSE当作外网,则可以在网关上设置过滤规则来保护内网主机。
例如:对于内网访问外网的数据包,我们可以放行,但外网想要访问内网,拒绝,我们可以使用state状态来设置防火墙。
先设置默认规则,拒绝。
[root@test2 ~]# iptables -A FORWARD -j REJECT #拒绝所有
[root@test2 ~]# iptables -R FORWARD 2 -s 192.168.30.0/24 -i ens37 -m state --state=NEW -j ACCEPT #对ens37 192.168.30.0网络的主机状态为NEW的放行
[root@test2 ~]# iptables -I FORWARD -m state --state=ESTABLISHED -j ACCEPT #对ESTABLISH状态的报文放通。
#ping测无问题
[root@test1 ~]# ping 172.16.1.2
PING 172.16.1.2 (172.16.1.2) 56(84) bytes of data.
64 bytes from 172.16.1.2: icmp_seq=1 ttl=63 time=1.29 ms
64 bytes from 172.16.1.2: icmp_seq=2 ttl=63 time=2.21 ms
64 bytes from 172.16.1.2: icmp_seq=3 ttl=63 time=1.81 ms
反过来,SUSE想Ping测 因为状态为NEW不能通过
如果想放通Centos6的80端口,可以这样放通:
[root@test2 ~]# iptables -I FORWARD 2 -d 192.168.30.128 -p tcp --dport 80 -m state --state=NEW -j ACCEPT #放通STATE=NEW的tcp80数据包
#在SUSE上curl来测试80端口是否能通信。
linux-olth:~ # curl http://192.168.30.128/index.html
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access /index.html
on this server.</p>
<hr>
<address>Apache/2.2.15 (CentOS) Server at 192.168.30.128 Port 80</address>
</body></html>
//虽然网页因为权限问题被拒绝访问,但其实访问80端口是没问题的
NAT网络地址转换
在最开始的时候,NAT是用来保护内网主机不暴露在外网之中,后来发现NAT可以很好的用来解决IP地址数量不足的情况,即使用一个外网IP地址,就可以使得N台内网主机同时上网,而且上网的主机不会真正的暴露在外网之中。
在Linux上也可以很好的使用nat,而很多的家庭路由器,无非就是一个安装了linux内核的固件安装好netfilter然后提供一个WEB管理接口,就能成为一个路由器了。
SNAT
SNAT在POSTROUTING上做,例如,我把192.168.30.128在防火墙上通过SNAT转换成172.16.1.1,这样外网主机就认为是172.16.1.1这台主机在访问自己。这样可以把内网主机隐藏起来。
在Centos7的nat表中的POSTROUTING链上增加一条规则:
[root@test2 ~]# iptables -t nat -A POSTROUTING -s 192.168.30.128 -j SNAT --to-source 172.16.1.1 #这样192.168.30.128访问外网时候,就被转换成172.16.1.1
[root@test1 ~]# ping 172.16.1.2
PING 172.16.1.2 (172.16.1.2) 56(84) bytes of data.
...#我在192.168.30.128上ping 172.16.1.2
#在172.16.1.2上抓包,可以发现是172.16.1.2发过来的请求。
linux-olth:~ # tcpdump -nn -i ens33 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
16:20:01.191918 IP 172.16.1.1 > 172.16.1.2: ICMP echo request, id 4116, seq 1, length 64
16:20:01.191988 IP 172.16.1.2 > 172.16.1.1: ICMP echo reply, id 4116, seq 1, length 64
如果内网地址不固定,可以使用MASQUERADE,这个target会消耗资源,所以斟酌
DNAT是用于保护服务器的
如,Centos6作为web服务器,在网关做一个DNAT,外网通过172.16.1.1:80可以访问192.168.30.128:80,DNAT需要在PREROUTING上做,
[root@test2 ~]# iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.30.128:80 #把访问172.16.1.1:80转换成192.168.30.128:80
#在SUSE上telnet 172.16.1.1:80
linux-olth:~ # telnet 172.16.1.1 80
Trying 172.16.1.1...
Connected to 172.16.1.1.
Escape character is '^]'.
#在192.168.30.128 80端口上抓包
[root@test1 ~]# tcpdump -nn -i eth0 tcp dst port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
11:00:51.932726 IP 172.16.1.2.40394 > 192.168.30.128.80: Flags [S], seq 2023634883, win 29200, options [mss 1460,sackOK,TS val 3943340391 ecr 0,nop,wscale 7], length 0
11:00:51.934523 IP 172.16.1.2.40394 > 192.168.30.128.80: Flags [.], ack 1947788900, win 229, options [nop,nop,TS val 3943340392 ecr 3631953577], length 0
11:00:52.979786 IP 172.16.1.2.403
能顺利捕捉到172.16.1.2发过来的数据包
网友评论