C/C++詳解實現(xiàn)二層轉(zhuǎn)發(fā)
OSI第2層
前兩個字段分別是目的地址和源地址字段。第3個字段是2字節(jié)的類型字段,用來標(biāo)識上一層是什么協(xié)議。
數(shù)據(jù)鏈路層有兩個子層:邏輯鏈路控制 (LLC) 子層和媒體訪問控制 (MAC) 子層。
媒體訪問控制 (MAC):MAC 子層處理硬件標(biāo)識號的分配,稱為 MAC 地址,它唯一地標(biāo)識網(wǎng)絡(luò)上的每個設(shè)備。 任何兩個設(shè)備都不應(yīng)具有相同的 MAC 地址。 MAC 地址是在制造時分配的。 大多數(shù)網(wǎng)絡(luò)都會自動識別它。 MAC 地址位于網(wǎng)卡 上。
交換機(jī)跟蹤網(wǎng)絡(luò)上的所有 MAC 地址。
邏輯鏈路控制 (LLC):LLC 子層處理成幀尋址和流量控制。 速度取決于節(jié)點之間的鏈接,例如以太網(wǎng)或 Wifi。
第 2 層上的數(shù)據(jù)單元是一個幀。每個幀都包含一個幀頭、正文和一個幀尾:
Header:通常包括源節(jié)點和目標(biāo)節(jié)點的 MAC 地址。
Body:由正在傳輸?shù)奈唤M成。
Trailer:包括錯誤檢測信息。 當(dāng)檢測到錯誤時,根據(jù)網(wǎng)絡(luò)或協(xié)議的實現(xiàn)或配置,幀可能會被丟棄,或者可能會將錯誤報告給更高層以進(jìn)行進(jìn)一步的糾錯。
error detection mechanisms::循環(huán)冗余校驗 (CRC) 和幀校驗序列 (FCS)。
通常有一個最大幀大小限制,稱為最大傳輸單元,MTU。 巨型幀超過標(biāo)準(zhǔn) MTU.
通過ARP解析出目標(biāo) MAC 地址?
傳統(tǒng)交換在 OSI 模型的第 2 層運行,其中數(shù)據(jù)包根據(jù)目標(biāo) MAC 地址發(fā)送到特定的交換機(jī)端口。第 2 層網(wǎng)段中的設(shè)備不需要路由即可到達(dá)本地對等點。 然而,需要的是可以通過地址解析協(xié)議 (ARP) 解析的目標(biāo) MAC 地址,如下所示:
在這里,PC A 想要將流量發(fā)送到 IP 地址為 192.168.1.6 的 PC B。 然而,它不知道唯一的 MAC 地址,直到它通過 ARP 發(fā)現(xiàn)它,該 ARP 在整個第 2 層網(wǎng)段中廣播。
然后將數(shù)據(jù)包發(fā)送到適當(dāng)?shù)哪繕?biāo) MAC 地址,交換機(jī)將根據(jù)其 MAC 地址表將正確的端口轉(zhuǎn)發(fā)出去。
什么是MAC地址表
MAC地址表是在交換機(jī)中記錄局域網(wǎng)主機(jī)和對應(yīng)接口關(guān)系的表,交換機(jī)就是根據(jù)這張表負(fù)責(zé)將數(shù)據(jù)幀傳輸?shù)街付ǖ闹鳈C(jī)上的。
MAC地址表可以動態(tài)的學(xué)習(xí)數(shù)據(jù)幀中的原MAC地址。在MAC地址表中,交換機(jī)的一個接口可以對應(yīng)多個MAC地址。一個MAC地址只能對應(yīng)在一個接口上。下面是MAC地址表形成的具體過程,如下:
二層轉(zhuǎn)發(fā)C/C++代碼實現(xiàn)
cethping:
void ethping(char *destination, char* interface){ //創(chuàng)建原始套接字。 指定接口名稱 struct RawSocket* rawsocket = new_RawSocket(interface); //數(shù)據(jù)包數(shù)據(jù)緩沖區(qū) unsigned char buf[1024]; //定義數(shù)據(jù)包。 投射以匹配以太網(wǎng)幀的格式 struct ethhdr_frame* eth_packet = (struct ethhdr_frame*)buf; //存儲發(fā)送方和接收方的 MAC 地址。 協(xié)議類型是可選的,并且指定了 0x0806。 //根據(jù)指定的接口名稱獲取發(fā)送者的MAC地址 memset(buf, 0x0, sizeof(eth_packet)); set_macaddr_from_string(destination, eth_packet->h_dest); set_macaddr_from_ifname(interface, eth_packet->h_source); eth_packet->h_proto = 0x0806; //在payload中設(shè)置字符串“Hello” char* data = "Hello"; memcpy(eth_packet->payload, data, sizeof(data)); //綁定指定接口上的socket rawsocket->bind_rawsocket(rawsocket); int send_size = send(rawsocket->socket, &buf, sizeof(buf), 0); printf("%dbyte send.\n", send_size); //關(guān)閉原始套接字 rawsocket->close_rawsocket(rawsocket); } int main(int argc, char *argv[]){ if(argc != 3){ printf("usage: %s <destination> <interface>", argv[0]); exit(0); } char *destination = argv[1]; char *if_name = argv[2]; ethping(destination, if_name); return 0; }
cethpingd:
void start_daemon(char *interface){ //創(chuàng)建原始套接字(指定接收器接口名稱) struct RawSocket* rawsocket = new_RawSocket(interface); int len; //使用 bind 綁定到接口 rawsocket->bind_rawsocket(rawsocket); while(1){ int len = rawsocket->recv_rawsocket(rawsocket); struct ethhdr_frame *data = (struct ethhdr_frame*)(rawsocket->buf); fflush(stdout); //顯示接收到的數(shù)據(jù)包的內(nèi)容 if(len > 0){ printf("src: "); print_macaddr(data->h_source); printf(", "); printf("dst: "); print_macaddr(data->h_dest); printf(", "); printf("type: "); printf("%02x", (uint16_t)data->h_proto); printf(", "); printf("payload: "); printf("%s", data->payload); printf("\n"); } } } int main(int argc, char *argv[]){ if(argc != 2){ printf("usage: %s <interface>", argv[0]); exit(0); } char *if_name = argv[1]; start_daemon(if_name); return 0; }
編譯:
增加兩個虛擬網(wǎng)卡:
運行:
總結(jié)
轉(zhuǎn)發(fā)是將連接到網(wǎng)絡(luò)交換機(jī)一個端口的設(shè)備的網(wǎng)絡(luò)流量傳遞到連接到交換機(jī)上另一個端口的另一個設(shè)備的過程。
當(dāng)?shù)?2 層以太網(wǎng)幀到達(dá)網(wǎng)絡(luò)交換機(jī)上的端口時,交換機(jī)會讀取以太網(wǎng)幀的源 MAC 地址作為學(xué)習(xí)功能的一部分,它還會讀取目標(biāo) MAC 地址作為轉(zhuǎn)發(fā)功能的一部分。目標(biāo) MAC 地址對于確定連接目標(biāo)設(shè)備的端口號很重要。如果在 MAC 地址表中找到目的 MAC 地址,則交換機(jī)通過 MAC 地址對應(yīng)的端口轉(zhuǎn)發(fā)以太網(wǎng)幀。
參考:
《TCP IP詳解卷一》
到此這篇關(guān)于C/C++詳解實現(xiàn)二層轉(zhuǎn)發(fā)的文章就介紹到這了,更多相關(guān)C語言二層轉(zhuǎn)發(fā)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C/C++ 中怎樣使用SetConsoleTextAttribute()函數(shù)來控制輸出字符的顏色
這篇文章主要介紹了C/C++ 中如何使用SetConsoleTextAttribute()函數(shù)來控制輸出字符的顏色,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03C語言創(chuàng)建動態(tài)dll和調(diào)用dll(visual studio 2013環(huán)境下)
本篇文章主要介紹了C語言創(chuàng)建動態(tài)dll和調(diào)用dll(visual studio 2013環(huán)境下),非常具有實用價值,需要的朋友可以參考下2017-11-11C++內(nèi)存四區(qū)之代碼區(qū)、全局區(qū)、棧區(qū)和堆區(qū)
C++編譯器會把代碼直接分為四個小區(qū),弄懂這四小區(qū)對我們理解內(nèi)存有所幫助,所以下面這篇文章主要給大家介紹了關(guān)于C++內(nèi)存四區(qū)之代碼區(qū)、全局區(qū)、棧區(qū)和堆區(qū)的相關(guān)資料,需要的朋友可以參考下2021-07-07