Linux iptables
iptables
iptables是一个用户空间实用程序,允许系统管理员配置Linux内核防火墙(实现为不同的Netfilter模块)及其存储的链和规则提供的表,不同的内核模块和程序目前用于不同的协议; iptables适用于IPv4,ip6tables为IPv6,arptables为ARP,ebtables适用于以太网帧。
iptables 的组成
iptables 由四表五链及一些规则组成
四表
- filter :过滤规则表
- nat :地址转换表
- mangle :修改数据标记位规则表
- raw :跟踪数据规则表
五链
- INPUT
- OUTPUT
- PREROUTING
- POSTROUTING
- FORWARD
iptables 规则添加的一些原则
添加iptables规则时,思考放在那张表上才能实现控制功能,根据报文的流向决定房在哪个链上。规则在表中的顺序即为检查的顺序。
- 同类型规则,匹配精度高的规则放在上面
- 不同类规则,匹配报文频率较大的放上面
- 将可由一条规则描述的多条规则合并为一条
- 设置默认规则
iptables 命令格式
iptables [-t table] {subcommand chain} [-m matchname [per-match-options]] {-j targetname [per-target-options]}
[-t table]
规则添加在那张表上,省略不写为 filter
{subcommand chain}
subcommand 为对链上的规则进行何种操作的选项,按功能可分为以下几类
- 链管理
-N CHAIN_NAME :添加链
-X :删除链
-P :修改默认规则
-E :重命名自定义链,被关联的不能修改
- 查看
-L : list
-n : 不做反向解析
-v,-vv :显示详细信息
-x : exactly
--line-numbers :显示规则编号
-S : 以iptables-save命令格式显示链上的规则
- 规则管理
-A : 追加规则
-I [rulenum] : 插入规则
-D chain [rulenum] : 删除规则
-R chain rulenum : 替换规则
-F [chain [rulenum]]: 删除规则
-Z [chain [rulenum]]:清空规则上统计的包,字节
[-m matchname [per-match-options]]
该项为匹配条件,匹配条件可分为:
- 基本匹配 :netfilter自带的匹配规则
[!] -s address[/mask][,...] #匹配源地址
[!] -d address[/mask][,...] #匹配目标地址
[!] -p tcp|udp|icmp|all #匹配协议协议参考/etc/protocols中的定义
[!] -i interface_name #匹配报文流入的网卡接口
[!] -o interface_name #匹配报文流出的网卡接口
- 扩展匹配 :由扩展模块引入的匹配规则
- 隐式扩展 :对某一种协议的扩展,不需使用
-m
选项指明模块
- 隐式扩展 :对某一种协议的扩展,不需使用
1. tcp
[!] --sport PORT[:PORT] #匹配tcp源端口
[!] --dport PORT[:PORT] #匹配tcp目标端口
[!] --tcp-flags MASK COMP
#匹配tcp中的标志位SYN,ACK,FIN,RST,ALL,NONE
[!] --syn
#匹配tcp三次握手的第一次握手,等同于 --tcp-flags SYN,ACK,FIN,RST SYN
2. udp
[!] --sport PORT[:PORT] #匹配UDP源端口
[!] --dport PORT[:PORT] #匹配UDP目标端口
3. icmp
[!] --icmp-type {type[/code]|typename}
0/0 echo-reply #icmp应答
8/0 echo-request #icpm请求
- 显示扩展 :额外附件的更多匹配规则,功能性的扩展
需使用-m
选项指明扩展模块
1. multiport
--sports PORT[:PORT],PORT,... #匹配多个源端口
--dports PORT[:PORT],PORT,... #匹配多个目标端口
2. iprange
--src-range from[-to] #匹配连续的一组源IP
--dst-range from[-to] #匹配连续的一组目标IP
3. mac
--mac-source XX:XX:XX:XX:XX:XX #匹配源MAC地址
4. string #匹配字符串
--algo {bm|kmp} #指定算法
[!] --string pattern #给定匹配字符串的模式
[!] --hex-string pattern #给定十六进制的匹配字符串的模式
5. 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,...] #每周中的第几天
注意:CentOS7使用的是UTC时间,需减去8h
CentOS6使用本地时间,不需减
6. connlimit
--connlimit-upto n :小于等于n匹配
--connlimit-above n :大于n匹配
7. limit
--limit rate[/second|/minute|/hour|/day] #频率
--limit-burst number #从第几个开始
8. state
--state state
NEW #新建立连接
ESTABLISHED #已建立的连接
RELATED #与已建立的连接相关联的连接
INVALID #无效的连接
UNTRACKED #未跟踪的连接
{-j targetname [per-target-options]}
该项为匹配后处理的动作
ACCEPT #允许通过
DROP #丢弃到匹配的包
REJECT #拒绝通过
RETURN #返回调用的链
REDIRECT #端口转发
LOG #记录日志
MARK #做防火墙标记
DNAT #目标地址转换
SNAT #源地址转换
MASQUERADE #地址伪装
iptables 规则的保存与重载
查看当前内存中的规则
iptables -S
规则的保存
# CentOS6中的规则保存
sevice iptables save #保存于/etc/sysconfig/iptables中
#CentOS7中的规则保存
iptables -S > /path/file #方法一
iptables-save [option] > /path/file #方法二
-n|--noflush #追加规则
-t|--test #仅测试
规则的重载
# CentOS6 中重载规则到内存中
# 重启iptables服务自动重载/etc/sysconfig/iptables中的规则
service iptables restart
# CentOS7 中重载规则到内存中
iptables-restore < /path/file
实例
查看iptables中已添加的规则
iptables -vnL #查看filter表中添加的规则
iptables -t nat -vnL #查看表nat中添加的规则
iptables -S #以命令的格式显示filter表中添加的规则
开放被动模式的ftp服务
# 1. 装载nf_conntrack_ftp模块
modprobe nf_conntrack_ftp
# 2. 添加规则禁止所有172.18.17.15主机连接
iptables -A INPUT -s 172.18.17.15/32 -j REJECT
# 3. 让已建立的连接通过,并且新建立的连接与已建立的连接有关联的也允许通过
iptables -I INPUT -p tcp -m state --state RELATED,ESTABLISHED -j ACCEPT
# 4. 让21号端口通过
iptables -I INPUT 2 -p tcp -m tcp --dport 21 -m state --state NEW -j ACCEPT
自定义链
通过自定义链设置Server主机的防火墙仅允许Client PING通。
# 1. 修改默认INPUT、OUTPUT连接为DROP
iptables -P INPUT DROP
iptables -P OUTPUT DROP
# 2. 新建自定义链
iptables -N chain1
iptables -N chain2
# 3. 自定义链上添加允许Ping的规则
iptables -A chain1 -s 172.18.17.15/32 -p icmp -m icmp --icmp-type 8 -j ACCEPT
iptables -A chain2 -d 172.18.17.15/32 -p icmp -m icmp --icmp-type 0 -j ACCEPT
# 4. 自定义链与链INPUT、OUTPUT关联
iptables -A INPUT -j chain1
iptables -A OUTPUT -j chain2
SNAT
SNAT原理
网络地址转换分为源地址转换和目标地址转换
SNAT : Source Network Address Translation,由内网发起请求,修改请求报文中的源IP地址,从而让本地网络中的主机可以使用统一的公网地址与外部主机通信,解决IPv4公网地址不足的问题,也达到隐藏内网主机的作用,增强内网主机的安全性。源IP如何修改由系统管理员定义在NAT上的规则决定,响应报文则修改目标IP,由NAT自动根据会话表中追踪机制实现相应修改。
SNAT实现
如下图所示,Client 为公司内部的一台主机,通过NAT地址转换,最终实现访问外网WEB服务器的目的。此处将172.18.0.0/16当做公网地址(虽然它是私网地址)
# 1. 按上图搭建好拓扑图,SNAT服务器启用路由转发功能
# 临时修改立即生效
echo 1 > /proc/sys/net/ipv4/ip_forward
# 修改/etc/sysctl.conf配置文件,永久生效
net.ipv4.ip_forward=1
# 2. Client主机网关指向SNAT的内网地址192.168.17.21
[20@root network-scripts]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.17.21 0.0.0.0 UG 100 0 0 ens34
192.168.17.0 0.0.0.0 255.255.255.0 U 100 0 0 ens34
# 3. SNAT上配置防火墙功能,转换源IP
[21@root ~]# iptables -t nat -A POSTROUTING -s 192.168.17.0/24 ! -d 192.168.17.0/24 -j SNAT --to-source 172.18.17.21
# 4. Client上测试
[20@root network-scripts]# curl 172.18.17.22
DNAT
DNAT原理
DNAT :Destination Network Address Translation,隐藏内网中真实服务器的IP地址,使用统一的公网地址向外提供服务。由外部主机发起请求,NAT修改IP请求报文中的目标IP地址为内部网络中服务器的地址。目标IP地址如何修改由系统管理员定义在NAT上的规则决定,回应报文则修改源IP地址,由NAT自动根据会话表中追踪机制实现相应修改。
DNAT实现
如下图所示,WEB为公司内部的一台WEB服务器,没有公网地址,并且使用的WEB服务端口为8080,要求外部主机能够通过DNAT上的公网地址访问到内部主机的WEB服务。此时就需使用DNAT来实现。此处将172.18.0.0/16当做公网地址(虽然它是私网地址)
# 1. 按上图搭建好拓扑图,DNAT服务器启用路由转发功能
# 临时修改立即生效
echo 1 > /proc/sys/net/ipv4/ip_forward
# 修改/etc/sysctl.conf配置文件,永久生效
net.ipv4.ip_forward=1
# 2. WEB主机网关指向DNAT的内网地址192.168.17.21
[20@root network-scripts]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.17.21 0.0.0.0 UG 100 0 0 ens34
192.168.17.0 0.0.0.0 255.255.255.0 U 100 0 0 ens34
# 3. DNAT上配置防火墙功能,实现转换目标IP
[21@root ~]# iptables -t nat -A PREROUTING -d 172.18.17.21 -p tcp --dport 80 -j DNAT --to-destination 192.168.17.20:8080
# 4. Client上测试
[22@root ~]# curl 172.18.17.21
REDIRECT
端口重定向,可用于改变端口。当服务器上使用了非标准端口对外提供服务,此时可使用REDIRECT将标准端口转为自己定义的非标准端口。
如下图所示WEB服务器本机启用了8080端口对外提供服务,客户端使用默认的80端口能够访问WEB服务。在WEB服务器上配置防火墙规则实现此功能。
iptables -t nat -A INPUT -d 172.18.17.22 -p tcp --dport 80 -j REDIRECT --to-port 8080