如何在 Linux 机器上使用不同的 VLAN 标签来标记 IPv4 和 IPv6 数据包?

如何在 Linux 机器上使用不同的 VLAN 标签来标记 IPv4 和 IPv6 数据包?

我想用不同的 VLAN 标签标记来自启用双栈的连接传入的 IPv4 和 IPv6 数据包,例如 IPv4 数据包应进入 VLAN4,IPv6 数据包应进入 VLAN6。更一般地说,我想将混合了 IPv4 和 IPv6 数据包的双栈 IP 流拆分为两个干净的单栈网络,这样您就不会在 IPv6 网络上找到任何 IPv4 数据包,反之亦然。我需要这个来测试和支持仅 IPv6 的网络。当然,我仍然需要 IPv4 数据。它不能简单地被丢弃。

                          Linux Box
                       Debian Bullseye
       untagged         ┏━━━━━━━━━━━┓         tagged (trunk)
════════════════════════┫eth0  vlan4┣═╦══════════════════════
     IPv4 and IPv6      ┃      vlan6┣═╝eth1  IPv4 with VLAN4 tag
      dual stack        ┗━━━━━━━━━━━┛        IPv6 with VLAN6 tag

我查看了 Linux 桥接器,nftables但找不到解决方案。我该如何实现这种选择性标记?

答案1

虽然您的答案对您来说似乎有用,但它似乎过于复杂。但我怀疑它是否能满足您的要求,因为给定的输出中没有任何 IPv4 地址(lo 除外)。

创建 2 个标记接口(例如名为 vlan4 和 vlan6),为它们分配 IPv4 和 IPv6 地址 + 网关,并使用 sysctl 禁用 IPv4 的 SLAAC 就足够了。

除了需要在 eth0 和 eth1 之间启用流动之外,不需要桥接,也不需要处理 nftables。

答案2

我找到了一个解决方案。因为我想操作 VLAN,所以我必须使用网桥。VLAN 在 OSI 第 2 层上工作,网桥是可以处理第 2 层协议的设备。所以我首先在物理接口上添加了两个 VLAN 接口eth1.然后添加所有接口eth0VLAN4VLAN6到桥上。剩下的工作由nftables

IPv4 和 IPv6 在第 3 层定义,在第 2 层上没有不同含义。因此nftables可以将它们视为具有不同“标记”的数据包,即 IP 报头中的协议类型。幸运的是nftables可以使用 来选择它们meta protocol {}。它将传入的未标记的 IPv4 和 IPv6 数据包定向到相应的 VLAN 接口。标记由接口像往常一样自动完成。我使用systemd-networkd以下是详细配置。

首先创建网络设备vlan4、vlan6和网桥br0:

~$ sudo -Es
~# cat > /etc/systemd/network/01-vlan4.netdev <<EOF
[NetDev]
Name=vlan4
Kind=vlan
[VLAN]
Id=4
EOF

~# cat > /etc/systemd/network/02-vlan6.netdev <<EOF
[NetDev]
Name=vlan6
Kind=vlan
[VLAN]
Id=6
EOF

~# cat > /etc/systemd/network/03-br0.netdev <<EOF
[NetDev]
Name=br0
Kind=bridge
[Bridge]
DefaultPVID=6
VLANProtocol=802.1q
STP=no
EOF

然后将接口连接到 eth1 和网桥:

~# cat > /etc/systemd/network/12-eth1_attach-vlans.network <<EOF
[Match]
Name=eth1
[Network]
LLMNR=no
LinkLocalAddressing=no
VLAN=vlan4
VLAN=vlan6
EOF

~# cat > /etc/systemd/network/16-ifs_add_to_br0.network <<EOF
[Match]
Name=eth0 vlan4 vlan6
[Network]
Bridge=br0
LLMNR=no
LinkLocalAddressing=no
EOF

现在只需提起桥梁:

~# cat > /etc/systemd/network/20-br0-up.network <<EOF
[Match]
Name=br0
[Network]
LLMNR=no
MulticastDNS=yes
EOF

重启后你将得到:

~$ ip -brief address
lo               UNKNOWN        127.0.0.1/8 ::1/128
eth0             UP
br0              UP             2003:d5:2721:900:9012:fdff:fef0:ea7f/64 fe80::9012:fdff:fef0:ea7f/64
vlan6@eth1       UP
vlan4@eth1       UP
eth1             UP

# these are the slave interfaces of the bridge
~$ sudo bridge link show
4: vlan6@eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 4
5: vlan4@eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 4
6: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 4

还值得检查一下resolvectl。现在我们必须执行最后一步,并使用nftables使用这些规则:

~$ cat /etc/nftables.conf
#!/usr/sbin/nft -f

flush ruleset

table bridge filter {
    chain forward {
        type filter hook forward priority 0; policy accept;
        meta protocol { ip6 } iifname "vlan4" drop
        meta protocol { ip6 } oifname "vlan4" drop
        meta protocol { ip6 } iifname "vlan6" accept
        meta protocol { ip6 } oifname "vlan6" accept
        iifname "vlan6" drop
        oifname "vlan6" drop
    }

    chain output {
        type filter hook output priority 0; policy drop;
        meta protocol { ip6 } iifname "vlan6" accept
        meta protocol { ip6 } oifname "vlan6" accept
    }
}

在正向链中,这将丢弃所有往返于接口的 IPv6VLAN4并且只允许在界面上VLAN6. 所有其他内容都放在界面上VLAN6,但根据链上接口接受的默认策略VLAN4.这确保所有旧的东西,如ARP和其他广播也进入接口VLAN4

输出链只是为了避免网桥本身将数据包发送到错误的 VLAN。在我的配置中,它仅使用 IPv6(单栈),因此链默认策略将丢弃除 IPv6 之外的所有内容VLAN6

相关内容