Linux

Linux - 強制不同的使用者使用不同的網路介面

  • August 23, 2022

我有一台帶有一個物理網卡的 linux 機器,它與一個託管交換機連接。連接是 VLAN 中繼。在機器上有兩個 VLAN 介面,它們有不同的 IP 地址(不同 VLAN 的一部分)。

我想要實現的是,根據在這台機器上登錄的互動式使用者,強制使用者使用某個 VLAN 的網路介面。

目前網路設置

NIC = enp1s0
VLAN3 itf = enp1s0.3 - bridged in br0.3 with IP = 192.168.3.2
VLAN4 itf = enp1s0.4 - bridged in br0.4 with IP = 192.168.4.2

user3 (uid=1003) 登錄時應該讓他創建的所有網路流量通過 br0.3

user4 (uid=1004) 登錄時應該讓他創建的所有網路流量通過 br0.4

選項 1:僅 nft。

我的第一次嘗試是使用 nftables 來強制執行此操作。

# hook output, type route (allows to mangle with packets)
nft add table net4
nft add chain net4 mangle '{ 
   type route hook output priority -300; policy accept;
}'

nft add rule ip net4 mangle meta skuid 1004 ip saddr set 192.168.4.2 return
nft add rule ip net4 mangle meta skuid 1004 oif br0.3 drop

這不能按預期工作。數據包的源地址已更改,但它在 br0.3 上發出。返回數據包通過 br0.4 返回。即使更改了saddr,傳出的數據包仍然綁定到br0.3。我通過使用以下命令打開兩個終端看到了這種行為:

tcpdump -i br0.3 -nn host 192.168.3.2 or host 192.168.4.2
tcpdump -i br0.4 -nn host 192.168.3.2 or host 192.168.4.2

根據:https ://wiki.nftables.org/wiki-nftables/index.php/Netfilter_hooks輸出掛鉤是路由決定之後,所以看來這不能再改變了。

我嘗試了這樣的規則:

nft add rule ip net4 mangle meta skuid 1004 ip saddr set 192.168.4.2 meta oifname set br0.4 return

但不允許設置 oif 或 oifname。

根據https://www.nftables.org/documentation/HOWTO/netfilter-extensions-HOWTO-4.html#ss4.5有一個 ROUTE 更新檔可以提供更改 oif 的能力。但是這個例子是針對 iptables 的,我似乎不能將這個更新檔用於 nftables 或 iptables。

我也嘗試了另一種 nft 規則集,將標記與 ip 規則和 ip 路由結合使用:

nft add rule ip net4 mangle meta skuid 1004 ip saddr set 192.168.4.2 meta mark set 4 return
nft add rule ip net4 mangle meta skuid 1004 oif br0.3 drop

ip rule add priority 10000 fwmark 4 table 4
ip route add table 4 default via 192.168.4.1 dev br0.4

正如預期的那樣,這也不起作用,因為輸出掛鉤似乎確實在路由決策之後。

選項 2:帶有一點 nft 的網路命名空間

我嘗試了另一種選擇:網路命名空間。

# delete the network interface and bridge
ip link set dev br0.4 down
ip link set enp1s0.4 down
ip link del br0.4
ip link del enp1s0.4

# create netns and create new vlan interface in new netns
NAMESPACE=netns4
ip netns add $NAMESPACE
ip -n $NAMESPACE link set dev lo up
ip link add link enp1s0 name enp1s0.4 netns $NAMESPACE type vlan id 4
ip -n $NAMESPACE link add name br0.4 type bridge
ip -n $NAMESPACE link set dev enp1s0.4 master br0.4
ip -n $NAMESPACE link set enp1s0.4 up
ip -n $NAMESPACE link set br0.4 up
ip -n $NAMESPACE addr add 192.168.4.2/24 dev br0.4
ip -n $NAMESPACE route add default via 192.168.4.1 dev br0.4

當我現在以 root 身份在命名空間之間來回切換時,一切都按預期工作。如果我將此與不允許 user4 使用 br0.3 的 nft 規則結合起來,我或多或少有我需要的東西。

nft add rule ip net4 mangle meta skuid 1004 oif br0.3 drop

但是,使用此命名空間設置使用者會話並不簡單。systemd-logind 不允許使用非預設命名空間創建生成的使用者會話的配置。同樣,圖形登錄無法為每個使用者或使用者組配置名稱空間。我的系統有 sddm,它允許 Namespaces= 在

$$ General $$部分,但這意味著所有使用者都將加入所有指定的命名空間。 終端登錄,需要像這樣使用 sudoers 的 hack(因為配置文件的東西是以使用者身份執行的)和文件 /etc/profile.local 並且僅適用於 bash。

uid=`/usr/bin/id -u`
uname=`/usr/bin/id -un`
if [ $uid = 1004 ]; then
       namespace=netns4
       if [ -r /run/netns/$namespace ]; then
               namespace_inode=`ls -i /run/netns/$namespace | cut -d ' ' -f 1`
               proc_inode=`ls -l /proc/$$/ns/net | sed 's/.*\[\([0-9][0-9]*\)\]/\1/'`
               if [ $proc_inode != $namespace_inode ]; then
                       uname=`/usr/bin/id -un`
                       sudo /usr/bin/ip netns exec $namespace /usr/bin/su - $uname "${@}"
               fi
       fi
fi

並且 sudoers 必須有一行:

user4 ALL = (root) NOPASSWD: /usr/bin/ip netns exec netns4 /usr/bin/su - user4
user4 ALL = (root) NOPASSWD: /usr/bin/ip netns exec netns4 /usr/bin/su - user4 *

我似乎無法為 Xsession /usr/etc/X11/xdm/Xsession 做同樣的事情

有人知道如何實現我的原始要求嗎?

您只需要策略路由

ip route add table 1003 default dev enp1s0.3
ip rule add uidrange 1003-1003 table 1003

ip route add table 1004 default dev enp1s0.4
ip rule add uidrange 1004-1004 table 1004

rule add table main suppress_prefixlength 0

所以我試了一下,是的,它按預期工作。

我有點難以理解

ip rule add table main suppress_prefixlength 0

我想目的是確保由於某種原因在表 1003 或表 1004 中不匹配的數據包不會遵循主表中前綴長度為 0 的路由(即預設路由)。

引用自:https://serverfault.com/questions/1108819