歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Unix知識 >> BSD

FreeBSD之netgraph簡要解析

FreeBSD的netgraph真是太帥了,它到底是個什麼玩藝呢?知道Linux的Netfilter的不少,那麼就用Netfilter來類比吧。netgraph是一個基於圖的鉤子系統,正如其名稱所展示的那樣,什麼樣的圖呢?很簡單,就是通過邊連接的節點,和數據結構裡面學到的一樣。netgraph系統掛接在內核協議棧的特定點上,哪些點呢?這個和Netfilter很類似,但是卻不是Netfilter精心設計的那5個點,而是更簡單的每一層處理的輸入點和輸出點,如下圖所示:

netgraph到底長什麼樣子呢?到目前為止,我們只是知道了一張圖掛上去了,這僅僅是個接口,一個開始,既然掛上去了,數據包就從此處進入這張圖了,把它叫做地圖更加適合,因此從此以後,數據包就要在游歷於這張地圖了,最終的結果有兩個:
1.數據包從地圖的某處出來,重新進入系統標准的協議棧的當初被攔截的那個地方;
2.數據包再也沒有出來回到原點,要麼被地圖吃掉了(進入了某一房間?),要麼就是從某處出去,進入協議棧的別的地方。

以上兩點很類似於Netfilter的ACCEPT,STOLEN這樣的結果,仔細想想不是麼?netgraph和標准協議棧的銜接如下圖所示:

既然知道了netgraph的位置,那麼下面就看看它的樣子吧。還是先給出一幅圖

該圖中有兩種元素,一種是節點,另一種是連接到節點的邊的兩端的頂點。在netgraph的術語中,節點就是Node,而頂點叫做hook,一條邊連接兩個hook,hook通過CONNECT/MKPEER構成一條邊。從上圖中可以看出,一條邊的兩端必然有兩個hook,從命名上可以看出這些“邊的端點”其實就是真正處理數據的地方,而Node其實就是一個“數據+操作”的封裝,一個Node可以有多個hook,通過這些hook連接到其它的Node。
        我們可以用OO的思想來理解這些個netgraph的概念,Node就是一個對象,每一個Node都有它所屬的Type,可以將Type理解成類。而hook其實就是一個Node對象的私有數據,整個graph通過“各個hook的對接”來完成,FreeBSD提供了豐富的命令來完成netgraph的構建,說白了其實就是以下幾步驟:
1.生成一系列的Node對象;
2.為每一個Node定義一個或多個hook;
3.將特定的Node通過hook連接在一起。

如此一來整個graph就構建好了,FreeBSD提供了struct ng_type,它便是代表了一個類,然後你每生成一個特定ng_type的實例就相當於生成了一個對象,通過對該結構體裡面的一些字段的理解,我們就可以完整理解數據包在這個graph中的游歷過成了。struct ng_type定義如下:
  1. struct ng_type {  
  2.     u_int32_t       version;        /* must equal NG_API_VERSION */  
  3.     const char      *name;          /* Unique type name */  
  4.     modeventhand_t  mod_event;      /* Module event handler (optional) */  
  5.     ng_constructor_t *constructor;  /* Node constructor */  
  6.     ng_rcvmsg_t     *rcvmsg;        /* control messages come here */  
  7.     ng_close_t      *close;         /* warn about forthcoming shutdown */  
  8.     ng_shutdown_t   *shutdown;      /* reset, and free resources */  
  9.     ng_newhook_t    *newhook;       /* first notification of new hook */  
  10.     ng_findhook_t   *findhook;      /* only if you have lots of hooks */  
  11.     ng_connect_t    *connect;       /* final notification of new hook */  
  12.     ng_rcvdata_t    *rcvdata;       /* data comes here */  
  13.     ng_disconnect_t *disconnect;    /* notify on disconnect */  
  14.     const struct    ng_cmdlist *cmdlist;    /* commands we can convert */  
  15.     LIST_ENTRY(ng_type) types;              /* linked list of all types */  
  16.     int                 refs;               /* number of instances */  
  17. };  
注釋很清楚了,自不必說,如果我們看看其中一些回調函數的定義,就更能理解了。“構造函數”和“析構函數”都有,每一個“成員函數”的參數列表的第一個參數類型都是node_p,這難道不是this麼?這裡唯一要注意的就是rcvdata回調函數,該函數接收從另一個Node發送過來的數據,接收者是hook,而不是Node,再次強調,Node之間通過hook相連接,而不是通過node本身,然而每一個hook都要唯一綁定一個Node對象,因此我們可以從hook解析出唯一的Node對象,卻不能從Node中直接得到hook(一個Node對象擁有N多hook呢),要分清一對一和一對多的關系。因此rcvdata的第一個參數是hook_p就是合理的了。
        Node和Node之間通過hook傳遞控制信息,而網絡數據包則是通過一個hook向其peer hook發送消息的方式完成的,當然所謂的發送消息大多數情況下就是函數直接調用。既然一條邊兩端有兩個hook,那麼每一個hook就有一個peer,每當我們將數據包發送到一個hook的時候,實際的效果就是數據包被發送到了該hook的peer,這是netgraph的核心邏輯實現的,我們可以從下面的這個核心宏中看到這一點:
  1. #define NG_FWD_ITEM_HOOK_FLAGS(error, item, hook, flags)                \   
  2.     do {                                                            \  
  3.         (error) =                                               \  
  4.         ng_address_hook(NULL, (item), (hook), NG_NOFLAGS);  \  
  5.         if (error == 0) {                                       \  
  6.             SAVE_LINE(item);                                \  
  7.             (error) = ng_snd_item((item), (flags));         \  
  8.         }                                                       \  
  9.         (item) = NULL;                                          \  
  10.     } while (0)  
其中ng_address_hook完成了peer的定位,這個peer可以通過ngctl命令來設置。
Copyright © Linux教程網 All Rights Reserved