最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

詳細講解Linux內(nèi)核角度分析tcpdump原理(2)

2022-10-20 20:50 作者:補給站Linux內(nèi)核  | 我要投稿

詳細講解Linux內(nèi)核角度分析tcpdump原理(1)介紹了在內(nèi)核角度tcpdump的抓包原理(1),主要流程如下:

  • 應(yīng)用層通過libpcap庫:調(diào)用系統(tǒng)調(diào)用創(chuàng)建socket,sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));tcpdump在socket創(chuàng)建過程中創(chuàng)建packet_type(struct packet_type),并掛載到全局的ptype_all鏈表上。(同時在packet_type設(shè)置回調(diào)函數(shù)packet_rcv。

  • 網(wǎng)絡(luò)收包/發(fā)包時,會在各自的處理函數(shù)(收包時:__netif_receive_skb_core,發(fā)包時:dev_queue_xmit_nit)中遍歷ptype_all鏈表,并同時執(zhí)行其回調(diào)函數(shù),這里tcpdump的注冊的回調(diào)函數(shù)就是packet_rcv。

  • packet_rcv函數(shù)中會將用戶設(shè)置的過濾條件,通過BPF進行過濾,并將過濾的數(shù)據(jù)包添加到接收隊列中。

  • 應(yīng)用層調(diào)用recvfrom 。PF_PACKET 協(xié)議簇模塊調(diào)用packet_recvmsg 將接收隊列中的數(shù)據(jù)copy應(yīng)用層,到此將數(shù)據(jù)包捕獲到。

本文圍繞的重點是:BPF的過濾原理,如下源碼所示:run_filter(skb, sk, snaplen),本次文章將對BPF的過濾原理進行一些分析。

tcpdump依附標準的的BPF機器,tcpdump的過濾規(guī)則會被轉(zhuǎn)化成一段bpf指令并加載到內(nèi)核中的bpf虛擬機器上執(zhí)行,顯然,由用戶來寫過濾代碼太過復(fù)雜,因此 libpcap 允許用戶書寫高層的、容易理解的過濾字符串,然后將其編譯為BPF代碼,tcpdump自動完成,不為用戶所見。

一、BPF匯編指令集

BPF指令集

是一個偽機器碼,與能夠在物理機上直接執(zhí)行的機器碼不同,BPF指令集是可以在BPF虛擬機上執(zhí)行的指令集。bpf在內(nèi)核中實際就是一個虛擬機,有自己定義的虛擬機寄存器組。在最早的cBPF匯編框架中的三種寄存器:

在cBPF每條匯編指令如下這種格式:

我們最常見的用法莫過于從數(shù)據(jù)包中取某個字的數(shù)據(jù)來做判斷。按照bpf的規(guī)定,我們可以使用偏移來指定數(shù)據(jù)包的任何位置,而很多協(xié)議很常用并且固定,例如端口和ip地址等,bpf就為我們提供了一些預(yù)定義的變量,只要使用這個變量就可以直接取值到對應(yīng)的數(shù)據(jù)包位置。例如:?

cBPF在一些平臺還在使用,這個代碼就和用戶空間使用的那種匯編是一樣的,但是在X86架構(gòu),現(xiàn)在在內(nèi)核態(tài)已經(jīng)都切換到使用eBPF作為中間語言了。由于用戶可以提交cBPF的代碼,所以首先是將用戶提交來的結(jié)構(gòu)體數(shù)組進行編譯成eBPF代碼(提交的是eBPF就不用了)。然后再將eBPF代碼轉(zhuǎn)變?yōu)榭芍苯訄?zhí)行的二進制。eBPF匯編框架下的bpf語句如下:

tcpdump -d

tcpdump支持使用-d參數(shù)來顯示過濾規(guī)則轉(zhuǎn)換后的bpf匯編指令。在抓包時我們并不關(guān)心如何具體的編寫struct sock_filter內(nèi)的東西,因為tcpdump已經(jīng)內(nèi)置了這樣的功能。如想要對所接受的數(shù)據(jù)包過濾,只想抓取TCP協(xié)議、端口為8080數(shù)據(jù)包,那么在tcpdump當中的命令就是tcpdump ip and tcp port 8080 。如果你想讓tcpdump幫你編譯這樣的過濾器,則用tcpdump -d 'ip and tcp port 8080',如下案例(參考《Linux內(nèi)核觀測技術(shù)BPF》)如下圖所示,顯示“tcpdump抓取tcp端口8080數(shù)據(jù)包”的bpf匯編指令:



為了進一步分析這條案例的流程,先把數(shù)據(jù)包的幀格式和ip數(shù)據(jù)報的格式放下面便于分析:

以太網(wǎng)幀格式:



【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個人覺得比較好的學習書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。。ê曨l教程、電子書、實戰(zhàn)項目及代碼)??


001-003條bpf匯編指令進行解釋:

(000) ldh [12]:

ldh指令表示累加器在偏移量12處進行加載一個半字(16位),從以太網(wǎng)幀的格式中可以看到偏移量為12字節(jié)處為以太網(wǎng)類型字段。

(001) jeq #0x800 jt 2 jf 12:

jeq指令bioassay如果相等則跳轉(zhuǎn),也就是檢查上一條指令返回的以太網(wǎng)類型的值是否為ox800(ipv4的標識),如果為true(jt),就跳轉(zhuǎn)到指令2,否則跳轉(zhuǎn)到指令12。

(002) ldb [23]:

ldb指令在偏移量23字節(jié)處進行加載(計算一下:以太網(wǎng)幀的頭部是14個字節(jié),那么第23個字節(jié),也就是IP頭部的第9個字節(jié)),根據(jù)IP數(shù)據(jù)報的格式可以看到第9個字節(jié)是“協(xié)議”字段。

(003) jeq #0x6 jt 4 jf 12 :

jeq指令根據(jù)第9個字節(jié)的值進行再一次的判斷和跳轉(zhuǎn),如果第9個字節(jié)“協(xié)議字段”為0x6(TCP),如果是TCP則跳轉(zhuǎn)到下一條指令004,否則跳轉(zhuǎn)到012,數(shù)據(jù)包進行丟棄。

上面的規(guī)則對應(yīng)代碼結(jié)構(gòu)體在Linux內(nèi)核中的表示其實就是struct sock_filter,在libpcap庫中對應(yīng)的結(jié)構(gòu)體為struct bpf_insn

tcpdump -dd

上述使用tcpdump -d看到了過濾規(guī)則轉(zhuǎn)換后的bpf匯編指令,上面幾個指令:ld開頭的表示加載某地址數(shù)據(jù),jeq是比較,jt就是jump when true,jf就是jump when false,后面表示行號;tcpdump支持使用-dd參數(shù)將匹配信息包的代碼以c語言程序段的格式給出:



像c當中的數(shù)組的定義,這個就是過濾tcp8080數(shù)據(jù)包的struct sock_filter的數(shù)組代碼。

二、tcpdump設(shè)置BPF過濾器

在libpcap 設(shè)置過濾規(guī)則用到了兩個接口,pcap_compile()和 pcap_setfilter ()

pcap_compile 函數(shù)的主要工作就是創(chuàng)建一個bpf的結(jié)構(gòu)體,后面pcap_setfilter 會把生產(chǎn)的規(guī)則設(shè)置到內(nèi)核,讓規(guī)則生效。

struct pcap

在進行分析pcap_compile()和 pcap_setfilter ()前,先介紹一個結(jié)構(gòu)體:struct pcap,介紹后面的過程便于查閱該結(jié)構(gòu)體的成員變量,該結(jié)構(gòu)體在libpcap源碼的pcap-int.h中定義,該結(jié)構(gòu)體抓包過程的一個句柄。


pcap_compile

pcap_setfilter

函數(shù)原型:

調(diào)用pcap_setfilter_linux:

進一步調(diào)用pcap_setfilter_linux_common:

上面涉及到的Linux內(nèi)核中的struct sock_fprog和libpcap庫中的struct bpf_program如下所示:

struct sock_fprog { ? /* Required for SO_ATTACH_FILTER. */ ?unsigned short ? ? len; /* Number of filter blocks */ ?struct sock_filter __user *filter; }; struct bpf_program { ?u_int bf_len; ?struct bpf_insn *bf_insns;//該結(jié)構(gòu)體上面介紹過,相當于Linux內(nèi)核中的struct sock_filte };

install_bpf_program(handle, filter)的拷貝過程:

pcap_setfilter_linux_common最終會在set_kernel_filter中調(diào)用setsockopt系統(tǒng)調(diào)用(執(zhí)行到這才真正進入內(nèi)核,開始在Linux內(nèi)核上安裝和設(shè)置BPF過濾器),通過SO_ATTACH_FILTER 下發(fā)給內(nèi)核底層,從而讓規(guī)則生效,設(shè)置過濾器。

在liunx上,只需要簡單的創(chuàng)建的filter代碼,通過SO_ATTTACH_FILTER選項發(fā)送到內(nèi)核,并且filter代碼能通過內(nèi)核的檢查,這樣你就可以立即過濾socket上面的數(shù)據(jù)了。

三、setsockopt()

Linux 在安裝和卸載過濾器時都使用了函數(shù) setsockopt(),其中標志SOL_SOCKET 代表了對 socket 進行設(shè)置,而 SO_ATTACH_FILTER 和 SO_DETACH_FILTER 則分別對應(yīng)了安裝和卸載。

  • 在套接字socket 附加filter規(guī)則 :

setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &val, sizeof(val));

  • ·把filter從socket上移除 :

setsockopt(sockfd, SOL_SOCKET, SO_DETACH_FILTER, &val, sizeof(val));

Linux內(nèi)核在sock_setsockopt函數(shù)中進行設(shè)置:

上面出現(xiàn)的 sk_attach_filter() 定義在 net/core/filter.c,它把結(jié)構(gòu)sock_fprog 轉(zhuǎn)換為結(jié)構(gòu) sk_filter, 最后把此結(jié)構(gòu)設(shè)置為 socket 的過濾器:sk->filter = fp。

回到文章開始(抓包的引入):

run_filter:

綜上,結(jié)合上一篇,文章和本文就將Linux內(nèi)核角度將tcpdump的工作原理分析完畢。





詳細講解Linux內(nèi)核角度分析tcpdump原理(2)的評論 (共 條)

分享到微博請遵守國家法律
泉州市| 孟津县| 康定县| 耒阳市| 蓝田县| 乌鲁木齐县| 苏尼特右旗| 江油市| 班戈县| 建平县| 祥云县| 五大连池市| 工布江达县| 宜州市| 长丰县| 浏阳市| 松阳县| 磐安县| 乌苏市| 巴彦淖尔市| 永和县| 方正县| 田东县| 永兴县| 江津市| 仁寿县| 栾川县| 鄯善县| 丰顺县| 塔河县| 郯城县| 宁夏| 新昌县| 运城市| 启东市| 荥阳市| 化德县| 萨迦县| 萨嘎县| 陆河县| 汽车|