这是我的网络图:
56.56.56.56 192.168.0.1/24
MAC:AA:BB:CC:DD:EE:01
___________
---| Modem 1 |-------
| ___________ | ___________
Internet ---| | Switch |--------| Machine |
| ___________ | ___________
---| Modem 2 |------- 192.168.0.3/24
___________
67.67.67.67 192.168.0.2/24
MAC:AA:BB:CC:DD:EE:02
- 两个调制解调器都将相同的端口从互联网转发到机器。
- 调制解调器后面的机器应该对来自互联网的任何请求做出适当的响应。例如,调制解调器 1 的数据包通过调制解调器 1 返回,调制解调器 2 的数据包通过调制解调器 2 返回。
- 机器只有一个网口,交换机是非管理型的。
- 该机器使用
Netplan
、iptables 和 iproute2 用于网络配置。
答案1
我最终从文章和评论中找到了解决方案基于发送方 MAC 地址的 Linux 策略路由和Netplan.io 关于策略路由的参考。
诀窍是通过 标记并 CONNTRACK 按源 MAC 地址发送的数据包到单独的路由表iptables -t mangle
,然后告诉 Netplan 使用该表适当地路由传出的数据包。
首先,我们需要将数据包集中到以下表:
将以下内容附加到文件/etc/iproute2/rt_tables
:
1 modem1
2 modem2
然后,告诉 Netplan 有关表、路线和标记的信息:
network:
version: 2
ethernets:
eth0:
routes:
- to: 0.0.0.0/0
via: 192.168.0.1
table: 1
- to: 0.0.0.0/0
via: 192.168.0.2
table: 2
routing-policy:
- from: 0.0.0.0/0
mark: 1
table: 1
- from: 0.0.0.0/0
mark: 2
table: 2
第一部分说明netplan
这些不同表中的数据包需要不同的默认路由。第二部分说明某些数据包将具有来自fwmark
iptables 的路由,这些数据包应被集中到这些表中。
然后,告诉iptables
通过数据包的原始 MAC 地址来标记数据包,但仅当它不是来自本地网络时(一个小脚本):
#!/bin/bash -x
MAC_MODEM1=AA:BB:CC:DD:EE:01
MAC_MODEM2=AA:BB:CC:DD:EE:02
MARK_MODEM1=0x1
MARK_MODEM2=0x2
LOCALNET=192.168.0.0/24
## Optional - Clear everything first
iptables -t mangle -F
for MODEM in MODEM1 MODEM2; do
MAC=MAC_$MODEM
MARK=MARK_$MODEM
iptables --table mangle --append INPUT \
--match state --state NEW \
--match mac --mac-source ${!MAC} \
! --source $LOCALNET \
--jump CONNMARK --set-mark ${!MARK}
done
iptables --table mangle --append OUTPUT \
--jump CONNMARK --restore-mark
然后,告诉 netplan 生成并应用:
$ sudo netplan generate
$ sudo netplan apply
瞧!
奖励答案
如果你有多个内部网络(例如通过非本地 IP 的 VPN),请使用ipset
和iptables
-m set ! -match-set alias
,例如
ipset destroy officenets #optional - to clear
LOCALNET=192.168.0.0/24
VPNNET=10.10.10.0/29
ipset create privatenets hash:net
ipset add privatenets $LOCALNET
ipset add privatenets $VPNNET
然后在 iptables 脚本中...
iptables --table mangle --append INPUT \
--match state --state NEW \
--match mac --mac-source ${!MAC} \
-m set \
! --match-set privatenets src \
--jump CONNMARK --set-mark ${!MARK}
确认
验证 fwmark 规则以路由表:
$ ip rule
0: from all lookup local
0: from all fwmark 0x1 lookup modem1
0: from all fwmark 0x2 lookup modem2
32766: from all lookup main
32767: from all lookup default
验证 iptables mangle 路由:
$ sudo iptables -t mangle -L
...
Chain INPUT (policy ACCEPT)
target prot opt source destination
CONNMARK all -- anywhere anywhere state NEW MAC AA:BB:CC:DD:EE:01 ! source 192.168.0.1/24 CONNMARK set 0x1
CONNMARK all -- anywhere anywhere state NEW MAC AA:BB:CC:DD:EE:02 ! source 192.168.0.2/24 CONNMARK set 0x2
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
CONNMARK all -- anywhere anywhere CONNMARK restore
...
验证传出表路由:
$ ip route list table modem1
default via 192.168.0.1 dev eth0 proto static
$ ip route list table modem2
default via 192.168.0.2 dev eth0 proto static