后浪笔记一零二四

基于 netfilter 的技术

https://git.netfilter.org/

参考网址: https://en.wikipedia.org/wiki/Iptables

用于匹配packets的规则称为链(chain) 对匹配的packets执行的动作称为目标(target)

iptables-save的输出:

:PREROUTING ACCEPT [225:64427]
方括号左边的是数据包的个数
方括号右边的是数据包的byte数

1. iptables

1.1 iptables的原理

iptables 只是一个操作 Linux 内核 Netfilter 子系统的“界面”。 顾名思义,Netfilter 子系统的作用,就是 Linux 内核里挡在“网卡”和“用户态进程”之间的一道“防火墙”。 它们的关系,可以用如下的示意图来表示:

              +---------------+
              |  User Process |
 User Space   |    ^     |    |
              |    |     V    |
              +----|-----|----+
              +----|-----|----+
              |   NetFilter   |
              |    |     |    |
              |    |     |    |
Kernel Space  |    |     |    |
              |    |     |    |
              |    ^     V    |
              |   {  eth0 }   |
              +----|-----|----+

IP包在上图"一进一出"的两条路径上,有几个关键的"检查点",他们正是Netfilter设置"防火墙"的地方。 在iptables中,这些"检查点"被称为:链(Chain)。这是因为这些"检查点"对应的iptables规则,是按照 定义顺序依次进行匹配的。这些"检查点"的具体工作原理,可以用如下所示的示意图进行描述:

          Input Path            Forward Path                Output Path
  +-------------------------+----------------------------+---------------------+    用户空间方向
+-+-------------------------+----------------------------+---------------------+-+    ^
|                               上层协议栈(比如: 传输层)                           |    |
+-+------------------^------+----------------------------+-----------V---------+-+
  |                  |      |                            |           |         |
  |                  |      |                            |         (路由)      |
  |                  |      |                            |           |         |
  |                  ^      |                            |           V         |
  |               INPUT     |                            |         OUTPUT      |
  |                  ^      |                            |           |         |
  |           第一种 |      |                            |           |         |
  |                  |第二种|                            |           |         |
->|PREROUTING---->(路由)--->|FORWARD-------------------->|------POSTROUTING ---+-->
  +-------------------------+----------------------------+---------------------+
PREROUTING: raw->mangle->nat
INPUT: mangle->filter
OUTPUT: raw->mangle->nat->filter
FORWARD: mangle->filter
POSTROUTING: mangle->nat

表:目前有五个独立的表(这些表是否存在取决于内核配置选项和对应模块存在)。

  -t, --table table
      指定数据包所匹配的表。在内核配置了自动模块加载的前提下,如果该表不存在,将尝试为该表加载适当的模块。
      目前的linux内核共支持5个表:
      * filter: (默认值)
          其内置(built-in)的chain:
              INPUT: 对于发往本地套接字的数据包
              FORWARD: 用于通过box路由的数据包
              OUTPUT: 对于本地生成的数据包(用于修改路由之前本地生成的数据包)
      * nat: 当遇到创建新连接的数据包时会查询此表
          其内置的chain:
              PREROUTING: 用于在数据包进入时立即更改数据包
              OUTPUT: 
              POSTROUTING: 用于更改即将发出的数据包
              kernel 3.7之后支持IPv6 NAT
      * mangle: 此表用于专门的数据包更改
          其内置的chain:
              kernel == 2.4.17:
                  PREROUTING:
                  OUTPUT:
              kernel >= 2.4.18(额外支持的chain):
                  INPUT:
                  FORWARD:
                  POSTROUTING:
      * raw: 此表主要用于结合 NOTRACK 目标配置连接跟踪的豁免。
          它在具有更高优先级的 netfilter 挂钩(hook)上注册,因此在 ip_conntrack 或任何其他 IP 表之前被调用。
          其内置的chain: 
              PREROUTING:
              OUTPUT:
      * security: 此表用于强制访问控制 (MAC: Mandatory Access Control) 网络规则,例如由 SECMARK 和 CONNSECMARK 目标启用的规则。MAC由linux安全模块例如selinux实现。严禁使用security表,因为它使用了selinux,使用它可能会导致意料之外的事情。
          security表在filter表之后调用,允许filter表中的任意 自主访问控制(DAC: Discretionary Access Control) 规则在 MAC 规则之前生效。
          其内置的chain: 
              INPUT:
              OUTPUT:
              FORWARD:

可以看到,当一个 IP 包通过网卡进入主机之后,它就进入了 Netfilter 定义的流入路径(Input Path)里。 在这个路径中,IP 包要经过路由表路由来决定下一步的去向。而在这次路由之前,Netfilter 设置了一个名叫 PREROUTING 的“检查点”。在 Linux 内核的实现里,所谓“检查点”实际上就是内核网络协议栈代码里的 Hook(比如,在执行路由判断的代码之前,内核会先调用 PREROUTING 的 Hook)。

而在经过路由之后,IP 包的去向就分为了两种:

  • 第一种,继续在本机处理;

    这时候,IP 包将继续向上层协议栈流动。在它进入传输层之前,Netfilter 会设置一个名叫 INPUT 的“检查点”。到这里,IP 包流入路径(Input Path)结束。 接下来,这个 IP 包通过传输层进入用户空间,交给用户进程处理。而处理完成后,用户进程会通过本机发出返回的 IP 包。这时候,这个 IP 包就进入了流出路径(Output Path)。 此时,IP 包首先还是会经过主机的路由表进行路由。路由结束后,Netfilter 就会设置一个名叫 OUTPUT 的“检查点”。然后,在 OUTPUT 之后,再设置一个名叫 POSTROUTING“检查点”。

  • 第二种,被转发到其他目的地。

    这个 IP 包不会进入传输层,而是会继续在网络层流动,从而进入到转发路径(Forward Path)。在转发路径中,Netfilter 会设置一个名叫 FORWARD 的“检查点”。 而在 FORWARD“检查点”完成后,IP 包就会来到流出路径。而转发的 IP 包由于目的地已经确定,它就不会再经过路由,也自然不会经过 OUTPUT,而是会直接来到 POSTROUTING“检查点”。 所以说,POSTROUTING 的作用,其实就是上述两条路径,最终汇聚在一起的“最终检查点”。这就是为什么在流出路径结束后,Netfilter 会连着设置两个“检查点”(OUTPUT和POSTROUTING)的原因。

  • 需要注意的是,在有网桥参与的情况下,上述 Netfilter 设置“检查点”的流程,实际上也会出现在链路层(二层),并且会跟我在上面讲述的网络层(三层)的流程有交互。

这些链路层的“检查点”对应的操作界面叫作 ebtables。所以,准确地说,数据包在 Linux Netfilter 子系统里完整的流动过程,其实应该如下所示(https://en.wikipedia.org/wiki/Iptables#/media/File:Netfilter-packet-flow.svg) Netfilter-packet-flow 上图中的绿色部分,就是网络层的iptables链的工作流程,其中的每个白色的"检查点"上,还有一个绿色的"标签",比如: raw,nat,filter等等。在iptables里,这些标签叫做:表。比如,同样是 OUTPUT 这个“检查点”,filter Output 和 nat Output 在 iptables 里的语法和参数,就完全不一样,实现的功能也完全不同。

filter: 用来过滤数据包; nat: 转换包的源或目标地址或端口(分为目的地址转换DNAT,源地址转换SNAT); mangle: 给数据打标记以根据标记去操作包。

所以说,iptables 表的作用,就是在某个具体的“检查点”(比如 Output)上,按顺序执行几个不同的检查动作(比如,先执行 nat,再执行 filter)。

1.2 iptables的jump策略

iptables定义了一套链式处理的结构,在网络包传输的各个阶段可以使用不同的策略对包进行加工、传送或丢弃。 在容器虚拟化的技术中,经常会用到两种策略MASQUERADE和DNAT,用于容器和宿主机外部的网络通信。

  1. MASQUERADE iptables中的MASQUERADE,这是一个特殊的target,它会修改符合条件的数据包的源IP地址为出站接口的IP地址。SNAT需要指定IP,而MASQUERADE可以自动检测出口接口的IP。

比如某个Namespace中的网络设备地址是172.18.0.2,这个地址虽然在宿主机上可以路由到br0的网桥,但是到达宿主机外部之后, 是不知道如何路由到这个IP地址的,所以如果请求外部地址的话,需要先通过MASQUERADE策略将这个IP转换为宿主机出口网卡的IP,

如下:

1
2
3
4
5
6
7
8
9
$ # 打开IP转发
$ sysctl -w net.ipv4.conf.all.forwarding=1
# 对Namespace中发出的包添加网络地址转换
# 对来自 172.18.0.0/24 子网的数据包,如果它们是通过 enp0s3 接口发送出去的,那么在这些数据包离开主机之前,将其源IP地址伪装成 enp0s3 接口的IP地址(这里已经指定出站接口是enp0s3了)。
$ iptables -t nat -A POSTROUTING -s 172.18.0.0/24 -o enp0s3 -j MASQUERADE

# 对来自172.18.0.0/24这个子网的数据包,如果它们不是通过docker0接口发送出去的,那么在这些数据包离开主机之前,将其源IP地址伪装成出站接口的IP地址
# 其中docker0对应的网段是172.18.0.0/24
$ iptables -t nat -A POSTROUTING -s 172.18.0.0/24 ! -o docker0 -j MASQUERADE

在Namespace中请求宿主机外部地址时,将Namespace中的源地址转换成宿主机的地址作为源地址,就可以在Namespace中访问宿主机外的网络了。

  1. DNAT iptables中的DNAT策略也是做网络地址的转换,不过它是要更换目的地址,经常用于将内部网络地址的端口映射到外部去。 比如某个Namespace中,需要提供服务给宿主机之外的应用去请求,要怎么办呢?docker run -p80:80 外部应用没有办法直接路由到172.18.0.2这个地址,这时候就可以用到DNAT策略:
1
2
$ # 将宿主机上80端口的请求转发到Namespace的IP上
$ iptables -t nat -A PREROUTING -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.18.0.2:80

这样就可以把宿主机上80端口的TCP请求转发到Namespace中的地址172.18.0.2:80,从而实现外部的应用调用。

snat:出去的时候(POSTROUTING)改变源地址

dnat:进来的时候(PREROUTING)改变目的地址

1.3 CentOS通过raw表实现iptables日志输出和调试

当系统上iptables规则过多时,如果有出现丢包或者网络不通需要查看原因时,调试iptables规则就成了一个绕不过的问题。 raw表在所有iptables规则中优先级是最高的,raw表有两条链,prerouting和output,分别作为输入和输出的第一必经点,因此作为调试是最合适不过。

这里以调试两个docker容器间发送的ICMP报文为例,进行日志的采集:

1
2
3
# 在宿主机上执行
$ iptables -t raw -A OUTPUT -p icmp -j TRACE
$ iptables -t raw -A PREROUTING -p icmp -j TRACE

通过上面的设置,就可以在/var/log/messages里面看到数据包传输的日志了。

由于iptables的调试日志输出依赖于内核模块,这些内核模块并不是开机就加载的,因此我们需要手动加载

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ # centos7中
$ # 手动加载nf_log_ipv4模块
$ modprobe nf_log_ipv4
$ # 检测是否加载成功
$ sysctl net.netfilter.nf_log.2
net.netfilter.nf_log.2 = nf_log_ipv4
$ # reconfigure rsyslogd to log kernel messages (kern.*) to /var/log/messages:
$ cat /etc/rsyslog.conf | grep -e "^kern"
kern.*;*.info;mail.none;authpriv.none;cron.none  
$ systemctl restart rsyslog

清空/var/log/messages文件之后,记得重启下rsyslog

1.4 常用iptables命令

 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
26
# 查看命令
iptables -t nat -vnL POSTROUTING

# 允许指定服务去访问该端口
iptables -t mangle -I PREROUTING -i eth0 -s prometheus-server/32 -p tcp -m multiport --dports 8891,8888 -j ACCEPT
iptables -t mangle -I PREROUTING -i eth0 -p tcp -m multiport --dports 19345,9345 -m set --match-set ipset-whitelist src -j ACCEPT
# 拒绝指定端口的所有流量
iptables -t mangle -A PREROUTING -i eth0 -p tcp -m multiport --dports 8891,8888 -j DROP
# 删除规则
iptables -t mangle -D PREROUTING -i eth0 -p tcp -m multiport --dports 8891,8888 -j DROP
# 注意,DROP规则必须在ACCEPT规则的后面,否则,后面的ACCEPT规则无法被访问到

# 改变链的默认策略:设置当没有规则匹配时应该如何处理数据包
# 以下是改变默认策略的基本命令格式: iptables -t <表名> -P <链名> <目标>
# 将filter表中INPUT链的默认策略设置为DROP,可以执行如下命令:
iptables -t filter -P INPUT DROP

# iptables-save命令的解读
*mangle  (越靠近*mangle,越先被执行)
:PREROUTING ACCEPT [891:134034]
:INPUT ACCEPT [158:11247]
:FORWARD ACCEPT [665:115243]
:OUTPUT ACCEPT [138:52428]
:POSTROUTING ACCEPT [803:167671]
-A PREROUTING -i eth0 -p tcp -m multiport --dports 19345,9345 -m set --match-set ipset-whitelist src -j ACCEPT
-A PREROUTING -i eth0 -p tcp -m multiport --dports 9345,19345 -j DROP

1.5 iptables 规则的持久化

service iptables save 等同于 /usr/libexec/iptables/iptables.init save,iptables.init文件中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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
IPTABLES=iptables
IPTABLES_DATA=/etc/sysconfig/$IPTABLES
PROC_IPTABLES_NAMES=/proc/net/${IPV}_tables_names
# 省略若干
IPTABLES_SAVE_COUNTER="no"
# 省略若干

# Get active tables
NF_TABLES=$(cat "$PROC_IPTABLES_NAMES" 2>/dev/null)

# 省略若干

save() {
    # Check if iptable module is loaded
    if [ ! -e "$PROC_IPTABLES_NAMES" ]; then
        echo -n $"${IPTABLES}: Nothing to save."; warning; echo
        return 0
    fi

    # Check if firewall is configured (has tables)
    if [ -z "$NF_TABLES" ]; then
        echo -n $"${IPTABLES}: Nothing to save."; warning; echo
        return 6
    fi

    echo -n $"${IPTABLES}: Saving firewall rules to $IPTABLES_DATA: "

    OPT=
    [ "x$IPTABLES_SAVE_COUNTER" = "xyes" ] && OPT="-c"

    ret=0
    TMP_FILE=$(/bin/mktemp -q $IPTABLES_DATA.XXXXXX) \
        && chmod 600 "$TMP_FILE" \
        && $IPTABLES-save $OPT > $TMP_FILE 2>/dev/null \
        && size=$(stat -c '%s' $TMP_FILE) && [ $size -gt 0 ] \
        || ret=1
    if [ $ret -eq 0 ]; then
        if [ -e $IPTABLES_DATA ]; then
            cp -f $IPTABLES_DATA $IPTABLES_DATA.save \
                && chmod 600 $IPTABLES_DATA.save \
                && restorecon $IPTABLES_DATA.save \
                || ret=1
        fi
        if [ $ret -eq 0 ]; then
            mv -f $TMP_FILE $IPTABLES_DATA \
                && chmod 600 $IPTABLES_DATA \
                && restorecon $IPTABLES_DATA \
                || ret=1
        fi
    fi
    rm -f $TMP_FILE
    [ $ret -eq 0 ] && success || failure
    echo
    return $ret
}

restorecon的安装: yum install -y policycoreutils selinux-policy

restorecon 是 SELinux(Security-Enhanced Linux)生态系统中的一个重要命令,主要用于恢复文件或目录的安全上下文标签。正确设置这些标签对于确保 SELinux 策略的有效执行至关重要。

要启用这个持久化,需要开启iptables开机自启: systemctl enable iptables

但是,一般不推荐启用iptables的默认持久化,因为像firewalld和docker等,都会自动维护一套iptables链,这些链都不会使用iptables的默认持久化。

如果启用iptables的默认持久化,那么在执行 service iptables save命令后,会把firewalld和docker生成的iptables链也持久化到 /etc/sysconfig/iptables 文件里面,而firewalld和docker维护的那部分iptables规则是动态的,持久化到 /etc/sysconfig/iptables里面不太合适。

如果一定要启用iptables的默认持久化,那就禁用 service iptables save 命令,采用手动维护 /etc/sysconfig/iptables 的方式,避免把firewalld和docker生成的链带入到/etc/sysconfig/iptables文件里。

/etc/sysconfig/iptables文件的默认内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# sample configuration for iptables service
# you can edit this manually or use system-config-firewall(注意:system-config-firewall已经被弃用,取而代之的是 firewalld)
# please do not ask us to add additional ports/services to this default configuration
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

在这个例子中:

  • *filter 标志着 filter 表的开始。
  • :INPUT ACCEPT [0:0] 等定义了链的默认策略,这里表示如果没有任何规则匹配,那么默认接受所有流入的数据包。
  • -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT 添加了一条规则到 INPUT 链,这条规则接受所有已建立连接或相关联的数据包。
  • -A INPUT -p icmp -j ACCEPT 接受所有的 ICMP 数据包(通常用于 ping 请求)。
  • -A INPUT -i lo -j ACCEPT 接受所有通过本地回环接口(lo)的数据包。
  • -A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT 接受所有新的 TCP 连接请求到达 SSH 服务(端口 22)。
  • -A INPUT -j REJECT --reject-with icmp-host-prohibited 和 -A FORWARD -j REJECT --reject-with icmp-host-prohibited 拒绝所有其他未匹配的数据包,并发送主机禁止的消息作为回应。
  • COMMIT 表明 filter 表的规则已经结束。

1.6 iptables 表的优先级

在 iptables 中,不同表的优先级从高到低分别是:

  1. raw 表:原始表,优先级最高。此表用于进行连接跟踪之前的处理,例如对数据包进行标记
  2. mangle 表:数据修改表,优先级次高。此表用于对数据包进行修改,例如修改TTL(Time To Live)、修改数据包的标记等
  3. nat 表:网络地址转换表,优先级较高。此表用于网络地址转换,例如端口转发、SNAT和DNAT等
  4. filter 表: 过滤表,优先级较低。此表用于过滤数据包,例如允许或阻止特定的数据包通过
  5. security表: 安全表,优先级最低。此表用于SELinux安全策略的处理,仅在SELinux启用时才使用

当一个网络数据包到达时,iptables 会按照这个顺序依次匹配每个表,找到第一个匹配的规则,并根据规则的动作进行处理。如果没有匹配任何规则,则默认执行 ACCEPT 操作。

1.7 经典iptables防火墙的写法

-A INPUT -j SUPERWHITE
-A INPUT -j SUPERBLACK
-A INPUT -j SPORD
...
-A SPORD -i lo -j ACCEPT
-A SPORD -m state --state RELATED,ESTABLISHED,UNTRACKED -j ACCEPT
-A SPORD -p tcp -m multiport --dports 9090 -j SPORD_tcp_9090
-A SPORD -p icmp -j ACCEPT
-A SPORD -j DROP
-A SPORD_tcp_9090 -s 172.31.0.11/32 -j ACCEPT
-A SPORD_tcp_9090 -j DROP
-A SUPERWHITE -s 172.0.0.1/21 - ACCEPT
-A SUPERWHITE -s 10.61.191.3/32 -j ACCEPT

1.8 -s-d和-i-o的区别

-s(源地址)与-d(目标地址):

  • 作用:匹配数据包的IP地址或网段。
  • 适用范围:可用于所有链(如INPUT、OUTPUT、FORWARD、PREROUTING、POSTROUTING)

-i(输入接口)与-o(输出接口):

  • 作用:匹配数据包流经的网络接口(如eth0、docker0)
  • 适用范围:
    • -i:匹配数据包进入的网卡(仅用于INPUT、FORWARD、PREROUTING链)
    • -o:匹配数据包离开的网卡(仅用于OUTPUT、FORWARD、POSTROUTING链)

1.9 JUMP到自定义链,自定义链跑完后会返回到原链继续匹配后续规则么?

JUMP到自定义链:若未匹配终止型动作,会返回到原链继续匹配后续规则

终止型动作:

  • ACCEPT/DROP/REJECT
  • MASQUERADE/SNAT/DNAT

2. iptables升级

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$ yum install gcc make libnftnl-devel libmnl-devel autoconf automake libtool bison flex  \
libnetfilter_conntrack-devel libnetfilter_queue-devel libpcap-devel bzip2

$ wget wget https://www.netfilter.org/projects/iptables/files/iptables-1.6.2.tar.bz2
tar -xvf iptables-1.6.2.tar.bz2

$ cd iptables-1.6.2

$ ./autogen.sh
$ ./configure

$ make -j4 && make install

# 覆盖
$ cd /usr/local/sbin && cp iptables /sbin && cp iptables-restore /sbin/ && cp iptables-save /sbin/

# 重启kubelet和删除本地的kube-proxy的Pod

3. nftables

4. conntrack-tools


本文发表于 0001-01-01,最后修改于 0001-01-01。

本站永久域名「 jiavvc.top 」,也可搜索「 后浪笔记一零二四 」找到我。


上一篇 « 下一篇 »

赞赏支持

请我吃鸡腿 =^_^=

i ysf

云闪付

i wechat

微信

推荐阅读

Big Image