標籤:
電腦網路的課程設計要做防火牆,老師沒有限制在什麼系統上面做,所以決定在Linux上實現。找了一下相關的資料,發現其實Linux有提供Netfilter/Iptables,為使用者提供防火牆的功能,稍微看了一下,使用Iptables能夠很方便地配置使用者想要的防火牆,但是好像只能做過濾、資料報修改以及網路位址轉譯,好像不能做擷取其中資訊的功能,而且看了一下網上其他人的提問或者部落格,好像想做類似的功能還是需要直接使用Netfilter。而如果想要使用Netfiler的話,需要編寫hook函數,這個過程中不得不避免要編寫模組。所以這裡記錄一下我在這個過程中做的一些嘗試以及遇到的問題。
使用的平台:Ubuntu 14.10
核心版本: 3.16.0-23-generic (這個很重要啊,不用的核心可能函數都是不一樣的,網上的大部分教程用的核心版本都是2.6)
2015.4.23
第一次我是編寫一個hello world,在載入模組的時候以及移除模組的時候各輸出一次,這裡做的都是跟著網上的教程寫的。
代碼如下:
1 #include <linux/module.h> 2 #include <linux/kernel.h> 3 #include <linux/init.h> 4 5 6 static int __init lkp_init(void); 7 static int __exit lkp_exit(void); 8 9 static int __init lkp_init(void){10 printk("<1>Hello,world!\n");11 return 0;12 }13 14 static int __exit lkp_exit(void){15 printk("<2>Hello,world!\n");16 return 0;17 }18 19 module_init(lkp_init);20 module_exit(lkp_exit);
Makefile:
1 ifneq ($(KERNELRELEASE),) 2 mymodule-objs:=hello.c 3 obj-m += hello.o 4 5 else 6 PWD := $(shell pwd) 7 KVER := $(shell uname -r) 8 KDIR := /lib/modules/$(KVER)/build 9 10 all:11 $(MAKE) -C $(KDIR) M=$(PWD)12 clean:13 rm -rf *.o *.mod.c *.ko *.symvers *order *.markers *-14 endif
make一次以後然後載入模組: sudo insmod hello.ko
使用指令dmesg能夠查看到載入的時候的輸出。
移除模組: sudo rmmod hello.ko
再次使用dmesg能夠查看到移除的時候的輸出。
這裡這個Makefile是怎麼執行的,為什麼需要使用dmesg來查看輸出的問題我暫時先不寫,因為這些在網上都能找到而且能夠比較清楚地解釋,我打算寫的是一些我遇到的問題。
2015.4.26
開始編寫與Netfilter有關的函數,首先寫的這個也是按照別人的教程給的例子寫的程式。寫一個鉤子掛載到 LOCAL_OUT上。然後每隔四個發出去的資料包就攔截下下一個資料包。
代碼如下:
1 #ifndef __KERNEL__ 2 #define __KERNEL__ 3 #endif 4 #ifndef MODULE 5 #define MODULE 6 #endif 7 #include <linux/module.h> 8 #include <linux/kernel.h> 9 #include <linux/netfilter.h>10 #include <linux/netfilter_ipv4.h>11 12 static int count=0;13 14 static unsigned int func(unsigned int hooknum, struct sk_buff **skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)){15 count=(count+1)%5;16 if(count==0){17 return NF_DROP;18 }19 return NF_ACCEPT;20 }21 22 static struct nf_hook_ops nfho;23 24 static int __init myhook_init(void){25 nfho.hook = func;26 nfho.owner = THIS_MODULE;27 nfho.pf = PF_INET;28 nfho.hooknum = NF_INET_LOCAL_OUT;29 nfho.priority = NF_IP_PRI_FIRST;30 return nf_register_hook(&nfho);31 }32 33 static void __exit myhook_fini(void){34 nf_unregister_hook(&nfho);35 }36 37 module_init(myhook_init);38 module_exit(myhook_fini);
Makefile:
1 ifneq ($(KERNELRELEASE),) 2 mymodule-objs:=test0.c 3 obj-m += test0.o 4 5 else 6 PWD := $(shell pwd) 7 KVER := $(shell uname -r) 8 KDIR := /lib/modules/$(KVER)/build 9 10 all:11 $(MAKE) -C $(KDIR) M=$(PWD) modules12 clean:13 rm -rf *.o *.mod.c *.ko *.symvers *order *.markers *-14 endif
問題來了,如果是按照網上的其他例子來寫的話,make的時候就會說NF_IP_LOCAL_OUT找不到。當然還有一個警告說nfho.hook = func有問題,這個可能要看看怎樣寫它才會不警告,這裡不理這個警告沒有問題。我們繼續說NF_IP_LOCAL_OUT,開啟儲存所有標頭檔的目錄,發現這個宏定義有啊,就在linux/netfilter_ipv4.h裡面,是從uapi/linux/netfilter_ipv4.h包含進來的,但是這裡又有個問題,它是被ifndef __KERNEL__ ``` endif 包住了,所以它編譯的時候沒有包含進去,如下面的代碼:
1 #ifndef __KERNEL__ 2 3 #include <limits.h> /* for INT_MIN, INT_MAX */ 4 5 /* IP Cache bits. */ 6 /* Src IP address. */ 7 #define NFC_IP_SRC 0x0001 8 /* Dest IP address. */ 9 #define NFC_IP_DST 0x000210 /* Input device. */11 #define NFC_IP_IF_IN 0x000412 /* Output device. */13 #define NFC_IP_IF_OUT 0x000814 /* TOS. */15 #define NFC_IP_TOS 0x001016 /* Protocol. */17 #define NFC_IP_PROTO 0x002018 /* IP options. */19 #define NFC_IP_OPTIONS 0x004020 /* Frag & flags. */21 #define NFC_IP_FRAG 0x008022 23 /* Per-protocol information: only matters if proto match. */24 /* TCP flags. */25 #define NFC_IP_TCPFLAGS 0x010026 /* Source port. */27 #define NFC_IP_SRC_PT 0x020028 /* Dest port. */29 #define NFC_IP_DST_PT 0x040030 /* Something else about the proto */31 #define NFC_IP_PROTO_UNKNOWN 0x200032 33 /* IP Hooks */34 /* After promisc drops, checksum checks. */35 #define NF_IP_PRE_ROUTING 036 /* If the packet is destined for this box. */37 #define NF_IP_LOCAL_IN 138 /* If the packet is destined for another interface. */39 #define NF_IP_FORWARD 240 /* Packets coming from a local process. */41 #define NF_IP_LOCAL_OUT 342 /* Packets about to hit the wire. */43 #define NF_IP_POST_ROUTING 444 #define NF_IP_NUMHOOKS 545 #endif /* ! __KERNEL__ */
原因:在2.6.22以及以後的核心中,NF_IP_PRE_ROUTING以及NF_IP6_PRE_ROUTING都被放在了使用者態,而在核心態編程必須統一使用NF_INET_PRE_ROUTING。
所以解決的辦法就是使用NF_INET_XXXXXXX來代替相關的宏就行了。
這裡坑了我比較長的時間。
修改了以後再編譯一次,然後載入模組以後,ping一下,然後就出現效果了,每五個包就會有一個發不出去。
/******************************************************************************************************************************************************************************************/
持續更新...
Linux - 模組編程初試