免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開(kāi)通VIP
使用socket BPF
第一次聽(tīng)說(shuō)socket BPF的東西是CTO說(shuō)sniffer要注意效率問(wèn)題,需要針對(duì)規(guī)則設(shè)定一定的過(guò)濾規(guī)則,這樣可以減少程序在用戶空間和內(nèi)核空間的切換。于是就去google那個(gè)東西了。不過(guò)結(jié)果并不是很理想的,似乎研究這個(gè)的人不多。從方方面面的情況看,似乎用libpcap庫(kù)設(shè)置BPF的過(guò)濾器是比較容易的,但是我的機(jī)器并沒(méi)有裝libpcap,man了半天就是沒(méi)有東西,呵呵。不過(guò)折騰了一下也是弄出來(lái)了,那都是大半年前的事情了。今天寫程序又用到BPF了,突然想到應(yīng)用過(guò)程當(dāng)中有一個(gè)邏輯問(wèn)題,所以就想順便寫點(diǎn)什么吧。如果你不想裝libpcap庫(kù),又想折騰BPF,看這篇文章就對(duì)了。不過(guò),如果你是打算空手套白狼,不會(huì)用tcpdump,或者想從頭學(xué)怎么寫B(tài)PF規(guī)則,那我還沒(méi)有鉆研得那么深,咱們可以以后討論討論,呵呵。
    設(shè)置BPF過(guò)濾器是通過(guò)setsockopt調(diào)用來(lái)完成的,格式如下:
    setsockopt(sd, SOL_SOCKET, SO_ATTACH_FILTER, &Filter, sizeof(Filter));
    這個(gè)調(diào)用的格式大家都很熟悉了,不清楚的在參數(shù)Filter的設(shè)置上。Filter的定義是struct sock_fprog Filter; 此結(jié)構(gòu)在linux/filter.h當(dāng)中有定義:
struct sock_fprog       /* Required for SO_ATTACH_FILTER. */
{
        unsigned short          len;    /* Number of filter blocks */
        struct sock_filter      *filter;
};

    其中的filter指針指向結(jié)構(gòu)為struct sock_filter的BPF過(guò)濾代碼。結(jié)構(gòu)同樣也在同一個(gè)文件當(dāng)中定義:
struct sock_filter      /* Filter block */
{
        __u16   code;   /* Actual filter code */
        __u8    jt;     /* Jump true */
        __u8    jf;     /* Jump false */
        __u32   k;      /* Generic multiuse field */
};

    其實(shí)我們并不關(guān)心如何具體的編寫struct sock_filter內(nèi)的東西,因?yàn)閠cpdump已經(jīng)內(nèi)置了這樣的功能。例如,想要對(duì)所接受的數(shù)據(jù)包過(guò)濾,只想接收udp數(shù)據(jù)包,那么在tcpdump當(dāng)中的命令就是tcpdump udp。如果你想讓tcpdump幫你編譯這樣的過(guò)濾器,則用tcpdump udp -d,可以得到輸出:
[root@Kernel26 root]# tcpdump udp -d
(000) ldh      [12]
(001) jeq      #0x86dd          jt 2    jf 4
(002) ldb      [20]
(003) jeq      #0x11            jt 7    jf 8
(004) jeq      #0x800           jt 5    jf 8
(005) ldb      [23]
(006) jeq      #0x11            jt 7    jf 8
(007) ret      #96
(008) ret      #0
    瞧,這就是BPF的代碼了,看不懂吧@_@,其實(shí)挺像匯編的,琢磨一下就會(huì)了,ld開(kāi)頭的表示加載某地址數(shù)據(jù),jeq是比較啦,jt就是jump when true,jf呢就是jump when false,后面表示行號(hào)。不過(guò)這樣的東西用在程序里還是不習(xí)慣,再用tcpdump udp -dd,可以得到:
[root@Kernel26 root]# tcpdump udp -dd
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 2, 0x000086dd },
{ 0x30, 0, 0, 0x00000014 },
{ 0x15, 3, 4, 0x00000011 },
{ 0x15, 0, 3, 0x00000800 },
{ 0x30, 0, 0, 0x00000017 },
{ 0x15, 0, 1, 0x00000011 },
{ 0x6, 0, 0, 0x00000060 },
{ 0x6, 0, 0, 0x00000000 },
    哈哈,這個(gè)像什么?像c當(dāng)中的數(shù)組的定義吧。不錯(cuò),這個(gè)就是過(guò)濾udp包的struct sock_filter的數(shù)組代碼。把這部分復(fù)制到程序當(dāng)中,將Filter.filter指向這個(gè)數(shù)組,F(xiàn)ilter.len設(shè)置長(zhǎng)度,就可以用setsockopt設(shè)置過(guò)濾器了。
    不過(guò)使用這樣的過(guò)濾器還是有一些需要注意的問(wèn)題的,例如,設(shè)置一個(gè)過(guò)濾器,只允許兩個(gè)源MAC地址的數(shù)據(jù)包進(jìn)入,我們先用:
[root@Kernel26 root]# tcpdump ether src 01:02:03:04:05:06 or ether src 04:05:06:07:08:09 -dd
{ 0x20, 0, 0, 0x00000008 },
{ 0x15, 0, 2, 0x03040506 },
{ 0x28, 0, 0, 0x00000006 },
{ 0x15, 3, 4, 0x00000102 },
{ 0x15, 0, 3, 0x06070809 },
{ 0x28, 0, 0, 0x00000006 },
{ 0x15, 0, 1, 0x00000405 },
{ 0x6, 0, 0, 0x00000060 },
{ 0x6, 0, 0, 0x00000000 },
    生成模板,我們注意到第2、4行比較了第一個(gè)MAC地址,第5、7行比較了第二個(gè)MAC地址,所以我們只需要在我們的程序當(dāng)中動(dòng)態(tài)的改變這四行當(dāng)中的數(shù)值就可以了,例如:
SetFilter(char *mac1, char *mac2)
{
        struct sock_filter code[]={
        { 0x20, 0, 0, 0x00000008 },
        { 0x15, 0, 2, ntohl(*(unsigned int *)(mac1 + 2)) },
        { 0x28, 0, 0, 0x00000006 },
        { 0x15, 3, 4, ntohs(*(unsigned short *)mac1) },
        { 0x15, 0, 3, ntohl(*(unsigned int *)(mac2 + 2)) },
        { 0x28, 0, 0, 0x00000006 },
        { 0x15, 0, 1, ntohs(*(unsigned short *)mac2) },
        { 0x6, 0, 0, 0x00000060 },
        { 0x6, 0, 0, 0x00000000 }
        };
...
}
    這里,需要用ntohl/ntohs等函數(shù)將網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)換為主機(jī)字節(jié)序。但是這段代碼是有邏輯問(wèn)題的。它首先比較第一個(gè)mac地址的后4個(gè)字節(jié),如果不正確轉(zhuǎn)入比較第二個(gè)mac地址,如果正確轉(zhuǎn)入比較第一個(gè)mac地址的高2個(gè)字節(jié)。因此,如果打算將這個(gè)代碼用作通用的mac比較,那么在輸入的兩個(gè)mac地址后4字節(jié)都相同的情況下就會(huì)出現(xiàn)邏輯覆蓋錯(cuò)誤,即無(wú)法對(duì)滿足第二個(gè)mac地址的條件進(jìn)行判斷。因此在這種情況下必須要準(zhǔn)備兩段比較代碼,根據(jù)情況進(jìn)行設(shè)置。具體不再累述。
    此外,這段BPF代碼還存在的一個(gè)問(wèn)題是,一般情況下tcpdump只返回所捕獲包的頭96字節(jié),也就是0x60字節(jié),可見(jiàn)代碼的倒數(shù)第二行是ret #96。對(duì)于需要完整的包處理還是不行的,因此你需要將其設(shè)置為0x0000ffff,或者在用tcpdump生成的時(shí)候用tcpdump -s 65535 -dd ... 來(lái)生成。
    最后,用tcpdump生成的BPF代碼只能用于SOCK_RAW的socket,這類socket是可以直接操作數(shù)據(jù)鏈路層的,如果你打算將BPF用于ip層等較高層次的socket,那么你需要手工修改部分行的code.k,也就是修改如ldh [12]當(dāng)中的[12]這個(gè)數(shù)值,因?yàn)檫@個(gè)數(shù)值的偏移量是按照從鏈路層開(kāi)始計(jì)算得到的,在沒(méi)有鏈路層之后,這個(gè)值就發(fā)生了變化,這個(gè)是需要注意的。

參考資料:《Linux下Sniffer程序的實(shí)現(xiàn)》作者:Gianluca Insolvibile,
http://www.nsfocus.net/index.php?act=magazine&do=view&mid=1797



Trackback: http://tb.donews.net/TrackBack.aspx?PostId=173266

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Linux下Libpcap源碼分析和包過(guò)濾機(jī)制
linux socket
自己動(dòng)手寫網(wǎng)絡(luò)抓包工具
網(wǎng)絡(luò)協(xié)議棧入門知識(shí)
編寫端口掃描器(C++)
IP報(bào)文頭結(jié)構(gòu)體
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服