使用 iptables 在 VLAN 之间转发流量

Air*_*ett 5 networking linux routing iptables vlan

我们的网络上有以下 4 个 VLAN,通过 DHCP 连接到 Ubuntu Linux 机器。这个 Linux 也应该充当 L3 路由器。

VLAN 10  on interface eth1.10  with subnet 10.10.10.0/24
VLAN 20  on interface eth1.20  with subnet 10.10.20.0/24
VLAN 50  on interface eth1.50  with subnet 10.10.50.0/24
VLAN 100 on interface eth1.100 with subnet 10.10.100.0/24
Run Code Online (Sandbox Code Playgroud)

这里是/etc/network/interfaces

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
        address 192.168.10.169
        netmask 255.255.255.0
        gateway 192.168.10.1

auto eth1
iface eth1 inet static
        address 10.10.0.1
        network 10.10.0.0
        netmask 255.255.255.0
        broadcast 10.10.0.255

auto eth1.100
iface eth1.100 inet static
        address 10.10.100.1
        network 10.10.100.0
        netmask 255.255.255.0
        broadcast 10.10.100.255

auto eth1.10
iface eth1.10 inet static
        address 10.10.10.1
        network 10.10.10.0
        netmask 255.255.255.0
        broadcast 10.10.10.255

auto eth1.20
iface eth1.20 inet static
        address 10.10.20.1
        network 10.10.20.0
        netmask 255.255.255.0
        broadcast 10.10.20.255

auto eth1.50
iface eth1.50 inet static
        address 10.10.50.1
        network 10.10.50.0
        netmask 255.255.255.0
        broadcast 10.10.50.255
Run Code Online (Sandbox Code Playgroud)

现在,来自所有 VLAN 的所有客户端都应该能够通过接口连接到公共互联网eth0。该部分实际上适用于 iptables 规则-A POSTROUTING -o eth0 -j MASQUERADE。DHCP 服务器也正在工作。

但是,由于 VLAN 100 将成为管理计算机的网络,因此 VLAN 100 中的客户端应该能够访问 VLAN 10、20 和 50 中的所有其他计算机。并且VLAN 10、20 和 50 中的客户端只能访问能够访问自己 VLAN 内的计算机。

到目前为止,我已经尝试了以下 iptables 规则以及MASQUERADE

-A FORWARD -i eth1.100 -o eth1.10 -j ACCEPT
-A FORWARD -i eth1.100 -o eth1.20 -j ACCEPT
-A FORWARD -i eth1.100 -o eth1.50 -j ACCEPT
-A FORWARD -i eth1.10 -o eth1.100 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i eth1.20 -o eth1.100 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i eth1.50 -o eth1.100 -m state --state RELATED,ESTABLISHED -j ACCEPT
Run Code Online (Sandbox Code Playgroud)

我尝试从 IP 地址为 10.10.100.101 的 PC ping 通 IP 地址为 10.10.20.100 的 PC,但没有成功。我也无法从 100 子网 ping 通 10.10.50.101。

并且有一个奇怪的副作用:VLAN 20 偶然(我不知道为什么)表现得像 100 应该的那样。从那里我可以 ping 通 VLAN 10 和 100 中的 PC,但这最终是不可能的。

我在内核中启用了 IPv4 转发,并且外部互联网按预期工作。

这是完整的输出iptables-save

# Generated by iptables-save v1.6.0 on Thu May 26 09:28:59 2016
*filter
:INPUT ACCEPT [7375:724156]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [3695:415474]
-A FORWARD -i eth1.100 -o eth1.10 -j ACCEPT
-A FORWARD -i eth1.100 -o eth1.20 -j ACCEPT
-A FORWARD -i eth1.100 -o eth1.50 -j ACCEPT
-A FORWARD -i eth1.10 -o eth1.100 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i eth1.20 -o eth1.100 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i eth1.50 -o eth1.100 -m state --state RELATED,ESTABLISHED -j ACCEPT
COMMIT
# Completed on Thu May 26 09:28:59 2016
# Generated by iptables-save v1.6.0 on Thu May 26 09:28:59 2016
*nat
:PREROUTING ACCEPT [32796:9980970]
:INPUT ACCEPT [142:30526]
:OUTPUT ACCEPT [1829:211124]
:POSTROUTING ACCEPT [128:29756]
-A POSTROUTING -o eth0 -j MASQUERADE
COMMIT
# Completed on Thu May 26 09:28:59 2016
Run Code Online (Sandbox Code Playgroud)

和输出route

Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         192.168.10.1    0.0.0.0         UG    0      0        0 eth0
10.10.0.0       *               255.255.255.0   U     0      0        0 eth1
10.10.10.0      *               255.255.255.0   U     0      0        0 eth1.10
10.10.20.0      *               255.255.255.0   U     0      0        0 eth1.20
10.10.50.0      *               255.255.255.0   U     0      0        0 eth1.50
10.10.100.0     *               255.255.255.0   U     0      0        0 eth1.100
link-local      *               255.255.0.0     U     1000   0        0 eth0
192.168.10.0    *               255.255.255.0   U     0      0        0 eth0
Run Code Online (Sandbox Code Playgroud)

预先感谢,希望有人能弄清楚我应该使用哪些 iptables 规则来实现我想要的(如果这就是问题所在)。

编辑:

按照 @Sanael 的要求,我做了更多日志记录 ( -A FORWARD -o eth1+ -p icmp -j LOG --log-prefix "IPTABLES FORWARD: " --log-level 7),结果如下:

Ping 10.10.20.101 --> 10.10.50.100成功,日志如下:

May 26 12:14:57 homeserver kernel: IPTABLES FORWARD: IN=eth1.20 OUT=eth1.50 MAC=00:0a:5e:50:7c:c1:c8:0a:a9:e5:f0:bc:08:00:45:00:00:3c SRC=10.10.20.101 DST=10.10.50.100 LEN=60 TOS=0x00 PREC=0x00 TTL=127 ID=23708 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=96
May 26 12:14:57 homeserver kernel: IPTABLES FORWARD: IN=eth1.50 OUT=eth1.20 MAC=00:0a:5e:50:7c:c1:00:1e:ec:fa:d1:10:08:00:45:00:00:3c SRC=10.10.50.100 DST=10.10.20.101 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=15185 PROTO=ICMP TYPE=0 CODE=0 ID=1 SEQ=96
May 26 12:14:58 homeserver kernel: IPTABLES FORWARD: IN=eth1.20 OUT=eth1.50 MAC=00:0a:5e:50:7c:c1:c8:0a:a9:e5:f0:bc:08:00:45:00:00:3c SRC=10.10.20.101 DST=10.10.50.100 LEN=60 TOS=0x00 PREC=0x00 TTL=127 ID=23709 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=97
May 26 12:14:58 homeserver kernel: IPTABLES FORWARD: IN=eth1.50 OUT=eth1.20 MAC=00:0a:5e:50:7c:c1:00:1e:ec:fa:d1:10:08:00:45:00:00:3c SRC=10.10.50.100 DST=10.10.20.101 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=15317 PROTO=ICMP TYPE=0 CODE=0 ID=1 SEQ=97
May 26 12:14:59 homeserver kernel: IPTABLES FORWARD: IN=eth1.20 OUT=eth1.50 MAC=00:0a:5e:50:7c:c1:c8:0a:a9:e5:f0:bc:08:00:45:00:00:3c SRC=10.10.20.101 DST=10.10.50.100 LEN=60 TOS=0x00 PREC=0x00 TTL=127 ID=23710 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=98
May 26 12:14:59 homeserver kernel: IPTABLES FORWARD: IN=eth1.50 OUT=eth1.20 MAC=00:0a:5e:50:7c:c1:00:1e:ec:fa:d1:10:08:00:45:00:00:3c SRC=10.10.50.100 DST=10.10.20.101 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=15349 PROTO=ICMP TYPE=0 CODE=0 ID=1 SEQ=98
May 26 12:15:00 homeserver kernel: IPTABLES FORWARD: IN=eth1.20 OUT=eth1.50 MAC=00:0a:5e:50:7c:c1:c8:0a:a9:e5:f0:bc:08:00:45:00:00:3c SRC=10.10.20.101 DST=10.10.50.100 LEN=60 TOS=0x00 PREC=0x00 TTL=127 ID=23711 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=99
May 26 12:15:00 homeserver kernel: IPTABLES FORWARD: IN=eth1.50 OUT=eth1.20 MAC=00:0a:5e:50:7c:c1:00:1e:ec:fa:d1:10:08:00:45:00:00:3c SRC=10.10.50.100 DST=10.10.20.101 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=15597 PROTO=ICMP TYPE=0 CODE=0 ID=1 SEQ=99
Run Code Online (Sandbox Code Playgroud)

Ping 10.10.20.101 --> 10.10.100.100失败,日志如下:

May 26 12:09:06 homeserver kernel: IPTABLES FORWARD: IN=eth1.20 OUT=eth1.100 MAC=00:0a:5e:50:7c:c1:c8:0a:a9:e5:f0:bc:08:00:45:00:00:3c SRC=10.10.20.101 DST=10.10.100.100 LEN=60 TOS=0x00 PREC=0x00 TTL=127 ID=18715 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=85
May 26 12:09:11 homeserver kernel: IPTABLES FORWARD: IN=eth1.20 OUT=eth1.100 MAC=00:0a:5e:50:7c:c1:c8:0a:a9:e5:f0:bc:08:00:45:00:00:3c SRC=10.10.20.101 DST=10.10.100.100 LEN=60 TOS=0x00 PREC=0x00 TTL=127 ID=18716 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=86
May 26 12:09:16 homeserver kernel: IPTABLES FORWARD: IN=eth1.20 OUT=eth1.100 MAC=00:0a:5e:50:7c:c1:c8:0a:a9:e5:f0:bc:08:00:45:00:00:3c SRC=10.10.20.101 DST=10.10.100.100 LEN=60 TOS=0x00 PREC=0x00 TTL=127 ID=18717 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=87
Run Code Online (Sandbox Code Playgroud)

Ping 10.10.50.100 --> 10.10.20.101失败,日志如下:

May 26 12:11:28 homeserver kernel: IPTABLES FORWARD: IN=eth1.50 OUT=eth1.20 MAC=00:0a:5e:50:7c:c1:00:1e:ec:fa:d1:10:08:00:45:00:00:54 SRC=10.10.50.100 DST=10.10.20.101 LEN=84 TOS=0x00 PREC=0x00 TTL=63 ID=54378 DF PROTO=ICMP TYPE=8 CODE=0 ID=1903 SEQ=1
May 26 12:11:29 homeserver kernel: IPTABLES FORWARD: IN=eth1.50 OUT=eth1.20 MAC=00:0a:5e:50:7c:c1:00:1e:ec:fa:d1:10:08:00:45:00:00:54 SRC=10.10.50.100 DST=10.10.20.101 LEN=84 TOS=0x00 PREC=0x00 TTL=63 ID=54495 DF PROTO=ICMP TYPE=8 CODE=0 ID=1903 SEQ=2
May 26 12:11:30 homeserver kernel: IPTABLES FORWARD: IN=eth1.50 OUT=eth1.20 MAC=00:0a:5e:50:7c:c1:00:1e:ec:fa:d1:10:08:00:45:00:00:54 SRC=10.10.50.100 DST=10.10.20.101 LEN=84 TOS=0x00 PREC=0x00 TTL=63 ID=54693 DF PROTO=ICMP TYPE=8 CODE=0 ID=1903 SEQ=3
Run Code Online (Sandbox Code Playgroud)

Ping 10.10.50.100 --> 10.10.100.100失败,日志如下:

May 26 12:12:24 homeserver kernel: IPTABLES FORWARD: IN=eth1.50 OUT=eth1.100 MAC=00:0a:5e:50:7c:c1:00:1e:ec:fa:d1:10:08:00:45:00:00:54 SRC=10.10.50.100 DST=10.10.100.100 LEN=84 TOS=0x00 PREC=0x00 TTL=63 ID=8069 DF PROTO=ICMP TYPE=8 CODE=0 ID=1905 SEQ=1
May 26 12:12:25 homeserver kernel: IPTABLES FORWARD: IN=eth1.50 OUT=eth1.100 MAC=00:0a:5e:50:7c:c1:00:1e:ec:fa:d1:10:08:00:45:00:00:54 SRC=10.10.50.100 DST=10.10.100.100 LEN=84 TOS=0x00 PREC=0x00 TTL=63 ID=8269 DF PROTO=ICMP TYPE=8 CODE=0 ID=1905 SEQ=2
May 26 12:12:26 homeserver kernel: IPTABLES FORWARD: IN=eth1.50 OUT=eth1.100 MAC=00:0a:5e:50:7c:c1:00:1e:ec:fa:d1:10:08:00:45:00:00:54 SRC=10.10.50.100 DST=10.10.100.100 LEN=84 TOS=0x00 PREC=0x00 TTL=63 ID=8375 DF PROTO=ICMP TYPE=8 CODE=0 ID=1905 SEQ=3
Run Code Online (Sandbox Code Playgroud)

Ping 10.10.100.100 --> 10.10.20.101失败 ,但未创建任何日志输出。

Ping 10.10.100.100 --> 10.10.50.100成功 ,但没有创建任何日志输出。

Air*_*ett 3

现在问题至少部分解决了(我对此很满意)。

我一开始是用Windows客户端测试网络的,两台电脑最近都升级了Windows 10。问题本身非常愚蠢:Windows 没有响应 ping,因为 Windows 10 默认启用了一些新的安全性。当我将一台 Linux 笔记本电脑添加到网络时,我遇到了一种情况,所有其他笔记本电脑都可以 ping 通该 Linux 笔记本电脑(默认策略是ALLOW),但 Linux PC 无法 ping 任何其他内容(Windows 没有响应 ping)。然后我尝试从 VLAN 100 中的 Linux PC 远程桌面到 VLAN 10 和 50 中的 Windows PC,结果成功了!

所以iptables/netfilter规则完全没有问题。

非常感谢您的所有回答和评论!

这是我最终的、工作的和简化的 iptables 配置:

# Generated by iptables-save v1.6.0 on Thu May 26 16:00:55 2016
*filter
:INPUT ACCEPT [359:39449]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [563:89333]
-A FORWARD -i eth1+ -o eth1.100 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i eth1.100 -o eth1+ -j ACCEPT
-A FORWARD -i eth1+ -o eth0 -j ACCEPT
-A FORWARD -i eth0 -o eth1+ -m state --state RELATED,ESTABLISHED -j ACCEPT
COMMIT
# Completed on Thu May 26 16:00:55 2016
# Generated by iptables-save v1.6.0 on Thu May 26 16:00:55 2016
*nat
:PREROUTING ACCEPT [5650:1147271]
:INPUT ACCEPT [91:14019]
:OUTPUT ACCEPT [325:31088]
:POSTROUTING ACCEPT [44:7161]
-A POSTROUTING -o eth0 -j MASQUERADE
COMMIT
# Completed on Thu May 26 16:00:55 2016
Run Code Online (Sandbox Code Playgroud)