iptables

image-20240612195205802

iptables 是 Linux 内核空间的 netfilter 的一个用户空间应用程序。它允许系统管理员通过定义规则来配置 Linux 内核的 IPv4 数据包过滤处理行为。iptables 在 Linux 系统中扮演防火墙的角色,用于控制进出系统的网络数据流量。

工作原理 iptables 通过在内核的 netfilter 框架中设置规则,来控制进出数据流量。数据包在经过不同的netfilter钩子时,会根据预定义的规则进行检查和处理。

规则表(Table)和链(Chain) iptables 使用表和链的概念来组织规则。表代表不同的数据包处理方式,比如filter表处理过滤、nat表处理网络地址转换等。每个表包含多条链,链则是规则的有序集合。

规则和匹配机制 iptables 的规则可以匹配基于多种条件,例如源/目标IP、协议类型、端口号等。每条规则对应一个预定义的动作,如ACCEPT(接受)、DROP(丢弃)、REJECT(拒绝)等。

防火墙功能 iptables 通过构建规则,可以实现典型的防火墙功能,如数据包过滤、网络地址转换(NAT)、端口转发等。

配置方式 iptables 主要通过命令行工具进行配置,如iptables命令用于编辑规则、iptables-save保存规则等。也有一些前端工具如ufw、firewalld等提供更友好的界面配置。

处理过程 数据包到达后会按顺序遍历链中的规则,第一条匹配的规则会生效并决定是ACCEPT还是DROP等动作。如果没有规则匹配,则使用链的默认策略(policy)。

我们常见的ufw、firewalld都是对 iptables 的封装,底层调用的是 iptables。

netfilter是Linux操作系统核心层内部的一个数据包处理模块,它具有如下功能:

  • 网络地址转换(Network Address Translate)
  • 数据包内容修改
  • 以及数据包过滤的防火墙功能

语法

1
2
3
4
5
6
7
8
iptables -t 表名  -nL|-S  [链名]                          # 查看规则
iptables -t 表名  -F [链名]                               # 清空规则
iptables -t 表名  -A  链名  匹配条件   -j  动作             # 追加规则
iptables -t 表名  -I  链名 [数字]  匹配条件   -j  动作       # 插入规则,默认插入到第一条
iptables -t 表名  -D  链名 数字N                           # 删除指定链的第N条规则
iptables -t 表名  -D  链名  匹配条件  -j  动作              # 删除符合条件的规则
iptables -t 表名  -R  链名 数字  匹配条件   -j  动作         # 替换规则
iptables -t 表名  -P  链名 动作                            # 设置默认策略

操作选项: -L 显示所指定链所有规则,如果没有指定链,所有链将被显示, 前面-n表示以数字的形式显示,不解析 -F 清空所指定链所有规则,如果没有指定链,所有链将被清空 -S 详细打印出指定表中所有的规则 -D 删除链中某条规则,可以接序号,也可以接具体的规则动作 -P 设置指定链的默认策略 -A 向指定链中追加一条规则 -I 向指定链中插入一条规则,默认插入到第一条, 链名后接序号表示插入到第几条 -R 替换所指定链中的一条规则,链名后接序号 -N 自定义链 -X 删除自定义链

五链⛓

image-20240612200303858

  • PREROUTING

    数据包刚进入网络层,路由之前

  • INPUT

    路由判断,流入用户空间

  • OUTPUT

    用户空间发出,后接入路由判断出口的网络接口

  • FORWARD

    路由判断不进入用户空间,只进行转发

  • POSTROUTING

    数据包通过网络接口出去

四表

iptables的四个表iptable_filteriptable_mangleiptable_natiptable_raw,默认表是filter(没有指定表的时候就是filter表)。

  • filter 表

    用来对数据包进行过滤,具体的规则要求决定如何处理一个数据包。

    对应的内核模块为:iptable_filter,其表内包括三个链:inputforwardoutput;

  • nat 表

    nat 全称:network address translation 网络地址转换,主要用来修改数据包的 IP 地址、端口号信息。

    对应的内核模块为:iptable_nat,其表内包括三个链:preroutingpostroutingoutput;

  • mangle 表

    主要用来修改数据包的服务类型,生存周期,为数据包设置标记,实现流量整形、策略路由等。

    对应的内核模块为:iptable_mangle,其表内包括五个链:preroutingpostroutinginputoutputforward;

  • raw 表

    主要用来决定是否对数据包进行状态跟踪。

    对应的内核模块为:iptable_raw,其表内包括两个链:outputprerouting;

四表五链的关系

filter 过滤规则

filter负责过滤功能,比如允许哪些IP地址访问,拒绝哪些IP地址访问,允许访问哪些端口,禁止访问哪些端口,filter表会根据我们定义的规则进行过滤,filter表是我们最常用到的表。

查看规则

1
2
3
4
iptables -t filter -L
iptables -t filter -nvL
iptables -t filter -nvL --line-numbers
iptables -t filter -S

详细信息

只查看filter表中INPUT链的规则

1
2
3
4
5
[root@localhost ~]# iptables -nvL INPUT --line-numbers
Chain INPUT (policy ACCEPT 135 packets, 9536 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 DROP       all  --  *      *       10.10.10.49          0.0.0.0/0
2        4   336 DROP       all  --  *      *       10.10.10.50          0.0.0.0/0
  • 头含义:

    1
    2
    3
    
    policy:表示当前链的默认策略,policy ACCEPT表示上图中INPUT的链的默认动作为ACCEPT
    packets:表示当前链(上例为INPUT链)默认策略匹配到的包的数量,0 packets表示默认策略匹配到0个包。
    bytes:表示当前链默认策略匹配到的所有包的大小总和。
    

    我们可以把packets与bytes称作”计数器”,上图中的计数器记录了默认策略匹配到的报文数量与总大小,”计数器”只会在使用-v选项时,才会显示出来

  • 字段含义

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    pkts:对应规则匹配到的报文的个数。
    bytes:对应匹配到的报文包的大小总和。
    target:规则对应的target,往往表示规则对应的"动作",即规则匹配成功后需要采取的措施。
    prot:表示规则对应的协议,是否只针对某些协议应用此规则。
    opt:表示规则对应的选项。
    in:表示数据包由哪个接口(网卡)流入,我们可以设置通过哪块网卡流入的报文需要匹配当前规则。
    out:表示数据包由哪个接口(网卡)流出,我们可以设置通过哪块网卡流出的报文需要匹配当前规则。
    source:表示规则对应的源头地址,可以是一个IP,也可以是一个网段。
    destination:表示规则对应的目标地址。可以是一个IP,也可以是一个网段。
    

增加规则

可以使用iptables -F INPUT命令清空filter表INPUT链中的规则

  • 增加

    1
    2
    
    iptables -t 表名  -A  链名  匹配条件   -j  动作         # 追加规则
    iptables -t 表名  -I  链名 [数字] 匹配条件 -j  动作   # 插入规则,默认插入到第一条
    
    1
    
    iptables -t filter -I INPUT -s 123.117.179.97 -j DROP
    
  • 规则的顺序

    如果报文已经被前面的规则匹配到,iptables则会对报文执行对应的动作,即使后面的规则也能匹配到当前报文,很有可能也没有机会再对报文执行相应的动作。

删除规则

  1. 根据规则编号去删除规则
  2. 根据具体的匹配条件与动作删除规则
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 添加两条规则
iptables -t filter -A INPUT -s 10.10.10.49 -j DROP
iptables -t filter -A INPUT -s 10.10.10.50 -j DROP

# 查看
iptables --line -nvL INPUT
Chain INPUT (policy ACCEPT 108 packets, 7620 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 DROP       all  --  *      *       10.10.10.49          0.0.0.0/0
2        0     0 DROP       all  --  *      *       10.10.10.50          0.0.0.0/0

# 两种删除方式
iptables -D INPUT 1
iptables -D INPUT -s 10.10.10.50 -j DROP
  1. 删除所有

    1
    
    iptables -t filter -F
    

    -F选项为flush之意,即冲刷指定的链,即删除指定链中的所有规则,慎用。

保存规则

在默认的情况下,我们对”防火墙”所做出的修改都是”临时的”,换句话说就是,当重启iptables服务或者重启服务器以后,我们平常添加的规则或者对规则所做出的修改都将消失,为了防止这种情况的发生,我们需要将规则”保存”。

centos7中,使用firewall替代了原来的iptables service

1
2
3
4
5
6
7
8
firewall-cmd --zone=public --add-port=3000/tcp --permanent
firewall-cmd --reload

# 也可以安装 iptables-service
yum install -y iptables-services
systemctl disable firewalld
systemctl enable iptables
service iptables save

匹配

匹配条件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[!] -p  协议    tcp   udp  icmp      # **
[!] -s  源ip地址,三层封包中的源地址   # ***
    -d  目标ip地址           
    -i  网卡名称                       # 从哪个网卡进来的 **
    -o  网卡名称                       # 从哪个网卡出去的 **
    -m  扩展匹配
        tcp  
            --sport 源端口            # 可以使用80:90表示匹配一段范围内所有的端口
            --dport 目标端口          # 可以使用80:90表示匹配一段范围内所有的端口  ***
            --tcp-flags  mark标记
        udp
            --sport 源端口        
            --dport 目标端口
        icmp
            --icmp-type              # 指定匹配ICMP类型    0 应答   8 请求
        mac
            --mac-source             # 匹配源MAC地址
        multiport
            --sports                 # 匹配多个源端口  
            --dports                 # 匹配多个目标端口   22,69,123,80:90
            --ports                  # 匹配多个端口
        state
            --state                  # INVALID  ESTABLISHED  NEW  RELATED
        mark
            --mark                   # 匹配防火墙标记

动作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
filter表:
    REJECT          # 拒绝
    ACCEPT          # 允许
    DROP            # 丢弃

nat表
    DNAT            # 目标地址转换,一般用于对外发布服务         
    SNAT            # 源地址转换,一般用于实现内网机器上网      --- 静态
    MASQUERADE      # 地址伪装   ---动态的 NAT
    REDIRECT        # 重定向     ---仅修改端口

匹配方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 单个匹配
iptables -I INPUT -s 1.1.1.2 -j DROP

# 多个匹配
iptables -I INPUT -s 1.1.1.3,1.1.1.4 -j DROP

# 网段匹配
iptables -I INPUT -s 1.1.1.5/23 -j DROP

# 取反匹配
iptables -I INPUT ! -s 1.1.1.6 -j ACCEPT

匹配IP地址

1
2
# 只丢弃从 1.1.1.7 发往 1.1.1.8 这个IP的报文
iptables -I INPUT -s 1.1.1.7 -d 1.1.1.8 -j DROP

匹配协议类型

1
iptables -I INPUT -s 1.1.1.2 -p tcp -j DROP

centos7中,-p选项支持如下协议类型

1
tcp, udp, udplite, icmp, icmpv6,esp, ah, sctp, mh

当不使用-p指定协议类型时,默认表示所有类型的协议都会被匹配到

匹配网卡接口

入口:

使用-i选项,指定网卡名称, 表示丢弃由eth0网卡流入的icmp类型的报文。

1
iptables -I INPUT -s 223.70.253.1 -i eth0 -p icmp -j DROP

-i选项是用于匹配报文流入的网卡的,也就是说,从本机发出的报文是不可能会使用到-i选项的,因为这些由本机发出的报文压根不是从网卡流入的,而是要通过网卡发出的,从这个角度考虑,-i选项的使用是有限制的。

所以-i选项只能用于上图中的PREROUTING链、INPUT链、FORWARD链,这是-i选项的特殊性。

出口:

当主机有多块网卡时,可以使用-o选项,匹配报文将由哪块网卡流出,没错,-o选项与-i选项是相对的,-i选项用于匹配报文从哪个网卡流入,-o选项用于匹配报文将从哪个网卡流出。

-o选项只能用于FORWARD链、OUTPUT链、POSTROUTING链。

匹配端口

1
2
3
iptables -I INPUT -s 1.1.1.2 -p tcp -m tcp --dport 22 -j DROP

iptables -I INPUT -s 1.1.1.2 -p tcp -m multiport --dports 22,36,80 -j DROP

SNAT 实验

DNAT(Destination Network Address Translation,目的地址转换) 通常被叫做目的映射。而SNAT(Source Network Address Translation,源地址转换)通常被叫做源映射。

image-20240613145236080

配置三台 linux 机器

  1. 一台名为 client

    ip:10.10.10.12

    删除原网关: route del default gw 10.10.10.2

    将网关设为:route add default gw 10.10.10.11

  2. 一台名为 iptables

    两张网卡(10.10.10.11(对内) 和 180.15.16.17(对外))

    开启转发功能:/etc/sysctl.conf 添加 net.ipv4.ip_forward = 1

  3. 一台名为 server

    ip:180.15.100.100

    安装并开启:httpd

关闭所有机器的 firewalld

在iptables 机器中设置规则:

1
2
3
4
5
6
7
# 允许经过 180.15.16.17 的 ens33 网卡,访问 server 机器的 80 端口
iptables -t nat -A POSTROUTING -o ens33 -p tcp --dport 80 -j SNAT --to 180.15.16.17

# iptables -t nat -nvL POSTROUTING
Chain POSTROUTING (policy ACCEPT 204 packets, 15404 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    1    60 SNAT       tcp  --  *      ens33   0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:180.15.16.17

现在可以在 client 机器上使用curl 180.15.100.100访问到内容

上面的案例公网 ip 是180.15.16.17,但是实际上有些情况公网 ip 会变更,我们可以使用动态的 NAT,自动根据公网 ip 转发:

1
2
3
4
5
iptables -t nat -A POSTROUTING -s 10.10.10.0/24 -o ens33 -j MASQUERADE
iptables -t nat -nvL POSTROUTING
Chain POSTROUTING (policy ACCEPT 2 packets, 152 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 MASQUERADE  all  --  *      ens33   10.10.10.0/24        0.0.0.0/0  

DNAT 实验

image-20240613162925910

1
2
3
4
5
iptables -t nat -A PREROUTING -i ens33 -p tcp --dport 80 -j DNAT --to 10.10.10.12
iptables -t nat -nvL PREROUTING
Chain PREROUTING (policy ACCEPT 1 packets, 76 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DNAT       tcp  --  ens33  *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:10.10.10.12

在 10.10.10.12 的服务器上的 80 端口开启一个服务

cient 访问 180.15.16.17 的 80 端口就能通过端口映射到服务器上的80端口上的服务。

Filter 实验

在实验二(DNAT)的基础上:

  1. 将web服务器端口改为8080,要求客户端通过80端口仍能正常访问;

    1
    
    iptables -t nat -A PREROUTING -i ens33 -p tcp --dport 80 -j DNAT --to 10.10.10.12:8080
    
  2. 防火墙的22号端口仅对管理机开放

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    # 先开放管理机
    iptables -A INPUT -s 10.10.10.1 -p tcp -m tcp --dport 22 -j ACCEPT
    # 再拒绝其他机器
    iptables -A INPUT -j DROP
    # 把转发先关掉
    iptables -A FORWARD -j DROP
    
    # 只开启 22 端口 允许所有源端口为22(SSH)的TCP流量进入。
    iptables -I INPUT 2 -p tcp --sport 22 -j ACCEPT
    # 或者 使用下面方法
    iptables -I INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT
    
  3. 对外仅开放80端口(开放http业务)

    1
    2
    3
    
    # 由于我们把转发关闭了,所以要允许 目的端口和源端口为 8080 的 tcp 包通过
    iptables -I FORWARD -p tcp -m tcp --sport 8080 -j ACCEPT
    iptables -I FORWARD -p tcp -m tcp --dport 8080 -j ACCEPT
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    [root@iptables ~]# iptables -S
    -P INPUT ACCEPT
    -P FORWARD ACCEPT
    -P OUTPUT ACCEPT
    -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT
    -A INPUT -s 10.10.10.1/32 -p tcp -m tcp --dport 22 -j ACCEPT
    -A INPUT -j DROP
    -A FORWARD -p tcp -m tcp --sport 8080 -j ACCEPT
    -A FORWARD -p tcp -m tcp --dport 8080 -j ACCEPT
    -A FORWARD -j DROP
    

    filter

将本机的 80 端口转发到 8080 端口:REDIRECT

1
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8080

ftp服务

image-20240616121140968

1
2
3
4
[root@ftp-server ~]# vim /etc/vsftpd/vsftpd.conf
pasv_min_port=7000
pasv_max_port=7999
pasv_address=180.15.16.17

查看 filer 表,应该修改成这样:

1
2
3
4
5
6
7
8
9
[root@iptables ~]# iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT
-A INPUT -s 10.10.10.1/32 -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -j DROP
-A FORWARD -p tcp -m tcp --dport 8080 -j ACCEPT
-A FORWARD -p tcp -m state --state ESTABLISHED -j ACCEPT

修改 nat 表:

1
$ iptables -t nat -A PREROUTING -i ens33 -p tcp -m multiport --dport 21,7000:7999 -j DNAT --to 10.10.10.12

可以在 client 机器上安装 lftp 验证

主动模式:

1
$ iptables -t nat -A POSTROUTING -o ens33 -p tcp --sport 20 -j MASQUERADE
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[root@iptables ~]# iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT
-A INPUT -s 10.10.10.1/32 -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -j DROP
-A FORWARD -p tcp -m tcp --dport 8080 -j ACCEPT
-A FORWARD -p tcp -m state --state ESTABLISHED -j ACCEPT
-A FORWARD -j DROP

$ iptables -I FORWARD 3 -p tcp -m multiport --dports 21,7000:7999 -j ACCEPT

[root@iptables ~]# iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT
-A INPUT -s 10.10.10.1/32 -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -j DROP
-A FORWARD -p tcp -m tcp --dport 8080 -j ACCEPT
-A FORWARD -p tcp -m state --state ESTABLISHED -j ACCEPT
-A FORWARD -p tcp -m multiport --dports 21,7000:7999 -j ACCEPT
-A FORWARD -j DROP
1
2
# 放行源端口为 20 的
$ [root@iptables ~]# iptables -I FORWARD 3 -p tcp --sport 20 -j ACCEPT

总结:

image-20240616121300744

配置防火墙的注意事项:

堵: 默认为放行,设置策略禁止需要禁止的流量

疏: 默认为禁止,设置策略放行需要放行的流量

堵不如疏

  1. 注意策略顺序, 防火墙的匹配是从上到下,匹配到即执行相应的动作
  2. 设置默认禁止策略先设置好放行管理机策略,再把默认策略放在最后一条,不建议用-P设置默认禁止
  3. 同一条策略里不同类型的多个条件之间是与的关系,同一个条件的多个参数之间是或的关系
  4. 将匹配较多的策略放在上面,以避免额外的系统开销

如果希望开机启动,安装iptables-services 保存iptables策略: iptables-save > /etc/sysconfig/iptables 恢复iptables策略: iptables-restore /etc/sysconfig/iptables