【小菜學網路】觀察集線器與交換機

fasionchan發表於2021-02-25

集線器和交換機是兩種典型的網路裝置,集線器 位於 物理層,而 交換機 位於於 資料鏈路層 ,行為明顯不同。本節準備了兩個簡單實驗,旨在通過實踐加深對理論知識的理解,逐步掌握 Linux 主機網路操作。

實驗一:觀察乙太網集線器

本實驗將 3Linux 主機連到一個集線器上,以此觀察集線器的工作行為,網路拓撲圖如下:

實驗環境以 docker 容器的形式提供,執行這個 docker 命令即可一鍵開啟:

docker run --name hub-lab --rm -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_ADMIN -v /data -h hub-lab fasionchan/netbox:0.5 bash /script/hub-lab.sh

實驗環境開啟後,可以看到 3 個視窗,各自代表一臺主機:

這是用 tmux 命令實現的視窗劃分,按下_ Ctrl-B_ 後再按方向鍵,即可在不同主機視窗間切換。

請特別注意,按下 Ctrl-B 後要鬆手,然後再按方向鍵,才能切到想要操作的主機視窗。

還有一種更快捷的切換方法,先按下 Ctrl-B ,鬆手後再按 Q 。這時,每個視窗都會顯示一個數字。接著,按下對應的數字即可切到想要的視窗:

我們先切到主機 ant ,觀察它的網路卡資訊,ifconfigip 命令均可:

root@ant [ ~ ]  ➜ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether 32:90:b9:9f:35:56  txqueuelen 1000  (Ethernet)
        RX packets 6  bytes 540 (540.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3  bytes 270 (270.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
root@ant [ ~ ]  ➜ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/tunnel6 :: brd ::
6: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 32:90:b9:9f:35:56 brd ff:ff:ff:ff:ff:ff link-netnsid 0

接著,切到主機 beecicada ,繼續觀察它們的網路卡資訊:

root@bee [ ~ ]  ➜ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/tunnel6 :: brd ::
8: eth0@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether a2:17:41:bb:cd:98 brd ff:ff:ff:ff:ff:ff link-netnsid 0
root@cicada [ ~ ]  ➜ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/tunnel6 :: brd ::
10: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether ee:76:f2:37:5e:69 brd ff:ff:ff:ff:ff:ff link-netnsid 0

經過觀察,3 臺主機網路卡及 MAC 地址資訊整理如下:

主機 網路卡 MAC地址
ant eth0 32:90:b9:9f:35:56
bee eth0 a2:17:41:bb:cd:98
cicada eth0 ee:76:f2:37:5e:69

現在,我們從主機 ant 向主機 bee 傳送一句話,看主機 bee 是否可以收到這個資訊,於此同時觀察主機 cicada 是否也可以收到。開始傳送之前,我們先在 beecicada 執行抓包工具 tcpdump 命令,嗅探網路流量:

root@bee [ ~ ]  ➜ tcpdump -ni eth0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
root@cicada [ ~ ]  ➜ tcpdump -ni eth0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes

tcpdump 命令 -i 選項指定嗅探網路卡,這裡我們嗅探每臺主機 eth0 網路卡上的流量。

一切準備就緒,我們在主機 ant 上執行自制工具 sendetherbee 發一段文字:

root@ant [ ~ ]  ➜ sendether -i eth0 -t a2:17:41:bb:cd:98 -T 0x0900 -d 'hello, world!'

sendether 是一個自制命令,用於傳送乙太網幀。其中,-i 指定傳送網路卡,-t 指定目的地址,-T 指定資料型別,-d 指定要傳送的資料。後續的程式設計環節,我們會講解 sendether 是如何封裝、傳送乙太網幀的。

我們立馬看到主機 bee 上的 tcpdump 抓到一個乙太網幀,它就是 ant 發出來的 hello, world!

root@bee [ ~ ]  ➜ tcpdump -ni eth0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
16:37:27.254658 32:90:b9:9f:35:56 > a2:17:41:bb:cd:98, ethertype Unknown (0x0900), length 27:
	0x0000:  6865 6c6c 6f2c 2077 6f72 6c64 21         hello,.world!

注意到,主機 cicada 也收到這個幀,這符合集線器的行為:

root@cicada [ ~ ]  ➜ tcpdump -ni eth0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
16:37:27.254624 32:90:b9:9f:35:56 > a2:17:41:bb:cd:98, ethertype Unknown (0x0900), length 27:
	0x0000:  6865 6c6c 6f2c 2077 6f72 6c64 21         hello,.world!

由於這個幀的目的主機並不是 cicadacicada 協議棧將丟棄它。

實驗二:觀察乙太網交換機

本實驗將 3Linux 主機連到一個交換機上,以此觀察交換機的工作行為,網路拓撲圖如下:

實驗環境同樣通過 docker 容器提供,執行以下命令即可一鍵開啟:

docker run --name switch-lab --rm -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_ADMIN -v /data -h switch fasionchan/netbox:0.5 bash /script/switch-lab.sh

實驗環境啟動後,可以看到 4 個由 tmux 命令劃分的視窗,分別代表 3 臺主機以及交換機。

為了方便觀察交換機 MAC 地址學習的過程,我們為每臺主機設定了一個很好分辨的 MAC 地址:

主機 網路卡 MAC地址 交換機埠
ant eth0 40:aa:aa:aa:aa:aa 1
bee eth0 40:bb:bb:bb:bb:bb 2
cicada eth0 40:cc:cc:cc:cc:cc 3

實驗環境中的交換機由 bridge 虛擬裝置模擬,裝置名為 switch0 :

root@switch [ ~ ]  ➜ ip link show switch0
4: switch0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 4a:9e:f8:3c:75:40 brd ff:ff:ff:ff:ff:ff

執行 brctl 命令,可以檢視交換機當前的 MAC 地址表:

root@switch [ ~ ]  ➜ brctl showmacs switch0
port no	mac addr		is local?	ageing timer
  3	4a:9e:f8:3c:75:40	yes		   0.00
  3	4a:9e:f8:3c:75:40	yes		   0.00
  2	6a:64:44:0d:d1:55	yes		   0.00
  2	6a:64:44:0d:d1:55	yes		   0.00
  1	be:24:47:bd:f2:52	yes		   0.00
  1	be:24:47:bd:f2:52	yes		   0.00

噫?怎麼 MAC 地址表已經有一些條目了?我們明明還沒有在任何主機上發資料,地址表按理說應該是空的呀!

其實,這些 MAC 地址是交換機自己的, is local 列值都是 yes 。如果將該列值為 yes 的記錄過濾掉,就可以確認 MAC 地址表確實為空(暫未學習到任何地址):

root@switch [ ~ ]  ➜ brctl showmacs switch0 | grep -v yes
port no	mac addr		is local?	ageing timer

現在,我們在主機 ant 上往主機 bee 傳送一個乙太網幀,來觀察交換機行為。開始之前,我們先在主機 beecicada 上執行 tcpdump 命令來嗅探網路流量。

root@bee [ ~ ]  ➜ tcpdump -ni eth0
root@cicada [ ~ ]  ➜ tcpdump -ni eth0
root@ant [ ~ ]  ➜ sendether -i eth0 -t 40:bb:bb:bb:bb:bb -d 'hello, bee!'

這個幀成功發出去後,我們同時在主機 beecicada 上觀察它。原因在於,交換機還沒學到主機 beeMAC 地址,只能將這個幀轉發到其他所有埠,因此 cicada 也會收到它。

root@bee [ ~ ]  ➜ tcpdump -ni eth0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
16:40:34.437330 40:aa:aa:aa:aa:aa > 40:bb:bb:bb:bb:bb, ethertype Unknown (0x0900), length 25:
	0x0000:  6865 6c6c 6f2c 2062 6565 21              hello,.bee!
root@cicada [ ~ ]  ➜ tcpdump -ni eth0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
16:40:34.437152 40:aa:aa:aa:aa:aa > 40:bb:bb:bb:bb:bb, ethertype Unknown (0x0900), length 25:
	0x0000:  6865 6c6c 6f2c 2062 6565 21              hello,.bee!

交換機從埠 0 接到主機 ant 傳送的乙太網幀,源地址是 40:aa:aa:aa:aa:aa ,便知道以後發給這個地址的幀應該轉發給埠 0 。這樣一來,交換機機智地學習到主機 antMAC 地址:

root@switch [ ~ ]  ➜ brctl showmacs switch0 | grep -v yes
port no	mac addr		is local?	ageing timer
  1	40:aa:aa:aa:aa:aa	no		   1.97

接著,我們在主機 beeant 回覆一個資訊:

root@bee [ ~ ]  ➜ sendether -i eth0 -t 40:aa:aa:aa:aa:aa -d 'how are you?'

由於交換機已經學習到 ant 的地址,知道去往 40:aa:aa:aa:aa:aa 的幀應該轉發到埠 0 ,位於埠 3cicada 主機便不會收到這個幀了。

同理,在這個過程中,交換機學習到主機 beeMAC 地址 40:bb:bb:bb:bb:bb :

root@switch [ ~ ]  ➜ brctl showmacs switch0 | grep -v yes
port no	mac addr		is local?	ageing timer
  1	40:aa:aa:aa:aa:aa	no		  60.17
  2	40:bb:bb:bb:bb:bb	no		  50.14

這樣一來,主機 ant 再給 bee 發資料,cicada 同樣也不會收到了:

root@ant [ ~ ]  ➜ sendether -i eth0 -t 40:bb:bb:bb:bb:bb -d 'fine, thank you!'

小菜學網路】系列文章首發於公眾號【小菜學程式設計】,敬請關注:

相關文章