Netfilter Hook 程式範例
Netfilter 是 Linux Kernel 裏面對於網路封包處理一個非常有趣的設計,它在 Linux Kernel 的封包處理路徑上安插了許多的 Hook Point,這樣使用者可以隨自己的高興在這些 Hook Point 上安插自己的封包處理行為(使用註冊 callback function的方式),常見的應用如防火牆檢查、NAT等。在這邊稍微提一下,很多人會說 Linux 是用 iptables 來做防火牆的,我不太喜歡這個說法(但我不會說它是錯的),因為 iptables 不過是設定 netfilter 的 user space 工具,當你使用 iptables 時,不過就是將那些功能模組配合上使用者輸入的參數,然後掛載到對應的 Hook Point。下面是來自官網的描述:
netfilter is a set of hooks inside the Linux kernel that allows kernel modules to register callback functions with the network stack. A registered callback function is then called back for every packet that traverses the respective hook within the network stack.
至於有哪些 Hook Point 可以參考下面這張來自 Wiki 的圖:
這個概念是從 Linux Kernel 2.4 以後就內建在核心的機制。基本上我在研究所很常利用 iptables 這個設定工具來使用 netfilter,但一直沒有實際寫這 callback 的機會(之前工作上沒碰到,外加人懶)。但現在因為工作上有特殊的需求(來自一個莫名其妙的設計),所以就請(逼迫?)我同事撰寫了一個 Netfilter Callback 的模組範例出來(從程式裡可以找到作者),下面就是這個範例:
netfilter is a set of hooks inside the Linux kernel that allows kernel modules to register callback functions with the network stack. A registered callback function is then called back for every packet that traverses the respective hook within the network stack.
至於有哪些 Hook Point 可以參考下面這張來自 Wiki 的圖:
這個概念是從 Linux Kernel 2.4 以後就內建在核心的機制。基本上我在研究所很常利用 iptables 這個設定工具來使用 netfilter,但一直沒有實際寫這 callback 的機會(之前工作上沒碰到,外加人懶)。但現在因為工作上有特殊的需求(來自一個莫名其妙的設計),所以就請(逼迫?)我同事撰寫了一個 Netfilter Callback 的模組範例出來(從程式裡可以找到作者),下面就是這個範例:
這個 callback function 的功能非常簡單,就只是把經過封包的相關資訊給印出來,包含來源網卡、src mac、dst mac、src IP、dst IP,hooknum 填的地方就是 Hook Point。可能的選項可以參考 Linux/include/uapi/linux/netfilter_ipv4.h:#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/skbuff.h> #include <linux/netfilter.h> #include <uapi/linux/netfilter_ipv4.h> #include <linux/ip.h> #include <linux/udp.h> #include <linux/types.h> #define DRIVER_AUTHOR "JWGUO" #define DRIVER_DESC "HELLO WORLD" struct sk_buff *sock_buff; static struct nf_hook_ops nfho; /* Older kernel has different funcion definition. */ static unsigned int hook_func( const struct nf_hook_ops *ops, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { char *ifname = (char *)(in->name); struct ethhdr *mac_header = (struct ethhdr *)skb_mac_header(skb); struct iphdr *ip_header = (struct iphdr *)skb_network_header(skb); sock_buff = skb; if (!sock_buff) { return NF_ACCEPT; } // Do something to the pkt. printk(KERN_INFO "======HELLO WAYNE@net_dev: %s=====\n", ifname); printk(KERN_INFO "src_mac: %pM", mac_header->h_source); printk(KERN_INFO "dst_mac: %pM", mac_header->h_dest); printk(KERN_INFO "src_ip: %pI4", &ip_header->saddr); printk(KERN_INFO "dst_ip: %pI4", &ip_header->daddr); printk(KERN_INFO "\n"); return NF_ACCEPT; } static int __init init_main(void) { nfho.hook = hook_func; nfho.hooknum = NF_INET_PRE_ROUTING; // For older kernel: NF_IP_PRE_ROUTING nfho.pf = PF_INET; nfho.priority = NF_IP_PRI_FIRST; nf_register_hook(&nfho); printk(KERN_INFO "Successfully inserted a hook into kernel\n"); return 0; } static void __exit cleanup_main(void) { nf_unregister_hook(&nfho); printk(KERN_INFO "Successfully unloaded the hook\n"); } module_init(init_main); module_exit(cleanup_main); MODULE_LICENSE("GPLv3"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC);
附帶一提,這 module 是在 Linux Kernel 3.14.4 編譯並測試的。最後補上 makefile:/* IP Hooks */ /* After promisc drops, checksum checks. */ #define NF_IP_PRE_ROUTING 0 /* If the packet is destined for this box. */ #define NF_IP_LOCAL_IN 1 /* If the packet is destined for another interface. */ #define NF_IP_FORWARD 2 /* Packets coming from a local process. */ #define NF_IP_LOCAL_OUT 3 /* Packets about to hit the wire. */ #define NF_IP_POST_ROUTING 4 #define NF_IP_NUMHOOKS 5 #endif /* ! __KERNEL__ */
MOD := nfhook obj-m += $(MOD).o KVERSION := $(shell uname -r) all: $(MAKE) -C /lib/modules/$(KVERSION)/build M=$(PWD) modules clean: $(MAKE) -C /lib/modules/$(KVERSION)/build M=$(PWD) clean install: /sbin/insmod $(MOD).ko remove: /sbin/rmmod $(MOD).ko
留言
張貼留言