linux netfilter 五個鈎子點


參考http://www.linuxtcpipstack.com/685.html#NF_INET_PRE_ROUTING

https://opengers.github.io/openstack/openstack-base-netfilter-framework-overview/

http://blog.chinaunix.net/uid-26517122-id-4293010.html

https://netfilter.org/documentation/HOWTO/netfilter-hacking-HOWTO-3.html

https://en.wikipedia.org/wiki/Netfilter

在三層IPv4數據包的處理過程中,可能經過Netfilter的五個鈎子點,分別為NF_INET_PRE_ROUTING、NF_INET_LOCAL_IN、NF_INET_FORWARD、NF_INET_LOCAL_OUT、NF_INET_POST_ROUTING,在每個點都可以設置一些規則,來對數據包進行匹配檢查處理,這些規則的配置、布局和匹配流程。

 

 

 

 Netfilter 提供了一個基本的報文攔截框架,即hook機制;

Netfilter 中定義了一個全局二維數組,來存放注冊了的處理函數。

struct list_head hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS] __read_mostly;

 在每個關鍵點上,有很多已經按照優先級預先注冊了的回調函數;

每個鈎子函數最后必須向Netfilter框架返回下列幾個值其中之一

#define NF_DROP 0 /* 丟包,不再傳輸 */
#define NF_ACCEPT 1 /* 接受數據包,繼續正常傳輸 這個返回值告訴 Netfilter:到目前為止,該數據包還是被接受的並且該數據包應當被遞交到網絡協議棧的下一個階段 */
#define NF_STOLEN 2 /* 數據包已經被接管,回調函數處理該包,NF不再處理,該回調函數將從此開始對數據包的處理,並且Netfilter應當放棄對該數據包做任何的處理。但是,這並不意味着該數據包的資源已經被釋放。這個數據包以及它獨自的sk_buff數據結構仍然有效,只是回調函數從Netfilter 獲取了該數據包的所有權 */
#define NF_QUEUE 3 /*對該數據報進行排隊 ,通常用於將數據包交給用戶空間的進程處理 */
#define NF_REPEAT 4 /* 再次調用該回調函數,應當謹慎使用這個值,以免造成死循環*/
#define NF_STOP 5    /*結束執行, 數據包通過了掛載點的所有規則。但與NF_ACCEPT不同的一點時,當某條規則的判定結果為NF_STOP,那么可以直接返回結果NF_STOP,無需進行后面的判定了。而NF_ACCEPT需要所以的規則都為ACCEPT,才能返回NF_ACCEPT */
#define NF_MAX_VERDICT NF_STOP
 

netfilter 回調函數注冊

nf_hook_ops是注冊的鈎子函數的核心結構,字段含義如下所示,一般待注冊的鈎子函數會組成一個nf_hook_ops數組,在注冊過程中調用nf_register_net_hooks將所有規則加入到指定的鈎子點;

/*
list:因為在一個HOOK點有可能注冊多個鈎子函數,因此這個變量用來將某個HOOK點所注冊的所有鈎子函數組織
成一個雙向鏈表;
hook:該參數是一個指向nf_hookfn類型的函數的指針,由該函數指針所指向的回調函數在該hook被激活時調用【nf_hookfn在后面做解釋】;
owner:表示這個hook是屬於哪個模塊的
pf:該hook函數所處理的協議。目前我們主要處理IPv4,所以該參數總是PF_INET;
hooknum:鈎子函數的掛載點,即HOOK點;
priority:優先級。前面也說過,一個HOOK點可能掛載了多個鈎子函數,當Netfilter在這些HOOK點上遍歷查找所注冊的鈎子函數時,這些鈎子函數的先后執行順序便由該參數來制定。
*/
struct nf_hook_ops {
    struct list_head    list;
 
    /* User fills in from here down. */
    nf_hookfn        *hook; /* 鈎子函數 */
    struct net_device    *dev; /* 設備 */
    void            *priv; /* 私有數據 */
    u_int8_t        pf; /* 協議族 */
    unsigned int        hooknum; /* 鈎子點 */
    /* Hooks are ordered in ascending priority. */
    int            priority; /* 優先級 */
};

鈎子函數原型為:

typedef unsigned int nf_hookfn(void *priv,
                   struct sk_buff *skb,
                   const struct nf_hook_state *state);
View Code

nf_register_net_hook為鈎子函數注冊的主流程,首先找到鈎子點函數的入口,然后根據優先級將當前注冊的鈎子函數插入到鏈表中;

int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg)
{
    struct list_head *hook_list;
    struct nf_hook_entry *entry;
    struct nf_hook_ops *elem;
 /* 分配鈎子入口結構 */
    entry = kmalloc(sizeof(*entry), GFP_KERNEL);
    if (!entry)
        return -ENOMEM;

    entry->orig_ops    = reg;
    entry->ops    = *reg;
/* 找到鈎子點鏈表頭部 */
    hook_list = nf_find_hook_list(net, reg);
    if (!hook_list) {
        kfree(entry);
        return -ENOENT;
    }

    mutex_lock(&nf_hook_mutex);
     /* 找到鈎子應該插入的位置 */
    list_for_each_entry(elem, hook_list, list) {
        if (reg->priority < elem->priority)
            break;
    }
     /* 插入鈎子點 */
    list_add_rcu(&entry->ops.list, elem->list.prev);
    mutex_unlock(&nf_hook_mutex);
#ifdef CONFIG_NETFILTER_INGRESS
    if (reg->pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS)
        net_inc_ingress_queue();
#endif
#ifdef HAVE_JUMP_LABEL
    static_key_slow_inc(&nf_hooks_needed[reg->pf][reg->hooknum]);
#endif
    return 0;
}
View Code
/*
對於nf
其鈎子函數入口形式為hooks[協議族][鈎子點],在二維數組的每個節點都對應着一個鈎子函數鏈表,內部多個nf_hook_entry通過優先級從小到大排列;
*/
struct netns_nf {
#if defined CONFIG_PROC_FS
    struct proc_dir_entry *proc_netfilter;
#endif
    const struct nf_queue_handler __rcu *queue_handler;
    const struct nf_logger __rcu *nf_loggers[NFPROTO_NUMPROTO];
#ifdef CONFIG_SYSCTL
    struct ctl_table_header *nf_log_dir_header;
#endif
    struct list_head hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
};

enum {
    NFPROTO_UNSPEC =  0,
    NFPROTO_INET   =  1,
    NFPROTO_IPV4   =  2,
    NFPROTO_ARP    =  3,
    NFPROTO_NETDEV =  5,
    NFPROTO_BRIDGE =  7,
    NFPROTO_IPV6   = 10,
    NFPROTO_DECNET = 12,
    NFPROTO_NUMPROTO,
};
//IPv4鈎子點的定義如下:
enum nf_inet_hooks {
    NF_INET_PRE_ROUTING,
    NF_INET_LOCAL_IN,
    NF_INET_FORWARD,
    NF_INET_LOCAL_OUT,
    NF_INET_POST_ROUTING,
    NF_INET_NUMHOOKS
};

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM