Administrator
发布于 2025-05-13 / 113 阅读
0
0

CentOS7 iptables 使用(允许、封禁 IP)

前言

iptables 作为底层防火墙框架,已经有新的官方继任者 nftables 了(内核版本 3.15 及以上)。

在一些旧的发行版,比如阿里云 CentOS 7 版本是 3.10(uname -r),只能用 iptables(通常默认会附带 firewalld)。

对于普通用户,推荐使用 firewalld。firewalld 是更上层、更易用的抽象层(接口层)。建议技术人员或者遇到极其复杂的网络配置、性能极致优化时,才去操作 iptables、nftables。

firewalld 是 Red Hat 系的产物,Debian 系默认没有集成,但可以通过官方软件源另行安装。

用汽车类比:iptables、nftables 这些底层防火墙框架相当于发动机的控制算法,firewalld 相当于油门、刹车、挡位这些易于操作的工具。

注意事项:iptables、nftables 、firewalld 选一个配置就行,请不要同时配置,可能会引起规则冲突。

firewalld、iptables、nftables 关系图:

firewalld 的使用请看本站另一篇文章【CentOS7 firewalld 使用】。

一、iptables 表和链

iptables 共有 5 个表(table),按处理优先级从高到低排列:

表名

优先级

用途

支持的链

raw

1(最高)

连接跟踪控制(NOTRACK)

PREROUTING, OUTPUT

mangle

2

修改数据包头部(TOS、TTL、MARK)

PREROUTING, INPUT, FORWARD, OUTPUT, POSTROUTING

nat

3

网络地址转换(DNAT、SNAT、MASQUERADE)

PREROUTING, INPUT, OUTPUT, POSTROUTING

filter

4

数据包过滤(ACCEPT、DROP、REJECT),默认表

INPUT, FORWARD, OUTPUT

security

5(最低)

SELinux 安全上下文标记

INPUT, FORWARD, OUTPUT

提示:

  • 不指定 -t 时默认使用 filter 表。

  • 大多数日常操作(放行/拦截端口)都在 filter 表

  • NAT 操作必须在 nat 表(详见本站《Linux 策略路由与 NAT 转发指南》)

(1)数据包流向

不同流向的数据包经过的链顺序不同(可配合下方数据包流向图对照理解):

入站包(到达本机):

PREROUTING → INPUT → 本机进程
(mangle/nat) (mangle/filter/security)

转发包(经过本机):

PREROUTING → FORWARD → POSTROUTING
(mangle/nat) (mangle/filter/security) (mangle/nat)

本机发出的包:

OUTPUT → POSTROUTING
(mangle/nat/filter/security) (mangle/nat)

(2)数据包在各表中的完整路径

入站包:
raw(PREROUTING) → mangle(PREROUTING) → nat(PREROUTING)
→ mangle(INPUT) → filter(INPUT) → security(INPUT)

转发包:
raw(PREROUTING) → mangle(PREROUTING) → nat(PREROUTING)
→ mangle(FORWARD) → filter(FORWARD) → security(FORWARD)
→ mangle(POSTROUTING) → nat(POSTROUTING)

本机发出的包:
raw(OUTPUT) → mangle(OUTPUT) → nat(OUTPUT) → filter(OUTPUT) → security(OUTPUT)
→ mangle(POSTROUTING) → nat(POSTROUTING)

(3)规则链创建、引用

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
  931  564K ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    1    60 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0           
    1    60 INPUT_direct  all  --  *      *       0.0.0.0/0            0.0.0.0/0   
    0     0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate INVALID
# 所有未被前面规则匹配的包,都执行 REJECT 动作,并且在拒绝时向发送方返回一个 icmp-host-prohibited 类型的 ICMP 错误报文。
    0     0 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited

Chain INPUT_direct (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    2   216 ACCEPT     47   --  *      *       0.0.0.0/0            0.0.0.0/0  

如上所示,INPUT_direct 规则链被 INPUT 链所引用(1 reference)。

  • 创建:使用 iptables -N <自定义链名> 就可以创建一条新的、空的规则链

  • 引用:用 -j 参数将数据包从默认链“跳转”到自定义链。例如,iptables -I INPUT -j INPUT_direct。只有被引用后,自定义链才有意义。

二、查看 iptables 所有规则

# 1、查看所有
iptables -L
iptables -L -nv

# 2、查看指定的 chain
iptables -L IN_public_allow -nv
iptables -L INPUT -nv
  • -L:--list,列出所有规则。语法:-L [chain [rulenum]]

  • -n:--numeric,显示 ip 和端口号,而不是解析为域名

  • -v:--verbose,详细信息

  • -t:--table,默认是 filter 表

  • --line-numbers,显示规则行号,删除会用到

三、添加规则到规则链中

注意规则顺序:iptables 按顺序匹配,允许规则必须优先于拒绝规则,否则会被提前拦截。

# 1、允许特定 IP 访问(一般用不上)
iptables -A INPUT -j DROP
iptables -A INPUT -s 192.168.1.100 -j ACCEPT

# 2、拒绝特定 IP 访问(封禁 IP)
iptables -A INPUT -s 192.168.1.100 -j DROP
iptables -I INPUT -s 192.168.1.100 -j DROP

# 3.1 拒绝访问 3306 数据库
iptables -A INPUT -p tcp --dport 3306 -j DROP

# 3.2 放行 ip 访问 3306、只允许建立新连接(目前我们生产环境使用)
iptables -A IN_public_allow -s 10.96.224.136 -p tcp --dport 3306 -m conntrack --ctstate NEW,UNTRACKED -j ACCEPT

# 3.3 放行当前 ip 访问 3306、只允许建立新连接(目前我们生产环境使用)
iptables -A IN_public_allow -s ${SSH_CLIENT%% *} -p tcp --dport 3306 -m conntrack --ctstate NEW,UNTRACKED -j ACCEPT

# ${SSH_CLIENT}
# 输出: 客户端IP地址 客户端端口号 服务器端口号 => 例如: 192.168.1.100 54321 22
# %% * => %%空格*
# %%模式匹配: 去掉匹配的最长后缀, 去掉第一个空格以及后面的所有字符(* 匹配所有字符)
  • -A:Append(追加),追加到链条的最后,最后匹配。

  • -I:Insert(插入),插入到链的最前面(或指定位置),优先匹配。

  • INPUT:规则链名称

  • -s:--source,语法:-s address[/mask]

  • -p:--protocol,协议,例如 tcp

  • --dport:目标端口为 3306

  • -m conntrack --ctstate NEW,UNTRACKED:-m 同 --match,使用连接跟踪模块,匹配状态为 NEW(新连接)或 UNTRACKED(未跟踪)的连接。只允许建立新的连接,防止某些类型的攻击(如 SYN 洪水攻击)。高流量的环境中如果连接跟踪表满了,新连接也会标记为 UNTRACKED

  • -j:--jump,跳转到某个目标操作,用于指定目标操作。

    • ACCEPT:接受匹配数据包,允许其通过防火墙

    • DROP:丢弃匹配的数据包,不发送任何响应(静默丢弃)

    • REJECT:拒绝数据包,并发送一个拒绝响应

    • LOG:记录匹配数据包到日志,然后把数据包传递给下一条规则

    • REDIRECT:将数据包重定向本机的另一个端口。通常用于将流量重定向到本地的代理服务

    • NOTRACK:不跟踪数据包,用于减少连接跟踪表的负担

    • DNAT:目标地址转换,用于端口转发、负载均衡

    • SNAT:源地址转换,适合静态 IP

    • MASQUERADE:对匹配的数据包进行源地址伪装(NAT)。也是源地址转换,可以理解为 SNAT 的一种特殊形式,适用于动态 IP

SNAT 和 MASQUERADE 场景介绍:

SNAT 和 MASQUERADE 一般用于多网络接口和内网转发,比如服务器 A 有两个网络接口:

  • eth0:连接公网,IP 为 203.x.113.45

  • eth1:连接私有网络,IP 为 192.168.1.1

服务器 A 可以执行 SNAT 命令使得内网可以通过 eth0 访问外部网络。

内网比如机器 B(192.168.1.100)设置网关为服务器 A 的内网 IP(192.168.1.1),请求发送给网关后就会通过 eth0 发送出去。

四、删除规则

# 1、获取规则编号
iptables -L -nv --line-numbers

# 1.1 通过规则号删除
iptables -D IN_public_allow 规则编号

# 2、通过规则内容删除
# 用 SQL 类比解释: delete from INPUT where source = '192.168.1.100' AND action = 'DROP';
iptables -D INPUT -s 192.168.1.100 -j DROP
  • -D:--delete,删除

五、保存规则

上面添加、修改没有保存,重启系统后配置会重置。可使用以下两种方法保存:

1、使用 iptables-services 服务

阿里云 CentOS7 默认未安装,需要安装才能使用:

# 1. 安装
yum install -y iptables-services

# 2. 保存当前规则到 /etc/sysconfig/iptables
service iptables save

# 3. 启用开机自启
systemctl enable iptables

# 4. 可选:关闭 firewalld 避免冲突
systemctl stop firewalld
systemctl disable firewalld

2、使用iptables-save 保存以及 iptables-restore恢复

可配置 systemd 服务实现开机时自动执行恢复命令。

# 保存(位置可自定义)
iptables-save > /etc/iptables.rules

# 恢复/替换(清空再加载)
iptables-restore < /etc/iptables.rules

# 追加(不清空,只添加新规则)
iptables-restore -n < /etc/iptables.rules

# 测试(只检查语法,不实际加载。-T,--test)
iptables-restore -T < /etc/iptables.rules

六、使用场景

1、DNAT 端口转发

服务器 A 配置转发,把 10058 端口的请求转发到服务器 B (172 是 B 的内网 IP)。

服务器 B 启用 10058 端口的服务,服务器 A 单纯做转发不用启服务。

最终效果:请求服务器 A,实际提供服务的是服务器 B,实现了反向代理。

# 1、开启转发
grep -q "net.ipv4.ip_forward" /etc/sysctl.conf || echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sed -i 's/^#*net.ipv4.ip_forward.*/net.ipv4.ip_forward = 1/' /etc/sysctl.conf
sysctl -p   # 立即生效

# 2、放行转发
iptables -I FORWARD -p tcp -s 172.18.141.171 -j ACCEPT

# 3、NAT
iptables -t nat -A PREROUTING -p tcp --dport 10058 -j DNAT --to-destination 172.18.141.171
iptables -t nat -A POSTROUTING -p tcp -d 172.18.141.171 --dport 10058 -j MASQUERADE

# 4. 验证(服务器 A、B 都放行 10058 端口)
# 从第三台机器 telnet A_IP 10058

数据包变化:

原始请求:
  源IP: 客户端IP
  目标IP: 服务器A公网IP:10058

经过服务器A DNAT后:
  源IP: 客户端IP(不变)
  目标IP: 172.18.141.171:10058(已修改)

经过服务器A MASQUERADE后(返回时):
  源IP: 服务器A公网IP(伪装)
  目标IP: 客户端IP

2、数据包流向图

(1)收到外部请求

                     ┌─────────────────────────────────────────────────────────────┐
                     │           网络数据包到达网卡(外部请求)                    │
                     │   (来自互联网WAN口 或 来自内网其他机器LAN口)              │
                     └─────────────────────────────────────────────────────────────┘
                                       │
                                       ▼
                              ┌─────────────────┐
                              │   PREROUTING    │  ← 端口映射(DNAT)在这里修改目标IP
                              │   (nat表)       │  (典型场景:公网IP → 内网服务器)
                              └─────────────────┘
                                       │
                                       ▼
                              路由决策:这个包是发给谁的?
                                       │
                    ┌──────────────────┴──────────────────┐
                    │                                      │
                    ▼                                      ▼
          目标地址是本机                          目标地址不是本机
          (如路由器IP)                          (内网设备 或 外网)
                    │                                      │
                    ▼                                      ▼
            ┌─────────────┐                       ┌─────────────┐
            │   INPUT     │                       │   FORWARD   │  ← 转发流量都走这里
            │ (filter表)  │                       │ (filter表)  │     不管是去内网还是外网
            └─────────────┘                       └─────────────┘
                    │                                      │
                    ▼                                      ▼
            交给本机进程处理                      ┌─────────────┐
            (如SSH、Web服务)                   │  POSTROUTING│
                                                │  (nat表)    │  ← SNAT在这里改源IP
                                                └─────────────┘
                                                       │
                                                       ▼
                                              ┌─────────────────┐
                                              │   发出网卡接口    │
                                              │ (WAN口 或 LAN口)│
                                              └─────────────────┘

(2)本机请求

         ┌─────────────────────┐
         │  本机进程发起请求   │  ← 比如路由器上执行 ping、curl、ntpdate
         │  (如 ping 百度)   │
         └─────────────────────┘
                    │
                    ▼
            ┌─────────────┐
            │   OUTPUT    │  ← ⭐ 只处理本机自己产生的包
            │ (filter表)  │
            └─────────────┘
                    │
                    ▼
            ┌─────────────┐
            │  POSTROUTING│
            │  (nat表)    │
            └─────────────┘
                    │
                    ▼
              发出到外网


评论