• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-162  評論-223  文章-30  trackbacks-0
             
            描述
               攔截Linux動態(tài)庫API的常規(guī)方法,是基于動態(tài)符號鏈接覆蓋技術(shù)實現(xiàn)的,基本步驟是
                1. 重命名要攔截的目標(biāo)動態(tài)庫。
                2. 創(chuàng)建新的同名動態(tài)庫,定義要攔截的同名API,在API內(nèi)部調(diào)用原動態(tài)庫對應(yīng)的API。這里的同名是指與重命名前動態(tài)庫前的名稱相同。
               顯而易見,如果要攔截多個不同動態(tài)庫中的API,那么必須創(chuàng)建多個對應(yīng)的同名動態(tài)庫,這樣一來不僅繁瑣低效,還必須被優(yōu)先鏈接到客戶二進(jìn)制程序中(根據(jù)動態(tài)庫鏈接原理,對重復(fù)ABI符號的處理是選擇優(yōu)先鏈接的那個動態(tài)庫)。 另外在鉤子函數(shù)的實現(xiàn)中,若某調(diào)用鏈調(diào)用到了原API,則會引起死循環(huán)而崩潰。本方法通過直接修改ELF文件中的動態(tài)庫API入口表項,解決了常規(guī)方法的上述問題。

            特點
               1. 不依賴于動態(tài)庫鏈接順序。
               2. 能攔截多個不同動態(tài)庫中的多個API。
               3. 支持運行時動態(tài)鏈接的攔截。
               4. 鉤子函數(shù)內(nèi)的實現(xiàn)體,若調(diào)用到原API,則不會死循環(huán)。


            實現(xiàn)
               攔截映射表
                  為了支持特點2和3,建立了一個攔截映射表,這個映射表有2級。第1級為ELF文件到它的API鉤子映射表,鍵為ELF文件句柄,值為API鉤子映射表;第2級為API到它的鉤子函數(shù)映射表,鍵為API名稱,值為包含最老原函數(shù)地址和最新鉤子函數(shù)地址的結(jié)構(gòu)體,如下圖
                  當(dāng)最先打開ELF文件成功時,會在第1級映射表中插入記錄;反之當(dāng)最后關(guān)閉同一ELF文件時,就會從中移除對應(yīng)的記錄。當(dāng)?shù)谝淮螔煦^動態(tài)庫API時,就會在第2級映射表插入記錄;反之卸鉤同一API時,就會從中刪除對應(yīng)的記錄。

               計算ELF文件的映像基地址
                  計算映像基地址是為了得到ELF中動態(tài)符號表和重定位鏈接過程表的內(nèi)容,因為這些表的位置都是相對于基地址的偏移量,該算法在打開ELF文件時執(zhí)行,如下圖
                  EXE文件為可執(zhí)行文件,DYN文件為動態(tài)庫。對于可執(zhí)行文件,映射基地址為可執(zhí)行裝載段的虛擬地址;對于動態(tài)庫,可通過任一API的地址減去它的偏移量得到,任一API的地址可通過調(diào)用libdl.so庫API dlsym得到,偏移量通過查詢動態(tài)鏈接符號表得到。

               打開ELF文件
                  為了支持特點2即攔截不同動態(tài)庫的多個API,節(jié)省每次掛鉤API前要打開并讀文件的開銷,獨立提供了打開ELF文件的接口操作,流程如下圖
                  若輸入ELF文件名為空,則表示打開當(dāng)前進(jìn)程的可執(zhí)行文件,此時要從偽文件系統(tǒng)/proc/self/exe讀取文件路徑名,以正確調(diào)用系統(tǒng)調(diào)用open。當(dāng)同一ELF文件被多次打開時,只須遞增結(jié)構(gòu)elf的引用計數(shù)。

               掛鉤API
                  當(dāng)打開ELF文件后,就可掛鉤API了,流程如下圖
                  當(dāng)?shù)谝淮螔煦^時,需要保存原函數(shù)以供后面卸鉤;第二次以后繼續(xù)掛鉤同一API時,更新鉤子函數(shù),但原函數(shù)不變。   
               
               卸鉤API
                  當(dāng)打開ELF文件后,就可卸鉤API了,流程如下圖

               關(guān)閉ELF文件
                  因為提供了打開ELF文件的接口操作,所以得配有關(guān)閉ELF文件的接口操作。當(dāng)不需要掛鉤API的時候,就可以關(guān)閉ELF文件了,流程如下圖


            運行時動態(tài)攔截裝置
               在初始化模塊中打開當(dāng)前可執(zhí)行文件,掛鉤libdl.so庫的API dlopen和dlsym;在轉(zhuǎn)換模塊中,按動態(tài)庫句柄和API名稱在攔截映射表中查找鉤子函數(shù),若找到則返回鉤子函數(shù),否則返回調(diào)用dlsym的結(jié)果;在銷毀模塊中,卸鉤dlopen和dlsym。
            當(dāng)動態(tài)庫被進(jìn)程加載的時候,會調(diào)用初始化模塊;當(dāng)被進(jìn)程卸載或進(jìn)程退出的時候,會調(diào)用銷毀模塊;當(dāng)通過dlsym調(diào)用API時,則會在dlsym的鉤子函數(shù)中調(diào)用轉(zhuǎn)換模塊。通過環(huán)境變量LD_PRELOAD將動態(tài)庫libhookapi.so設(shè)為預(yù)加載庫,這樣就能攔截到所有進(jìn)程對dlopen及dlsym的調(diào)用,進(jìn)而攔截到已掛鉤動態(tài)庫API的調(diào)用。
            posted @ 2016-08-25 11:10 春秋十二月 閱讀(2293) | 評論 (0)編輯 收藏
               本方法適用于linux 2.6.x內(nèi)核。

               1. 先獲取dentry所屬文件系統(tǒng)對應(yīng)的掛載點,基本原理是遍歷文件系統(tǒng)vfsmount樹,找到與dentry有相同超級塊的vfsmount,實現(xiàn)如下
             1extern spinlock_t *vfsmnt_lock;
             2
             3static struct vfsmount* next_mnt(struct vfsmount *p, struct vfsmount *root)
             4{
             5    struct list_head *next = p->mnt_mounts.next;
             6    if (next == &p->mnt_mounts) {
             7        while (1{
             8            if (p == root)
             9                return NULL;
            10            next = p->mnt_child.next;
            11            if (next != &p->mnt_parent->mnt_mounts)
            12                break;
            13            p = p->mnt_parent;
            14        }

            15    }

            16    return list_entry(next, struct vfsmount, mnt_child);
            17}

            18
            19static struct vfsmount* get_dentry_mnt(struct dentry *dentry)
            20{
            21    struct vfsmount *p, *root;
            22    struct fs_struct *fs = current->fs;            
            23
            24    read_lock(&fs->lock);
            25    root = fs->root.mnt;
            26    mntget(root);
            27    read_unlock(&fs->lock);
            28
            29    spin_lock(vfsmnt_lock);
            30    for(p = root; p; p = next_mnt(p,root)){
            31        if(p->mnt_sb == dentry->d_sb){
            32            mntget(p);
            33            break;    
            34        }

            35    }

            36    spin_unlock(vfsmnt_lock);
            37
            38    mntput(root);
            39    
            40    return p;
            41}
               next_mnt函數(shù)實現(xiàn)了先根遍歷法,遍歷以root為根的文件系統(tǒng)掛載點,p為遍歷過程中的當(dāng)前結(jié)點,返回p的下一個掛載點;vfsmnt_lock可通過內(nèi)核函數(shù)kallsyms_on_each_symbol或kallsyms_lookup_name查找獲得。

               2. 再調(diào)用內(nèi)核函數(shù)d_path,接口封裝如下
             1char* get_dentry_path(struct dentry *dentry,char *buf,int len)
             2{
             3    char *= "";    
             4    struct vfsmount *mnt = get_dentry_mnt(dentry);
             5    
             6    if(mnt){
             7        struct path ph = {.dentry = dentry, .mnt = mnt};
             8        p = d_path(&ph,buf,len);
             9        if(IS_ERR(p))
            10            p = "";
            11        mntput(mnt);
            12    }

            13    
            14    return p;
            15}
            posted @ 2016-08-24 19:22 春秋十二月 閱讀(5892) | 評論 (0)編輯 收藏
            描述
               原始套接字具有廣泛的用途,特別是用于自定義協(xié)議(標(biāo)準(zhǔn)協(xié)議TCP、UDP和ICMP等外)的數(shù)據(jù)收發(fā)。在Linux下攔截套接字IO的一般方法是攔截對應(yīng)的套接字系統(tǒng)調(diào)用,對于發(fā)送為sendmsg和sendto,對于接收為recvmsg和recvfrom。這種方法雖然也能攔截原始套接字IO,但要先判斷套接字的類型,如果為SOCK_RAW(原始套接字類型),那么進(jìn)行攔截處理,這樣一來由于每次IO都要判斷套接字類型,性能就比較低了。因此為了直接針對原始套接字來攔截,提高性能,發(fā)明了本方法。
               本方法可用于防火墻或主機(jī)防護(hù)系統(tǒng)中,丟棄接收和發(fā)送的攻擊或病毒數(shù)據(jù)包。

            特點
               運行在內(nèi)核態(tài),直接攔截所有進(jìn)程的原始套接字IO,支持IPv4和IPv6。


            實現(xiàn)
               原理
                  在Linux內(nèi)核網(wǎng)絡(luò)子系統(tǒng)中,struct proto_ops結(jié)構(gòu)提供了協(xié)議無關(guān)的套接字層到協(xié)議相關(guān)的傳輸層的轉(zhuǎn)接,而IPv4協(xié)議族中內(nèi)置的inet_sockraw_ops為它的一個實例,對應(yīng)著原始套接字。因此先找到inet_sockraw_ops,再替換它的成員函數(shù)指針recvmsg和sendmsg,就可以實現(xiàn)攔截了。下面以IPv4為例(IPv6同理),說明幾個流程。

               搜索inet_sockraw_ops
                  該流程在掛鉤IO前進(jìn)行。由于inet_sockraw_ops為Linux內(nèi)核未導(dǎo)出的內(nèi)部符號,因此需要通過特別的方法找到它,該特別的方法基于這樣的一個事實:
                   所有原始套接字接口均存放在以SOCK_RAW為索引的雙向循環(huán)鏈表中,而inet_sockraw_ops就在該鏈表的末尾。
                   內(nèi)核提供了注冊套接字接口的API inet_register_protosw,對于原始套接字類型,該API將輸入的套接字接口插入到鏈表頭后面。
                  算法如下
                  
                  注冊p前或注銷p后,鏈表如下
                  注冊p后,鏈表如下

               掛鉤IO
                  該流程在內(nèi)核模塊啟動時進(jìn)行。

               卸鉤IO
                  該流程在內(nèi)核模塊退出時進(jìn)行。


            運行部署

               該方法實現(xiàn)在Linux內(nèi)核模塊中,為了防止其它內(nèi)核模塊可能也注冊了原始套接字接口,因此需要在操作系統(tǒng)啟動時優(yōu)先加載。  
            posted @ 2016-07-14 10:27 春秋十二月 閱讀(2665) | 評論 (3)編輯 收藏
            描述
               TCP連接跟蹤是網(wǎng)絡(luò)流控和防火墻中的一項重要的基礎(chǔ)技術(shù),當(dāng)運用于主機(jī)時,連接必與進(jìn)程相關(guān)聯(lián),要么是主動發(fā)出的,要么是被動接受的,當(dāng)后代進(jìn)程被動態(tài)創(chuàng)建時,由于文件描述符的繼承,一個連接就會被這個進(jìn)程樹中的所有進(jìn)程共享;當(dāng)一個進(jìn)程發(fā)出或接受多個連接時,就擁有了多個連接。本方法可用于網(wǎng)絡(luò)安全產(chǎn)品中,監(jiān)控TCP連接及所屬進(jìn)程,能準(zhǔn)確并動態(tài)地知道一個連接被哪些進(jìn)程共享,一個進(jìn)程擁有哪些連接。

            特點

               操作系統(tǒng)自帶的netstat工具只是關(guān)聯(lián)到了一個根進(jìn)程,無法看到擁有該連接的所有進(jìn)程,查看進(jìn)程擁有的全部連接也不方便。該方法的特點是實時跟蹤、查看連接與進(jìn)程相關(guān)信息方便、支持連接的管控。


            實現(xiàn)

               本方法通過內(nèi)核安全的十字鏈表實現(xiàn)了連接與進(jìn)程的相關(guān)性,連接信息結(jié)構(gòu)體含有一個所屬進(jìn)程鏈表頭,進(jìn)程信息結(jié)構(gòu)體含有一個擁有連接鏈表頭,通過十字鏈表結(jié)點鏈接,x方向鏈接到進(jìn)程的連接鏈表,y方向鏈接到連接的進(jìn)程鏈表,如下圖所示
               進(jìn)程1為根進(jìn)程,進(jìn)程2,...,進(jìn)程n為進(jìn)程1的后代進(jìn)程;連接1,連接2,...,連接n為進(jìn)程1產(chǎn)生的連接。node(x,y)為十字鏈表結(jié)點,用于關(guān)聯(lián)連接與進(jìn)程,x對應(yīng)進(jìn)程編號,y對應(yīng)連接編號,每個node包含了所屬的連接和進(jìn)程指針,每行和每列都是一個雙向循環(huán)鏈表(循環(huán)未畫出),每個鏈表用一個自旋鎖同步操作。
               動態(tài)跟蹤的過程包括4個方面:進(jìn)程創(chuàng)建、進(jìn)程退出、連接產(chǎn)生、連接銷毀。在Linux下,可通過攔截內(nèi)核函數(shù)do_fork掛鉤進(jìn)程創(chuàng)建,攔截do_exit掛鉤進(jìn)程退出;可通過攔截inet_stream_ops的成員函數(shù)connect和accept掛鉤連接產(chǎn)生,攔截成員函數(shù)release掛鉤連接銷毀。下面為4個方面對應(yīng)的流程圖,由于所有外層加鎖前已禁止本地中斷和內(nèi)核搶占,因此內(nèi)層加鎖前就不必再禁止本地中斷和內(nèi)核搶占了。

               進(jìn)程創(chuàng)建
               將copy_node插入到c的進(jìn)程鏈表末尾,即為y方向增加(下同);插入到p的連接鏈表末尾,為x方向增加(下同)。

               進(jìn)程退出
               從c的進(jìn)程鏈表中移除node,即為y方向移除(下同);再從p的連接鏈表中移除node,即為x方向移除(下同)。


               連接產(chǎn)生
                  當(dāng)進(jìn)程發(fā)出連接或接受連接時,調(diào)用此流程。

               連接銷毀
                  當(dāng)某個進(jìn)程銷毀連接時,調(diào)用此流程。
            posted @ 2016-07-13 11:24 春秋十二月 閱讀(1549) | 評論 (0)編輯 收藏
            描述
               在P2P應(yīng)用系統(tǒng)中,當(dāng)需要與處于不同私網(wǎng)的對方可靠通信時,先嘗試TCP打洞穿透,若穿透失敗,再通過處于公網(wǎng)上的代理服務(wù)器(下文簡稱proxy)轉(zhuǎn)發(fā)與對方通信,如下圖所示  
               終端A先連接并發(fā)消息msg1到proxy(連接為c1);proxy再發(fā)消息msg2給P2P服務(wù)器,P2P服務(wù)器收到消息后通過已有的連接發(fā)消息msg3給終端B,B收到msg3后,連接并發(fā)消息msg4到proxy(連接為c2)。這4個消息格式由應(yīng)用層協(xié)議決定,但必須遵守的規(guī)范如下:
                msg1至少包含B的設(shè)備ID。
                msg2至少包含B的設(shè)備ID和c1的連接ID。
                msg3至少包含c1的連接ID和連接代理指示。
                msg4至少包含B的設(shè)備ID和c1的連接ID。
               proxy為多線程架構(gòu),當(dāng)接受到若干連接時,如果數(shù)據(jù)相互轉(zhuǎn)發(fā)的兩個連接(比如上圖中的c1和c2)不在同一線程,由于一個連接寫數(shù)據(jù)到另一連接的發(fā)送隊列,而另一連接從發(fā)送隊列讀數(shù)據(jù)以發(fā)送,那么就要對另一連接的發(fā)送隊列(或緩沖區(qū))加鎖,這樣一來由于頻繁的網(wǎng)絡(luò)IO而頻繁地加解鎖,降低了轉(zhuǎn)發(fā)效率,因此為了解決這一問題,就需要調(diào)度TCP連接到同一線程。


            特點
               本方法能將數(shù)據(jù)轉(zhuǎn)發(fā)的兩邊連接放在同一線程,從而避免了數(shù)據(jù)轉(zhuǎn)發(fā)時的加鎖,由于是一對一的連接匹配,因此也做到了每個線程中連接數(shù)的均衡。


            實現(xiàn)
               工作原理
                  proxy的主線程負(fù)責(zé)綁定知名端口并監(jiān)聽連接,工作線程負(fù)責(zé)數(shù)據(jù)轉(zhuǎn)發(fā)。當(dāng)接受到一個連接時,按輪轉(zhuǎn)法調(diào)度它到某個工作線程,在那個線程內(nèi)接收分析應(yīng)用層協(xié)議數(shù)據(jù),以識別連接類型,即判斷連接是來自數(shù)據(jù)請求方還是數(shù)據(jù)響應(yīng)方,為統(tǒng)一描述,這里把前者特稱為客戶連接,后者為服務(wù)連接,連接所在的線程為宿主線程。如果是客戶連接,那么先通知P2P服務(wù)器請求對應(yīng)的客戶端來連接代理,并等待匹配;如果是服務(wù)連接,那么就去匹配客戶連接,在匹配過程中,如果服務(wù)連接和客戶連接不在同一線程內(nèi),那么就會調(diào)度到客戶連接的宿主線程,匹配成功后,就開始轉(zhuǎn)發(fā)數(shù)據(jù)。
                  為了加快查找,分2個hash表存放連接,客戶連接放在客戶連接hash表中,以連接ID為鍵值;服務(wù)連接放在服務(wù)連接hash表中,以設(shè)備ID為鍵值。

               TCP連接調(diào)度
                  包括新連接的輪轉(zhuǎn)、識別連接類型、匹配客戶連接1、匹配客戶連接2和關(guān)閉連接共5個流程,如下一一所述。
                  新連接的輪轉(zhuǎn)
                     該流程工作在主線程,如下圖所示
                  索引i初始為0,對于新來的連接,由于還不明確連接類型,所以先放入客戶連接表中。

                  識別連接類型
                     該流程工作在工作線程,當(dāng)接受到一個連接時開始執(zhí)行,如下圖所示
                  當(dāng)連接類型為服務(wù)連接時,從客戶連接表轉(zhuǎn)移到服務(wù)連接表。

                  匹配客戶連接1
                     該流程工作在工作線程,當(dāng)接受到一個服務(wù)連接時開始執(zhí)行,如下圖所示

                  匹配客戶連接2
                     該流程工作在工作線程,當(dāng)服務(wù)連接移到客戶連接的宿主線程時開始執(zhí)行,如下圖所示
                  這里的流程和匹配客戶連接流程1有些類似,看起來好像做了重復(fù)的判斷操作,但這是必要的,因為在服務(wù)連接轉(zhuǎn)移到另一線程這個瞬間內(nèi),客戶連接有可能斷開了,也有可能斷開后又來了一個相同連接ID的其它客戶連接,所以要重新去客戶連接表查找一次,然后進(jìn)行4個分支判斷。 
               
                  關(guān)閉連接
                     該流程工作在工作線程內(nèi),當(dāng)連接斷開或空閑時執(zhí)行。當(dāng)一邊讀數(shù)據(jù)出錯時,不能馬上關(guān)閉另一邊連接,得在另一邊緩沖區(qū)數(shù)據(jù)發(fā)送完后才能關(guān)閉;當(dāng)一邊連接寫數(shù)據(jù)出錯時,可以馬上關(guān)閉另一邊連接,如下圖所示
            posted @ 2016-07-12 16:59 春秋十二月 閱讀(1827) | 評論 (0)編輯 收藏
                 摘要:    為了使nginx支持windows服務(wù),本文闡述以下主要的改進(jìn)實現(xiàn)。ngx_main函數(shù)   為了在SCM服務(wù)中復(fù)用main函數(shù)的邏輯,將其重命名為ngx_main,并添加第3個參數(shù)is_scm以兼容控制臺運行方式,聲明在core/nginx.h中。    Code highligh...  閱讀全文
            posted @ 2016-07-12 15:31 春秋十二月 閱讀(4524) | 評論 (0)編輯 收藏
            結(jié)構(gòu)定義
             1 struct state_machine {
             2     int state;
             3     
             4 };
             5 
             6 enum { 
             7     s1,
             8     s2,
             9     
            10     sn
            11 };
               假設(shè)s1為初始狀態(tài),狀態(tài)變遷為s1->s2->...->sn。

            常規(guī)實現(xiàn) 
               狀態(tài)機(jī)處理函數(shù)state_machine_handle通常在一個循環(huán)內(nèi)或被事件驅(qū)動框架調(diào)用,輸入data會隨時序變化,從而引起狀態(tài)的變遷,偽代碼框架如下。
             1void handle_s1(struct state_machine *sm, void *data)
             2{
             3    //do something about state 1
             4    if(is_satisfy_s2(data))
             5        sm->state = s2;
             6}

             7
             8void handle_s2(struct state_machine *sm, void *data)
             9{
            10    //do something about state 2
            11    if(is_satisfy_s3(data))
            12        sm->state = s3;
            13}

            14
            15void handle_sn_1(struct state_machine *sm, void *data)
            16{
            17    //do something about state n-1
            18    if(is_satisfy_sn(data))
            19        sm->state = sn;
            20}

            21
            22void state_machine_handle(struct state_machine *sm, void *data)
            23{
            24    switch(sm->state){
            25        case s1:
            26            handle_s1(sm,data);
            27            break;
            28            
            29        case s2:
            30            handle_s2(sm,data);
            31            break;            
            32            
            33        case sn:
            34            handle_sn(sm,data);
            35            break;
            36    }

            37}
               sm->state初始化為s1。

            改進(jìn)實現(xiàn)
               為了免去丑陋的switch case分支結(jié)構(gòu),在state_machine內(nèi)用成員函數(shù)指針handler替代了state,改進(jìn)后的框架如下。
             1struct state_machine;
             2typedef void (*state_handler)(struct state_machine*void*);
             3
             4struct state_machine {
             5    state_handler handler;
             6    
             7}
            ;
             8
             9void handle_s1(struct state_machine *sm, void *data)
            10{
            11    //do something about state 1
            12    if(is_satisfy_s2(data))
            13        sm->handler = handle_s2;
            14}

            15
            16void handle_s2(struct state_machine *sm, void *data)
            17{
            18    //do something about state 2
            19    if(is_satisfy_s3(data))
            20        sm->handler = handle_s3;
            21}

            22
            23void handle_sn_1(struct state_machine *sm, void *data)
            24{
            25    //do something about state n-1
            26    if(is_satisfy_sn(data))
            27        sm->handler = handle_sn;
            28}

            29
            30void state_machine_handle(struct state_machine *sm, void *data)
            31{
            32    sm->handler(sm, data);
            33}
               sm->handler初始化為handle_s1,該方法在性能上應(yīng)略優(yōu)于常規(guī)方法,而且邏輯更清晰自然,非常適合于網(wǎng)絡(luò)流的處理,在nginx中分析http和email協(xié)議時,得到了廣泛應(yīng)用。
            posted @ 2016-05-05 09:46 春秋十二月 閱讀(4090) | 評論 (1)編輯 收藏
            腳本概述
               由于使用objdump反匯編linux內(nèi)核的輸出太多(2.6.32-220.el6.x86_64統(tǒng)計結(jié)果為1457706行),而很多時候只是想查看特定部分的機(jī)器碼與匯編指令,例如函數(shù)的入口、堆棧、調(diào)用了哪個函數(shù)等,為了高效和通用,因此編寫了一個簡單的awk腳本,其命令行參數(shù)說明如下:
               ● SLINE表示匹配的起始行號(不小于1),SPAT表示匹配的起始行模式,這兩個只能有一個生效,當(dāng)都有效時,以SLINE為準(zhǔn)。
               ● NUM表示從起始行開始的連續(xù)輸出行數(shù)(不小于1,含起始行),EPAT表示匹配的結(jié)束行模式,這兩個只能有一個生效,當(dāng)都有效時,以NUM為準(zhǔn)。

            腳本實現(xiàn)
               檢查傳值
               由于向腳本傳入的值在BEGIN塊內(nèi)沒生效,在動作塊{}和END塊內(nèi)有效,但若在{}內(nèi)進(jìn)行檢查則太低效,因為處理每條記錄都要判斷,所以為了避免在{}內(nèi)進(jìn)行多余的判斷,就在BEGIN塊內(nèi)解析命令行參數(shù)來間接獲得傳值,當(dāng)傳值無效時,給出提示并退出。
             1for(k=1;k<ARGC;++k){
             2        str=ARGV[k]
             3        if(1==match(str,"SLINE=")){
             4            SLINE = substr(str,7)
             5        }else if(1==match(str,"SPAT=")){
             6            SPAT = substr(str,6)
             7        }else if(1==match(str,"NUM=")){
             8            NUM = substr(str,5)
             9        }else if(1==match(str,"EPAT=")){
            10            EPAT = substr(str,6)
            11        }
            12    }
            13
            14  if(SLINE<=0 && SPAT==""){
            15      print "Usage: rangeshow must specifies valid SLINE which must be greater than 0, or SPAT which can't be empty"
            16      exit 1    
            17  }
            18
            19  if(NUM<=0 && EPAT==""){
            20      print "Usage: rangeshow must specifies valid NUM which must be greater than 0, or EPAT which can't be empty"
            21    exit 1
            22}

               結(jié)束處理
               當(dāng)處理了NUM條記錄或匹配了結(jié)束行模式時,應(yīng)退出動作塊{}。   
             1if(0==start_nr){ 
             2      
             3}else{
             4    if(NUM>0) {
             5        if(NR<start_nr+NUM) {
             6            ++matched_nr
             7            print $0            
             8        }else
             9            exit 0
            10
            11    }else{
            12        ++matched_nr
            13        print $0        
            14        if(0!=match($0,EPAT))
            15            exit 0
            16    }
            17}

               完整腳本下載:rangeshow

            腳本示例
               查看linux內(nèi)核第10000行開始的10條指令,如下圖
               
               
               查看linux內(nèi)核函數(shù)do_fork入口開始的10條指令,如下圖    
               

               查看linux內(nèi)核第10000行開始到callq的一段指令,如下圖
               

               查看linux內(nèi)核函數(shù)do_exit入口到調(diào)用profile_task_exit的一段指令,如下圖   
               
            posted @ 2015-10-27 15:36 春秋十二月 閱讀(1820) | 評論 (1)編輯 收藏
               本文根據(jù)RFC793協(xié)議規(guī)范和BSD 4.4的實現(xiàn),總結(jié)了TCP分組丟失時的狀態(tài)變遷,如下圖所示:實線箭頭表示客戶端的狀態(tài)變遷,線段虛線箭頭表示服務(wù)端的狀態(tài)變遷,圓點虛線箭頭表示客戶端或服務(wù)端的狀態(tài)變遷;黑色文字表示正常時的行為,紅色文字表示分組丟失時的行為。

               這里假設(shè)重傳時分組依然會丟失,當(dāng)在不同狀態(tài)(CLOSED除外)分組丟失后,最終會關(guān)閉套接字而回到CLOSED狀態(tài)。下面逐個分析各狀態(tài)時的情景。

            SYN_SENT
               連接階段第1次握手,客戶端發(fā)送的SYN分組丟失,因此超時收不到服務(wù)端的SYN+ACK而重傳SYN,嘗試幾次后放棄,關(guān)閉套接字。

            SYN_RCVD
               1)連接階段第2次握手,服務(wù)端響應(yīng)的SYN+ACK分組丟失,因此超時收不到客戶端的ACK而重傳SYN+ACK,嘗試幾次后放棄,發(fā)送RST并關(guān)閉套接字。
               2)連接階段第3次握手,客戶端發(fā)送的ACK分組丟失,因此服務(wù)端超時收不到ACK而重傳SYN+ACK,嘗試幾次后放棄,發(fā)送RST并關(guān)閉套接字。
               3)同時打開第2次握手,本端響應(yīng)的SYN+ACK分組丟失,因此對端超時收不到SYN+ACK而重傳SYN、嘗試幾次后放棄、發(fā)送RST并關(guān)閉套接字,而此時本端收到RST。

            ESTABLISHED
               1)連接階段第3次握手,客戶端發(fā)送ACK分組后,雖然丟失但會進(jìn)入該狀態(tài)(因為ACK不需要確認(rèn)),但此時服務(wù)端還處于SYN_RCVD狀態(tài),因為超時收不到客戶端的ACK而重傳SYN+ACK、嘗試幾次后放棄、發(fā)送RST并關(guān)閉套接字,而此時客戶端收到RST。
               2)數(shù)據(jù)傳輸階段,本端發(fā)送的Data分組丟失,因此超時收不到對數(shù)據(jù)的確認(rèn)而重傳、嘗試幾次后放棄、發(fā)送RST并關(guān)閉套接字,而此時對端收到RST。

            FIN_WAIT_1
               1)關(guān)閉階段第1次握手,客戶端發(fā)送的FIN分組丟失,因此超時收不到服務(wù)端的ACK而重傳FIN,嘗試幾次后放棄,發(fā)送RST并關(guān)閉套接字。
               2)關(guān)閉階段第2次握手,服務(wù)端響應(yīng)的ACK分組丟失,因此客戶端超時收不到ACK而重傳FIN,嘗試幾次后放棄,發(fā)送RST并關(guān)閉套接字。
             
            FIN_WAIT_2
               關(guān)閉階段第3次握手,服務(wù)端發(fā)送的FIN分組丟失,因此超時收不到客戶端的ACK而重傳FIN、嘗試幾次后放棄、發(fā)送RST并關(guān)閉套接字,而此時客戶端收到RST。
             
            CLOSING
               同時關(guān)閉第2次握手,本端發(fā)送的ACK分組丟失,導(dǎo)致對端超時收不到ACK而重傳FIN、嘗試幾次后放棄、發(fā)送RST并關(guān)閉套接字,而此時本端收到RST。

            TIME_WAIT
               關(guān)閉階段第4次握手,客戶端響應(yīng)的ACK分組丟失,導(dǎo)致服務(wù)端超時收不到ACK而重傳FIN、嘗試幾次后放棄、發(fā)送RST并關(guān)閉套接字,而此時客戶端收到RST。

            CLOSE_WAIT
               關(guān)閉階段第2次握手,服務(wù)端響應(yīng)的ACK分組丟失,導(dǎo)致客戶端超時收不到ACK而重傳FIN、嘗試幾次后放棄、發(fā)送RST并關(guān)閉套接字,而此時服務(wù)端收到RST。

            LAST_ACK
               關(guān)閉階段第3次握手,服務(wù)端發(fā)送的FIN分組丟失,導(dǎo)致超時收不到客戶端的ACK而重傳FIN、嘗試幾次后放棄、發(fā)送RST并關(guān)閉套接字。
            posted @ 2015-10-05 00:44 春秋十二月 閱讀(3341) | 評論 (1)編輯 收藏
                 摘要:    由于linux內(nèi)核中的struct list_head已經(jīng)定義了指向前驅(qū)的prev指針和指向后繼的next指針,并且提供了相關(guān)的鏈表操作方法,因此為方便復(fù)用,本文在它的基礎(chǔ)上封裝實現(xiàn)了一種使用開鏈法解決沖突的通用內(nèi)核Hash表glib_htable,提供了初始化、增加、查找、刪除、清空和銷毀6種操作,除初始化和銷毀外,其它操作都做了同步,適用于中斷和進(jìn)程上下文。...  閱讀全文
            posted @ 2015-09-15 17:18 春秋十二月 閱讀(2231) | 評論 (0)編輯 收藏
            僅列出標(biāo)題
            共17頁: First 5 6 7 8 9 10 11 12 13 Last 
            国内精品久久久久久久亚洲 | 久久免费美女视频| 精品精品国产自在久久高清| 99久久国产综合精品成人影院| 91麻精品国产91久久久久| 久久综合给合综合久久| 色婷婷久久综合中文久久蜜桃av| 国产91久久精品一区二区| 伊人久久五月天| 99久久精品九九亚洲精品| 亚洲av伊人久久综合密臀性色| 一本伊大人香蕉久久网手机| 久久精品无码一区二区WWW| 91久久精品国产免费直播| 天天躁日日躁狠狠久久| 欧美午夜精品久久久久久浪潮| 久久66热人妻偷产精品9| 伊人久久精品无码二区麻豆| 久久一本综合| 欧美国产精品久久高清| 久久99精品久久久久久9蜜桃| 久久精品欧美日韩精品| 精产国品久久一二三产区区别| 国产精品无码久久四虎| 久久精品嫩草影院| 91精品国产高清91久久久久久| 午夜精品久久久久久久| 97精品依人久久久大香线蕉97| 日韩久久无码免费毛片软件| 精品久久久久久久久久久久久久久| 潮喷大喷水系列无码久久精品 | 久久se精品一区二区| 狠狠88综合久久久久综合网 | 99久久精品国产一区二区三区| 九九久久99综合一区二区| a高清免费毛片久久| 国产午夜精品久久久久免费视| 久久亚洲美女精品国产精品| 久久精品水蜜桃av综合天堂| 免费观看久久精彩视频| A级毛片无码久久精品免费|