目录
文章目录
iptables 与 netfilter
iptables 是运行在用户空间的防火墙配置工具,是 netfilter 项目的一部分,通过控制运行在 Linux 内核空间的 netfilter 模块,来管理网络数据包的处理和转发。之所以称之为配置工具是因为实际的防火墙过滤功能由内核模块 netfilter 提供,iptables 只是负责提供用户可操作的过滤 rules 配置接口。
简而言之,用户空间的 iptables 制定防火墙规则,内核空间的 netfilter 实现防火墙功能,iptables/netfilter(下文简称为 iptables)组合才是真防火墙。
NOTE:iptables 用于 ipv4,ip6tables 用于 ipv6。最新的 nftables 已经包含在 Linux kernel 3.13 中,以后会取代 iptables 成为主要的 Linux 防火墙配置工具。
NOTE:Netfilter 是 Linux Kernel 的一个数据包处理模块,具有以下功能:
- NAT(Network Address Translate,网络地址转换)
- 数据包过滤
- 基于协议类型的连接跟踪
工作机制
iptables 工作在 TCP/IP 的网络层,处理的是数据包(packet),具有五表五链。
iptables 存在 “表(tables)”、“链(chain)” 和 “规则(rules)” 三个层面。
其中表指的是不同类型的数据包处理流程,如:filter table 表示进行数据包过滤;nat table 则针对连接进行网络地址转换(NAT)操作。每个表中又可以存在多个链,系统按照预订的规则将数据包通过某个内建链,例如:将从本机发出的数据通过 OUTPUT 链。在链中可以存在若干规则,这些规则会被逐一进行匹配,如果匹配,则会执行相应的动作。如:修改数据包,或者跳转。跳转可以直接接受该数据包或拒绝该数据包,也可以跳转到其他链继续进行匹配,或者从当前链返回调用者链。当链中所有规则都执行完仍然没有跳转时,将根据该链的默认策略执行对应动作;如果也没有默认动作,则是返回调用者链。
规则(Rules)
规则(Rules)是用户预定义的,也是我们常说的防火墙规则,配置防火墙的主要工作就是添加、修改和删除这些规则。
数据包的过滤基于规则。规则由一个 目标(target,数据包匹配所有条件后的动作)和很多 匹配(Xmatch,导致该规则可以应用的数据包所满足的条件)指定。iptables 根据规则的匹配条件来尝试匹配每个流经此规则的数据包,一旦匹配成功,则启用规则对应的动作来对数据包进行处理。
匹配:
- interface(e.g. eth0 或者 eth1)
- 协议类型(e.g. ICMP、TCP 或者 UDP)
- Source IP/Destination IP
- Source Port/Destination Port
目标:可以是用户自定义的链、一个内置的特定目标或者是一个目标扩展。
- ACCEPT:运行通过
- DEOP:直接丢弃
- REJECT:拒绝通过
- SNAT:源地址转换
- DNAT:目标地址转换
- MASQUERADE:特殊的 SNAT,适用于动态变更的 IP
- LOG:记录日志信息
- QUEUE:将数据包移交到用户空间
- RETURN:防火墙停止执行当前链中的后续规则,并返回到调用链
- REDIRECT:端口重定向
- MARK:做防火墙标记
链(chain)
**链(chain)**是由若干个顺序排列的规则组成的列表。默认的,链中不存在任何规则。用户可以向链中添加自己预期的防火墙规则。简单来说,链就是顺序执行规则的编排方式。在复杂的网络环境中,管理员需求这种可控的、有序执行的规则应用方式。
链的默认规则通常设置为 ACCEPT,如果想确保任何包都不能通过规则集,则可以重置为 DROP。链中规则的次序非常关键,检查规则的时候,是按照从上往下的顺序进行的。所以谁的规则越严格,越应该放在靠前。默认的规则总是在一条链的最后生效,所以在默认规则生效前数据包需要通过所有存在的规则。
iptables 提供了以下 5 条链:
- INPUT 链:输入链。发往本机的数据报文通过此链。
- OUTPUT 链:输出链。从本机发出的数据报文通过此链。
- PORWARD 链:转发链。由本机转发的数据报文通过此链。
- PREROUTING 链:路由前链(Pre-Routing),在处理路由规则(Routing)前通过此链,通常用于目的地址转换(DNAT)。
- POSTOUTING 链:路由后链(Post-Routing),完成路由规则后通过此链,通常用于源地址转换(SNAT)。
NOTE:用户也可以加入自己定义的链,从而使规则集更有效并且易于修改。
表(tables)
当不同的链中的规则变得繁多而重复时,就会需求一种规则的分类方式。简单来说,表(tables)的本质就是规则集的组织形式。用户在实际的使用中,往往是通过表作为操作入口,对规则进行定义,将不同的表挂载到链上,实现了作用域更大的规则应用效果。
iptables 提供了以下五种表:
- filter 表:是默认表,提供数据包的过滤功能,用于防火墙规则。
- nat 表:提供网络地址转换(NAT)功能,用于网关路由器。
- mangle 表:提供数据包修改功能,拆解、修改、重新封装数据包。
- raw 表:关闭 net 表启动的连接追踪机制。
- security 表:用于强制访问控制网络规则。
每张表可挂载的链如下图所示::
网络数据包通过 iptables 的过程
┏╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┓
┌───────────────┐ ┃ Network ┃
│ table: filter │ ┗━━━━━━━┳━━━━━━━┛
│ chain: INPUT │◀────┐ │
└───────┬───────┘ │ ▼
│ │ ┌───────────────────┐
┌ ▼ ┐ │ │ table: nat │
│local process│ │ │ chain: PREROUTING │
└ ┘ │ └─────────┬─────────┘
│ │ │
▼ │ ▼ ┌─────────────────┐
┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ │ ┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ │table: nat │
Routing decision └─────Routing decision ─────▶│chain: PREROUTING│
┅┅┅┅┅┅┅┅┅┳┅┅┅┅┅┅┅┅┅ ┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ └────────┬────────┘
│ │
▼ │
┌───────────────┐ │
│ table: nat │ ┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ │
│ chain: OUTPUT │ ┌─────▶Routing decision ◀──────────────┘
└───────┬───────┘ │ ┅┅┅┅┅┅┅┅┳┅┅┅┅┅┅┅┅
│ │ │
▼ │ ▼
┌───────────────┐ │ ┌────────────────────┐
│ table: filter │ │ │ chain: POSTROUTING │
│ chain: OUTPUT ├────┘ └──────────┬─────────┘
└───────────────┘ │
▼
┏╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┓
┃ Network ┃
┗━━━━━━━━━━━━━━━┛
总结链、表和规则的关系
简单总结一下三者的关系。规则(rules)是数据包处理方式的描述、表(tables)是规则集的分类组织形式,链(chain)则是作为表的挂载点、以及表中规则集的有序执行的编排方式。
从网络数据包通过 iptables 的过程我们了解到,在 Linux 操作系统中 链的位置、链与表的挂载关系 实际上是比较固定的。作为用户,我们需要关心的仅仅是如何在特定的表中添加、修改、删除规则来影响数据包在 Linux 操作系统中的流入、流出以及转发。
iptables 指令应用
制定 iptables 表规则思路:
- 选择一张表(此表决定了数据包的处理方式,e.g. filter、nat)
- 选择一条链(此链决定了数据包的流经位置,e.g. INPUT、OUTPUT)
- 选择合适的条件(此条件决定了对数据包做何种条件匹配,e.g. Source IP、icmp)
- 选择处理数据包的动作,制定相应的防火墙规则(e.g. ACCEPT、DEOP)
iptables 语法格式:
iptables [ -t 表名 ] 管理选项 [ 链名 ] [ 条件匹配 ] [ -j 目标动作或转发 ]
NOTE:不指定表名时,默认为 filter 表,不指定链名时,默认表示该表的所有链。除非设置了链的缺省策略,否则需要指定条件匹配。
help:
Usage: iptables -[ACD] chain rule-specification [options]
iptables -I chain [rulenum] rule-specification [options]
iptables -R chain rulenum rule-specification [options]
iptables -D chain rulenum [options]
iptables -[LS] [chain [rulenum]] [options]
iptables -[FZ] [chain] [options]
iptables -[NX] chain
iptables -E old-chain-name new-chain-name
iptables -P chain target [options]
iptables -h (print this help information)
Daemon
大多 Linux 发型版将 iptables 被做成了一个服务,启动,则将防火规则生效。反之,则将防火规则撤销。
systemctl enable iptables.service
systemctl start iptables.service
配置文件为 /etc/sysconfig/iptables
或 /etc/iptables/iptables.rules
。
保存和加载规则
通过命令行添加规则,配置文件不会自动改变,所以必须手动保存:
# 备份与保存规则至指定文件
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:仅分析生成规则集,但不提交
查看规则
默认查看的是 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 -F # 清空所有的防火墙规则
iptables -X # 删除用户自定义的空链
iptables -Z # 清空计数
# 开发所有向外出口
# NOTE:更加严格的安全规则,连出口也会严格限制
iptables -A OUTPUT -j ACCEPT
# 放行本地回环,本地回环 lo 地址 127.0.0.1 是仅在本机上使用的,它进、出都设置为允许
iptables -A INPUT -i lo -j ACCEPT
# 放行已建立的或相关的连接的
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 允许被 ping
iptables -A INPUT -p icmp -j ACCEPT
# 放行 ssh 登录到本机
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# 配置默认链策略,拒绝所有
# NOTE:设置了默认策略,你将无法 ssh 连接到该机器。所以一般的会先设置 ssh 放行规则
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP
更多示例
放行所有网段的主机访问本机的 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
网络地址转换:假设办公室用小型局域网,由一台 Linux 主机作为路由器共享地址接入 Internet。局域网接口为 eth0,地址使用 192.168.0.0/24;Internet 接口为 eth1,使用的地址为 198.51.100.3。在局域网用户访问 Internet 时,源地址(SNAT)需要被转换为 198.51.100.3,若需要在局域网 192.168.0.2 上开启 HTTP 服务,将访问外部 TCP 80 端口的数据包重定向,则可以设置相应的目的地址(DNAT)转换。则使用规则:
# SNAT:由内到外的源地址转换
iptables -t nat -I POSTROUTING -s 192.168.0.0/24 -o eth1 -j SNAT --to 198.51.100.3
# DNAT:由外到内的目的地址转换
iptables -t nat -I PREROUTING -p tcp -d 198.51.100.3 --dport 80 -j DNAT --to 192.168.0.2
NOTE:NAT 转发操作需要在 filter 表中 FORWARD 链中允许,并且打开系统的转发功能。
网络地址转换 && 端口重定向:本机的 2222 端口映射到内网虚拟机的 22 端口
iptables -t nat -A PREROUTING -d 210.14.67.127 -p tcp --dport 2222 -j DNAT --to-dest 192.168.188.115:22
指定数据包出去的网络接口:
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
指令选项解析
管理选项
- 规则显示
-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:
- 对于进入的状态为 ESTABLISHED 都应该放行
- 对于出去的状态为 ESTABLISHED 都应该放行
- 严格检查进入的状态为 NEW 的连接
- 所有状态为 INVALIED 都应该拒绝
实战经验
为 OpenStack AIO 环境配置防火墙
- 让 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
- 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
- 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 的数据包:
但是没有 172.18.128.0/24 <= 10.8.8.201 <= 172.18.22.200:80 的数据包:
原因是没有添加 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 只有很多网络的问题都能有解决的思路了,非常棒的一个工具。
- 不开启本地回环的防火墙规则的话,
openstack server list
指令无法执行,看来本地回环规则应该要默认开启才好。
参考文章
https://www.cnblogs.com/frankb/p/7427944.html
https://wangchujiang.com/linux-command/c/iptables.html
https://wiki.archlinux.org/index.php/Iptables_(简体中文)#表(Tables)