目录


文章目录

  • 目录
  • iptables/netfilter 框架
  • iptables-service
  • iptables 指令应用
  • 查看规则
  • 添加规则
  • 删除规则
  • 修改规则
  • 保存和加载规则
  • 常规初始化配置
  • 指令选项解析
  • 管理选项
  • 条件匹配(Xmatch)
  • 实战经验
  • 为 OpenStack AIO 环境配置防火墙
  • 更多示例


iptables/netfilter 框架

iptables 是运行在 Userspace 的防火墙配置工具,是 netfilter 项目的防火墙应用部分,通过控制运行在 Kernelspace 的 netfilter 模块,来管理网络数据包的处理和转发。

之所以称 iptables CLI 为配置工具,是因为实际的防火墙过滤功能由内核模块 netfilter 提供,iptables 只是负责提供用户可操作的过滤 rules 配置接口。

简而言之,用户空间的 iptables 制定防火墙规则,内核空间的 netfilter 实现防火墙功能,iptables/netfilter(下文简称为 iptables)组合才是真防火墙。

NOTE​:iptables 用于 ipv4,ip6tables 用于 ipv6。最新的 nftables 已经包含在 Linux kernel 3.13 中,以后会取代 iptables 成为主要的 Linux 防火墙配置工具。

Linux Kernel TCP/IP Stack — L3 Layer — netfilter/iptables 防火墙_加载

iptables-service

大多 Linux 发型版将 iptables 被做成了一个服务,启动,则将防火规则生效。反之,则将防火规则撤销。

# 停止 firewalld 服务
systemctl stop firewalld
# 禁用 firewalld 服务
systemctl mask firewalld

yum install -y iptables
yum install iptables-services

systemctl enable iptables.service
systemctl start iptables.service

配置文件为 ​​/etc/sysconfig/iptables​​​ 或 ​​/etc/iptables/iptables.rules​​。

iptables 指令应用

制定 iptables 表规则思路​:

  1. 选择一张表(此表决定了数据包的处理方式,e.g. filter、nat)
  2. 选择一条链(此链决定了数据包的流经位置,e.g. INPUT、OUTPUT)
  3. 选择合适的条件(此条件决定了对数据包做何种条件匹配,e.g. Source IP、icmp)
  4. 选择处理数据包的动作,制定相应的防火墙规则(e.g. ACCEPT、DEOP)

iptables 语法格式​:

iptables [ -t 表名 ] 管理选项 [ 链名 ] [ 条件匹配 ] [ -j 目标动作或转发 ]

NOTE​:不指定表名时,默认为 filter 表,不指定链名时,默认表示该表的所有链。除非设置了链的缺省策略,否则需要指定条件匹配。

Linux Kernel TCP/IP Stack — L3 Layer — netfilter/iptables 防火墙_扩展模块_02

查看规则

默认查看的是 filter 表的规则,可以指定表名或链名,也可以显示规则编号。

iptables -nvL [--line-numbers] [-t 表名] [链名] 

--line-numbers:列出规则编号
  • 五表:raw,nat,filter,mangle,security
  • 五链:INPUT、OUTPUT、FORWARD、PREROUTING、POSTROUTING

添加规则

添加规则有两种方式,一种是在链最后追加(-A)规则,另一种是将规则插入(-I)到链上的某个特定位置。

# 添加规则到指定的链中
iptables -A INPUT -s 192.168.1.5 -j DROP

# 插入规则到指定的链中,默认为插入到链首
iptables -I INPUT -p tcp --dport 17500 -s 10.0.0.85 -j ACCEPT -m comment --comment "Friendly Dropbox"

删除规则

# 通过编号删除链中的规则
iptables -D INPUT 8

修改规则

# 用新规则代替已存在的旧规则
iptables -R INPUT 2 -s 127.0.0.1 -d 127.0.0.1 -i lo -j ACCEPT

保存和加载规则

通过命令行添加规则,配置文件不会自动改变,所以必须手动保存:

# 备份与保存规则至指定文件
cp /etc/sysconfig/iptables /etc/sysconfig/iptables.bak
iptables-save > /etc/sysconfig/iptables

修改配置文件后,需要重新加载服务生效:

systemctl reload iptables

或者通过指定配置文件由 iptables 直接加载:

# 从指定文件加载规则
iptabls-restore < /PATH/FROM/SOME_RULE_FILE
-n, --noflush:不清除原有规则
-t, --test:仅分析生成规则集,但不提交

常规初始化配置

# 查看 iptables 现有规则
iptables -L -n

# 备份现有的规则
cp /etc/sysconfig/iptables /etc/sysconfig/iptables.bak

# 先允许所有
iptables -P INPUT ACCEPT

# 清空所有默认规则
iptables -F
# 清空所有自定义规则
iptables -X
# 所有计数器归 0
iptables -Z

# 开放本地回环
iptables -A INPUT -i lo -j ACCEPT
# 开放已建立的或相关的连接的
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 开放 22 端口(SSH)
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# 开放 21 端口(FTP)
iptables -A INPUT -p tcp --dport 21 -j ACCEPT
# 开放 80 端口(HTTP)
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
# 开放 443 端口(HTTPS)
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
#开放 ping
iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT
# 允许接受本机请求之后的返回数据 RELATED,是为 FTP 设置的
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

# 其他入站一律丢弃
iptables -P INPUT DROP
# 所有出站一律绿灯
iptables -P OUTPUT ACCEPT
# 所有转发一律丢弃
iptables -P FORWARD DROP

指令选项解析

管理选项

  • 规则显示
-L, --list [chain]:列出规则;
-v, --verbose:详细信息;
-vv 更详细的信息
-n, --numeric:数字格式显示主机地址和端口号;
-x, --exact:显示计数器的精确值,而非圆整后的数据;
--line-numbers:列出规则时,显示其在链上的相应的编号;
-S, --list-rules [chain]:显示指定链的所有规则;
  • 规则管理
-A, --append chain rule-specification:追加新规则于指定链的尾部; 
-I, --insert chain [rulenum] rule-specification:插入新规则于指定链的指定位置,默认为首部;
-R, --replace chain rulenum rule-specification:使用新的规则替换指定的旧规则;
-D, --delete chain rulenum:根据规则编号删除规则;
-D, --delete chain rule-specification:根据规则本身删除规则;
  • 链管理
-N, --new-chain chain:新建一个自定义链;
-X, --delete-chain [chain]:删除自定义的引用计数为 0 的空链;
-F, --flush [chain]:清空指定链上的规则;
-E, --rename-chain old-chain new-chain:重命名链;
-Z, --zero [chain [rulenum]]:置零计数器;
NOTE:每条规则都有两个计数器
1. packets:被本规则匹配到的数据包个数;
2. bytes:被本规则匹配到的数据包大小之和;
-P, --policy chain target:制定链表的策略(ACCEPT | DROP | REJECT);

条件匹配(Xmatch)

条件匹配分为基本匹配和扩展匹配,扩展匹配又分为显示匹配和隐式匹配。

基本匹配​:无需加载扩展模块,匹配规则生效

-p:指定规则协议,e.g. tcp/udp/icmp/all
-s:指定数据包的源地址,IP or Hostname
-d:指定数据包的目的地址
-i:输入接口,网卡设备
-o:输出接口
!:取反

扩展匹配​:需要加载扩展模块,匹配规则方可生效;

隐式匹配​:使用 -p 选项指明协议时,无需同时使用 -m 选项指明扩展模块以及不需要手动加载扩展模块;

-p tcp
--sport:匹配报文段的源端口;可以给出多个端口,但只能是连续的端口范围
--dport:匹配报文段的目标端口;可以给出多个端口,但只能是连续的端口范围
--tcp-flags mask comp:匹配报文段的 tcp 标志位
-p udp
--sport:匹配数据报端口;可以给出多个端口,但只能是连续的端口范围
--dport:匹配数据报目标端口;可以给出多个端口,但只能是连续的端口范围
--icmp-type
8:echo request,Ping 请求
0:echo reply,接收 Ping 请求之后响应的 Ping 应答

显示匹配​:必须使用 -m 选项指明要调用的扩展模块的扩展机制以及需要手动加载扩展模块;

  • multiport(多端口)​:以离散或连续的方式定义多端口匹配条件,最多 15 个。
iptables -I INPUT -d 172.16.100.7 -p tcp -m multiport --dports 22,80 -j ACCEPT
iptables -I OUTPUT -s 172.16.100.7 -p tcp -m multiport --sports 22,80 -j ACCEPT
  • iprange(IP 范围)​:以连续地址块的方式来指明多个 IP 地址匹配条件。
iptables -A INPUT -d 172.16.100.7 -p tcp --dport 23 -m iprange --src-range 172.16.100.1-172.16.100.100 -j ACCEPT
iptables -A OUTPUT -s 172.16.100.7 -p tcp --sport 23 -m iprange --dst-range 172.16.100.1-172.16.100.100 -j ACCEPT
  • time​:指定时间范围。
iptables -A INPUT -d 172.16.100.7 -p tcp --dport 901 -m time --weekdays Mon,Tus,Wed,Thu,Fri --timestart 08:00:00 --time-stop 18:00:00 -j ACCEPT
iptables -A OUTPUT -s 172.16.100.7 -p tcp --sport 901 -j ACCEPT
  • string​:对应用层的报文做字符串模式匹配检测。
--algo {bm|kmp}:字符匹配查找时使用算法
--string "STRING":要查找的字符串
--hex-string "HEX-STRING":要查找的字符,先编码成16进制格式
  • connlimit​:根据每个客户端 IP 作并发连接数量限制。
--connlimit-upto n:连接数小于或等于 n 时匹配
--connlimit-above n:连接数大于 n 时匹配
  • limit​:报文速率控制。
  • state​:追踪本机上的请求和响应之间的数据报文的状态。
  • INVALID:无法识别的连接
  • ESTABLISHED:已建立的连接
  • NEW:新建立的连接
  • RELATED:相关联的连接,当前连接是一个新连接,但依附于某个已存在的连接
  • UNTRACKED:未追踪的连接

NOTE​:

  1. 对于进入的状态为 ESTABLISHED 都应该放行
  2. 对于出去的状态为 ESTABLISHED 都应该放行
  3. 严格检查进入的状态为 NEW 的连接
  4. 所有状态为 INVALIED 都应该拒绝

实战经验

为 OpenStack AIO 环境配置防火墙

  1. 让 AIO Ping 能通外网,但外网无法 Ping 通 AIO。
# 首先清空 AIO 的防火墙
iptables -F
iptables -X
iptables -Z

# 放行本机回环
iptables -A INPUT -i lo -j ACCPET
iptables -A OUTPUT -o lo -j ACCPET

# 放行本机发送 ICMP 8(echo request)请求数据包
iptables -A OUTPUT -p icmp --icmp-type 8 -j ACCEPT
# 放行接收 ICMP 0(echo reply)应答数据包
iptables -A INPUT -p icmp --icmp-type 0 -j ACCEPT

NOTE 1:如果不放行本机回环的话,无法 Ping 通外部网络,原因未明???

NOTE 2:如果希望只运行 Ping 通指定网段(e.g. 172.18.22.0/24)的话,需要指定目的 IP 网段。

iptables -R OUTPUT 1 -p icmp --icmp-type 8 -d 172.18.22.0/24 -j ACCEPT

在 host 172.18.22.220 抓包:

[root@localhost ~]# tcpdump -i ens160 -nnt src host 172.18.22.200
...
IP 172.18.22.200 > 172.18.22.220: ICMP echo request, id 49924, seq 1, length 64
  1. AIO 和外部可以互相 SSH
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT

NOTE 1:如果不放行 ssh 22 出口的话,外部无法 SSH 到本机,原因未明???

NOTE 2:因为 ssh 22 是一个 TCP 应用程序而非一个标准协议,所以是使用 ​​-p tcp --dport/--sport​​ 来指定的。

NOTE 3:如果希望指定网络的主机可以 SSH 到本机可以设定 INPUT 的 Source IP;如果希望指定本机只能 SSH 到指定网络的主机,可以设定 OUTPUT 的 Dest IP。e.g. 只允许 172.18.22.0/24 网段的主机可以 SSH 到本机:

iptables -R INPUT 3 -p tcp --dport 22 -s 172.18.22.0/24 -j ACCEPT
  1. AIO 的 80 端口(Dashboard)可以被指定的外部网络(172.18.128.0/24)访问
iptables -A INPUT -p tcp --dport 80 -s 10.8.8.201/24 -j ACCEPT

此时在 AIO 使用 tcpdump 抓包,有 172.18.128.0/24 => 10.8.8.201 => 172.18.22.200:80 的数据包:

Linux Kernel TCP/IP Stack — L3 Layer — netfilter/iptables 防火墙_数据_03

但是没有 172.18.128.0/24 <= 10.8.8.201 <= 172.18.22.200:80 的数据包:

Linux Kernel TCP/IP Stack — L3 Layer — netfilter/iptables 防火墙_扩展模块_04

原因是没有添加 AIO tcp 80 的出口规则:

iptables -A OUTPUT -p tcp --sport 80 -d 10.8.8.201 -j ACCEPT

NOTE:一开始怎么都不通,是因为我将出口的 Dest IP 设置成为了 ​​172.18.128.0/24​​​,我没想到本地网络还有路由网关 ​​10.8.8.201​​。全靠 tcpdump 抓包才能发现这个 GW,习惯使用 tcpdump 只有很多网络的问题都能有解决的思路了,非常棒的一个工具。

  1. 不开启本地回环的防火墙规则的话,​​openstack server list​​ 指令无法执行,看来本地回环规则应该要默认开启才好。

更多示例

放行所有网段的主机访问本机的 httpd 服务​:

# 入向规则
iptables -t filter -A INPUT -p tcp –dport 80 -m state –state NEW,ESTABLISHED -j ACCEPT
# 出向规则
iptables -t filter -A OUTPUT -p tcp –sport 80 -m state –state ESTABLISHED -j ACCEPT

端口重定向​:

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

NOTE:如果你在你的计算机上面运行了这个指令,它只会对连到你的机器上的外部 IP 产生效果。从本地端发起的连线不会遵循 nat 表上 PREROUTING 链的设置。如果你想让本地端也遵循规则,你需要将 lo 接口上的数据包输出由 80 端口转向到 8080 端口上面:

iptables -t nat -A OUTPUT -o lo -p tcp --dport 80 -j REDIRECT --to-port 8080

指定数据包出去的网络接口​:

NOTE:该操作只对 OUTPUT,FORWARD,POSTROUTING 三个链起作用。

iptables -A FORWARD -o eth0

阻止 Windows 蠕虫的攻击​:

iptables -I INPUT -j DROP -p tcp -s 0.0.0.0/0 -m string --algo kmp --string "cmd.exe"

防止 SYN 洪水攻击​:

iptables -A INPUT -p tcp --syn -m limit --limit 5/second -j ACCEPT