# 802.3 - Ethernet Frame [TOC] ## 課程影片 ### 第 2E 講 IEEE 802.3 乙太網路 (Ethernet) L02 {%youtube 6TV9UBGwISE %} ### [Python Network Packet Sniffer Tutorial - 1 - Introduction](https://youtu.be/WGJC5vT5YJo) {%youtube WGJC5vT5YJo %} ### [Python Network Packet Sniffer Tutorial - 2 - Formatting MAC Address](https://youtu.be/jVwvOZfAGNk) {%youtube jVwvOZfAGNk %} ### [Python Network Packet Sniffer Tutorial - 3 - Capturing Traffic](https://youtu.be/dM9grWOdTBI) {%youtube dM9grWOdTBI %} ## Ethernet Frame ![](https://i.imgur.com/0bgPaZZ.png) 當中各個欄位的定義,除了紀錄在 802.3 的規格中之外,一個實際出現的地方是 *Linux* 核心中 [`include/uapi/linux/if_ether.h`](https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/if_ether.h#L32) 定義的各個常數: ```c #define ETH_ALEN 6 /* Octets in one ethernet addr */ #define ETH_TLEN 2 /* Octets in ethernet type field */ #define ETH_HLEN 14 /* Total octets in header. */ #define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ #define ETH_DATA_LEN 1500 /* Max. octets in payload */ #define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ #define ETH_FCS_LEN 4 /* Octets in the FCS */ ``` 而 DA、SA 與 Type 三者合起來又稱為 *ethernet header*,*Linux* 核心對應的結構體則是 `struct ethhdr`: ```c struct ethhdr { unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ unsigned char h_source[ETH_ALEN]; /* source ether addr */ __be16 h_proto; /* packet type ID field */ } __attribute__((packed)); ``` ## Preamble (56 位元) 「前奏」的意思。前 56 個位元。這 56 個位元是 0 與 1 交錯。這是用來做提示與校正,當看到 *bus* 上出現不斷交錯的 0 與 1 時,就會知道可能有傳輸會發生。除此之外,由 0 與 1 的變化速度,也可以作為傳輸速度的同步。 ## SFD (8 位元) *Start frame delimeter*,區隔 *preamble* 與接下來的內容,表示傳輸即將開始。 ## DA 與 SA (48 + 48 位元) 接收端與發送端的 **MAC Address**。*MAC address* 是一個 48 位元的位址,一張網路卡(*adaptor*)會有唯一的 *MAC address*。這 48 位元的表示法通常每 8 個位元以分號區隔,並且用 16 進位表示。而這 48 個位元的前 24 個位元,用來識別這個網卡的供應商。比如說 AMD 是 `8:0:20`。 ### Unicast 要注意的是:傳輸一個 *frame* 傳遞到 *bus* 上時會使用廣播的機制,因此所有與這個 *bus* 連接的設備都看得到這個 *frame*。而這些設備看到這個 *frame* 之後,就看其中的 DA 來決定是否讀取這個 *frame*。這種傳輸稱為 *unicast*。 ### Broadcast 特別地,`ff:ff:ff:ff:ff:ff` 這個 *MAC address* 是用來表示「廣播」(*broadcast*)。當 DA 為這個數值時,表示這個 *frame* 發送給所有與這個 *bus* 連接的設備。 ### Multicast 除了 *unicast* 與 *broadcast*,還有介於兩者之間的 *multicast*,表示這個 *frame* 要同時傳送給 *bus* 上的多個裝置。不同設備之間可以形成群組,而不同的群組則是以一個 47 位元的數值作為識別。當 DA 的第一個位元為 `1` 時,就表示「要傳送給剩下 47 個位元所代表的群組中的所有設備」。而一個網卡最多可以加入 32 個群組。 > 因此,一張網卡在看到有 *frame* 出現在 *bus* 上面時,如果有下面三種狀況的其中任一,這個網卡就會把這個 *frame* 收下來: > > 1. 當這個 *frame* 的 DA 恰好為自己的 *MAC address* 時。 > 2. 當這個 *frame* 的 DA 為 `ff:ff:ff:ff:ff:ff` 時。 > 3. 當這個 *frame* 的 DA 的第一個位元為 `1`,而且自己恰好在 DA 剩下的 47 位元所代表的群組中的時候。 ## Type (16 位元) 表示 *payload* 是哪一個類型的資訊,比如說使用 L3 的哪種協定。 ## LLC + PAD (最大 1500 位元組) 真正的資料。這個欄位有範圍限制: $$ 46 \leq LLC + PAD \leq 1500 $$ 因此,連同後面的 FCS 算進去,一個乙太網路的 *frame* 至多只會到 1518 個 *byte*,而最短則是 64 *byte*。 ## FCS (32 位元) *frame check sequence*,檢查碼。比如說 CRC 校驗碼等等。