16.8.26

Linux Bridge VLAN SVI nftables in labs

測試環境 wsl + ubuntu22.04 實驗軟體式網路橋接,VLAN,SVI功能

[ Host A (ns-a) ]           [ Linux Bridge (br0) ]           [ Host B (ns-b) ]

veth-a (10.0.0.1) <======> veth-a-br <======> veth-b (10.0.0.2)


建立兩個虛擬網路空間 ns-a 與 ns-b

sudo ip netns add ns-a

sudo ip netns add ns-b

建立 Linux Bridge 橋接器 br0

sudo ip link add name br0 type bridge

sudo ip link set dev br0 up

建立並連接 veth pair

建立兩個虛擬網卡(veth)

建立連接 ns-a 的網卡

sudo ip link add veth-a type veth peer name veth-a-br

sudo ip link set veth-a netns ns-a

sudo ip link set dev veth-a-br master br0

建立連接 ns-b 的網卡

sudo ip link add veth-b type veth peer name veth-b-br

sudo ip link set veth-b netns ns-b

sudo ip link set dev veth-b-br master br0

分別設定兩台虛擬主機的 IP 位址,並啟動所有相關網卡

設定 Host A (ns-a)

sudo ip netns exec ns-a ip addr add 10.0.0.1/24 dev veth-a

sudo ip netns exec ns-a ip link set dev veth-a up

sudo ip link set dev veth-a-br up

設定 Host B (ns-b)

sudo ip netns exec ns-b ip addr add 10.0.0.2/24 dev veth-b

sudo ip netns exec ns-b ip link set dev veth-b up

sudo ip link set dev veth-b-br up

測試驗證 Linux Bridge 

ns-a (10.0.0.1) Ping ns-b (10.0.0.2)

sudo ip netns exec ns-a ping -c 3 10.0.0.2

觀察 Linux Bridge 的 FDB (Forwarding Database / MAC )

bridge fdb show dev br0

Linux Bridge 就是一台 Layer 2 Switch,它會學習 MAC 位址與 Port 的對應關係

veth-a-br 與 veth-b-br 介面會有對應的 ns-a 與 ns-b 的 MAC 位址

測試完畢後,以下指令可手動將建置環境清除

sudo ip netns del ns-a

sudo ip netns del ns-b

sudo ip link del br0

-----------------------------------------------------------------------------------------------------------------------

實驗 VLAN Filtering (VLAN 預測/過濾) 機制。在單一 Bridge 上同時處理 Access Port(打 Tag/剝 Tag)與 Trunk Port,實現不同 VLAN 之間的 Layer 2 隔離。

1.  PVID (Port VLAN ID):當未帶 Tag 的封包進入這個埠(Ingress)時,Bridge 會強制幫它帶上 VLAN ID。

2.  Puntagged (Untagged):當封包要離開這個埠(Egress)時,若 VLAN ID 與此設定相符,Bridge 會把 VLAN Tag 剝除。

[ Host A (ns-a) ]             [ Host B (ns-b) ]             [ Host C (ns-c) ]

  10.0.0.1/24                   10.0.0.2/24                       10.0.0.3/24

       |                                      |                                          |

 (Access VLAN 10)        (Access VLAN 10)         (Access VLAN 20)

       |                                      |                                         |

  veth-a-br                     veth-b-br                           veth-c-br

  +-----------------------------------------------------------------------+

  |                     Linux Bridge (br0, vlan_filtering=1)              |

  +-----------------------------------------------------------------------+

VLAN 10:ns-a (10.0.0.1) 與 ns-b (10.0.0.2)

VLAN 20:ns-c (10.0.0.3)

實驗測試 ns-a 與 ns-b 可以互通,跟 ns-c 無法連結。

建立三個虛擬網路空間,並建立開啟 VLAN Filtering 功能的 Bridge

建立 Namespace

sudo ip netns add ns-a

sudo ip netns add ns-b

sudo ip netns add ns-c

建立 Bridge 並開啟 vlan_filtering 功能

sudo ip link add name br0 type bridge vlan_filtering 1

sudo ip link set dev br0 up

建立對應的虛擬網卡,並分配 IP 位址

連接 ns-a

sudo ip link add veth-a type veth peer name veth-a-br

sudo ip link set veth-a netns ns-a

sudo ip link set dev veth-a-br master br0

sudo ip netns exec ns-a ip addr add 10.0.0.1/24 dev veth-a

sudo ip netns exec ns-a ip link set dev veth-a up

sudo ip link set dev veth-a-br up

連接 ns-b

sudo ip link add veth-b type veth peer name veth-b-br

sudo ip link set veth-b netns ns-b

sudo ip link set dev veth-b-br master br0

sudo ip netns exec ns-b ip addr add 10.0.0.2/24 dev veth-b

sudo ip netns exec ns-b ip link set dev veth-b up

sudo ip link set dev veth-b-br up

連接 ns-c

sudo ip link add veth-c type veth peer name veth-c-br

sudo ip link set veth-c netns ns-c

sudo ip link set dev veth-c-br master br0

sudo ip netns exec ns-c ip addr add 10.0.0.3/24 dev veth-c

sudo ip netns exec ns-c ip link set dev veth-c up

sudo ip link set dev veth-c-br up

預設情況下,Bridge 上的 Port 都屬於 VLAN 1。需要先清除預設值,再指派指定的 VLAN

設定 veth-a-br (VLAN 10) 

sudo bridge vlan del dev veth-a-br vid 1

sudo bridge vlan add dev veth-a-br vid 10 pvid untagged

設定 veth-b-br (VLAN 10) 

sudo bridge vlan del dev veth-b-br vid 10

sudo bridge vlan del dev veth-b-br vid 1

sudo bridge vlan add dev veth-b-br vid 10 pvid untagged

設定 veth-c-br (VLAN 20) 

sudo bridge vlan del dev veth-c-br vid 1

sudo bridge vlan add dev veth-c-br vid 20 pvid untagged

透過 bridge vlan show 指令查看各介面的 VLAN 分配情形

測試 sudo ip netns exec ns-a ping -c 2 10.0.0.2

跨 VLAN 測試 sudo ip netns exec ns-a ping -c 2 10.0.0.3

實作 Trunk Port

如果 Bridge 有一張實體網卡 eth1 要連接到外部的網管型交換器L3的(Switched Switch),並需要同時傳送 VLAN 10 與 VLAN 20 的帶 Tag 封包

設定 eth1 為 Trunk Port (允許 VLAN 10 與 20 通過,不剝除 Tag、不設定 pvid)

sudo bridge vlan del dev eth1 vid 1

sudo bridge vlan add dev eth1 vid 10

sudo bridge vlan add dev eth1 vid 20

測試完畢後,以下指令可手動將建置環境清除

sudo ip netns del ns-a

sudo ip netns del ns-b

sudo ip netns del ns-c

sudo ip link del br0

--------------------------------------------------------------------------------------------------------------------------

實驗不同 VLAN 之間的 Layer 3 路由(Inter-VLAN Routing),使用 SVI(Switch Virtual Interface)架構。

                             [ Linux Kernel Router ]

                               /                              \

            br0.10 (SVI)                     br0.20 (SVI)

           IP: 10.0.10.254                  IP: 10.0.20.254

                      |                                           |

  +-------------+---------------------------------+-------------+

  |               Linux Bridge (br0, vlan_filtering=1)          |

  +-------------------------------------------------------------+

                  |                                                       |

    (Access VLAN 10)                           (Access VLAN 20)

                 |                                                         |

          veth-a-br                                          veth-c-br

              |                                                           |

  [ Host A (ns-a) ]                                  [ Host C (ns-c) ]

   IP: 10.0.10.1/24                                 IP: 10.0.20.1/24

   GW: 10.0.10.254                                GW: 10.0.20.254

建立 Bridge 並開啟 vlan_filtering,將 ns-a 置入 VLAN 10,ns-c 置入 VLAN 20

建立 Namespace

sudo ip netns add ns-a

sudo ip netns add ns-c

建立 Bridge 並開啟 VLAN 過濾

sudo ip link add name br0 type bridge vlan_filtering 1

sudo ip link set dev br0 up

配置 Host A (ns-a) -> VLAN 10 (10.0.10.0/24)

sudo ip link add veth-a type veth peer name veth-a-br

sudo ip link set veth-a netns ns-a

sudo ip link set dev veth-a-br master br0

sudo ip netns exec ns-a ip addr add 10.0.10.1/24 dev veth-a

sudo ip netns exec ns-a ip link set dev veth-a up

sudo ip link set dev veth-a-br up

sudo bridge vlan del dev veth-a-br vid 1

sudo bridge vlan add dev veth-a-br vid 10 pvid untagged

配置 Host C (ns-c) -> VLAN 20 (10.0.20.0/24)

sudo ip link add veth-c type veth peer name veth-c-br

sudo ip link set veth-c netns ns-c

sudo ip link set dev veth-c-br master br0

sudo ip netns exec ns-c ip addr add 10.0.20.1/24 dev veth-c

sudo ip netns exec ns-c ip link set dev veth-c up

sudo ip link set dev veth-c-br up

sudo bridge vlan del dev veth-c-br vid 1

sudo bridge vlan add dev veth-c-br vid 20 pvid untagged

建立 Bridge 上的 VLAN 子介面,並給予每個 VLAN 的 Gateway IP。同時將對應的 VLAN 允許傳送至 Bridge (self)

建立 VLAN 10 的 SVI

sudo ip link add link br0 name br0.10 type vlan id 10

sudo ip addr add 10.0.10.254/24 dev br0.10

sudo ip link set dev br0.10 up

建立 VLAN 20 的 SVI

sudo ip link add link br0 name br0.20 type vlan id 20

sudo ip addr add 10.0.20.254/24 dev br0.20

sudo ip link set dev br0.20 up

Bridge 需接收帶有 VLAN 10/20 的封包 (SVI 必需)

sudo bridge vlan add dev br0 vid 10 self

sudo bridge vlan add dev br0 vid 20 self

兩張虛擬網卡加上預設閘道,並啟用 IP Forwarding 轉發

為 Host A 與 Host C 設定 Default Gateway

sudo ip netns exec ns-a ip route add default via 10.0.10.254

sudo ip netns exec ns-c ip route add default via 10.0.20.254

啟用 Linux IPv4 封包轉發

sudo sysctl -w net.ipv4.ip_forward=1

從 ns-a Ping VLAN 10 的 SVI 閘道

sudo ip netns exec ns-a ping -c 2 10.0.10.254

從 ns-a (VLAN 10, 10.0.10.1) 跨網段Ping ns-c (VLAN 20, 10.0.20.1)

sudo ip netns exec ns-a ping -c 3 10.0.20.1

ICMP 回應封包的 ttl會等於63,從 64 減 1,封包經過了一個路由

預設所有 VLAN 都能互通。要做存取控制要利用 Linux 的 iptables 在 FORWARD 鏈進行過濾

例如拒絕 VLAN 10 存取 VLAN 20

阻擋 VLAN 10 (10.0.10.0/24) 存取 VLAN 20 (10.0.20.0/24)

sudo iptables -A FORWARD -i br0.10 -o br0.20 -j DROP

測試完畢後,以下指令可手動將建置環境清除

sudo ip netns del ns-a

sudo ip netns del ns-c

sudo ip link del br0

---------------------------------------------------------------------------------------------------------------------

用nftables 實驗狀態防火牆(Stateful Firewall),是利用 Linux 的連線追蹤機制(conntrack / ct state)

透過追蹤封包的連線狀態(new, established, related, invalid)判斷

VLAN 10 發起連線(ct state new)往 VLAN 20

VLAN 20 回應(ct state established,related)給 VLAN 10

拒絕 VLAN 20 發起連線往 VLAN 10

建立一個 filter 的 inet 表格,並建立一個預設為 drop 的 forward 鏈

建立表格

sudo nft add table inet filter

建立 forward 鏈,設定 Hook 為 forward,策略為 drop (全擋)

sudo nft add chain inet filter forward '{ type filter hook forward priority filter; policy drop; }'

新增連線過濾。把 established,related 放在最頂端

允許(Established)與(Related)的封包通過

sudo nft add rule inet filter forward ct state established,related accept

直接丟棄異常(Invalid)的封包

sudo nft add rule inet filter forward ct state invalid drop

允許從 br0.10 進來、往 br0.20 出去的連線

sudo nft add rule inet filter forward iifname "br0.10" oifname "br0.20" ct state new accept

使用 nft list ruleset 查看目前的規則

sudo nft list ruleset

在 ns-c (VLAN 20, 10.0.20.1) 監聽 TCP Port 8080,並從 ns-a (VLAN 10, 10.0.10.1) 連線

在 ns-c (VLAN 20) 開啟監聽

sudo ip netns exec ns-c nc -lvp 8080

從 ns-a (VLAN 10) 進行連線

sudo ip netns exec ns-a nc -zv 10.0.20.1 8080

連線成功(Connection to 10.0.20.1 8080 port [tcp] succeeded!)

反過來,在 ns-a (VLAN 10) 監聽 Port 8080,並從 ns-c (VLAN 20) 進行連線

在 ns-a (VLAN 10) 開啟監聽

sudo ip netns exec ns-a nc -lvp 8080

從 ns-c (VLAN 20) 嘗試連線

sudo ip netns exec ns-c nc -zv -w 2 10.0.10.1 8080

連線逾時失敗(Connection timed out)

過濾時對封包留下日誌,可以在 forward 鏈加上一條 log 規則

sudo nft add rule inet filter forward iifname "br0.20" oifname "br0.10" log prefix \"[NFT-VLAN20-BLOCK] \" drop

確認規則是否已成功加入

sudo nft list chain inet filter forward

即時監看log

查看核心即時訊息

sudo dmesg -w | grep NFT-VLAN20-BLOCK

或透過 journalctl 監看

sudo journalctl -kf | grep NFT-VLAN20-BLOCK

沒有留言:

張貼留言