Linux - 模块编程初试

  计算机网络的课程设计要做防火墙,老师没有限制在什么系统上面做,所以决定在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) modules
12 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        0x0002
10 /* Input device. */
11 #define NFC_IP_IF_IN        0x0004
12 /* Output device. */
13 #define NFC_IP_IF_OUT        0x0008
14 /* TOS. */
15 #define NFC_IP_TOS        0x0010
16 /* Protocol. */
17 #define NFC_IP_PROTO        0x0020
18 /* IP options. */
19 #define NFC_IP_OPTIONS        0x0040
20 /* Frag & flags. */
21 #define NFC_IP_FRAG        0x0080
22
23 /* Per-protocol information: only matters if proto match. */
24 /* TCP flags. */
25 #define NFC_IP_TCPFLAGS        0x0100
26 /* Source port. */
27 #define NFC_IP_SRC_PT        0x0200
28 /* Dest port. */
29 #define NFC_IP_DST_PT        0x0400
30 /* Something else about the proto */
31 #define NFC_IP_PROTO_UNKNOWN    0x2000
32
33 /* IP Hooks */
34 /* After promisc drops, checksum checks. */
35 #define NF_IP_PRE_ROUTING    0
36 /* If the packet is destined for this box. */
37 #define NF_IP_LOCAL_IN        1
38 /* If the packet is destined for another interface. */
39 #define NF_IP_FORWARD        2
40 /* Packets coming from a local process. */
41 #define NF_IP_LOCAL_OUT        3
42 /* Packets about to hit the wire. */
43 #define NF_IP_POST_ROUTING    4
44 #define NF_IP_NUMHOOKS        5
45 #endif /* ! __KERNEL__ */

  原因:在2.6.22以及以后的内核中,NF_IP_PRE_ROUTING以及NF_IP6_PRE_ROUTING都被放在了用户态,而在内核态编程必须统一使用NF_INET_PRE_ROUTING。

  所以解决的办法就是使用NF_INET_XXXXXXX来代替相关的宏就行了。

  这里坑了我比较长的时间。

  修改了以后再编译一次,然后加载模块以后,ping一下,然后就出现效果了,每五个包就会有一个发不出去。

/******************************************************************************************************************************************************************************************/

持续更新...

时间: 2024-11-01 19:46:52

Linux - 模块编程初试的相关文章

Linux模块编程框架

Linux模块编程框架 Linux是单内核系统,可通用计算平台的外围设备是频繁变化的,不可能将所有的(包括将来即将出现的)设备的驱动程序都一次性编译进内核,为了解决这个问题,Linux提出了可加载内核模块(Loadable Kernel Module,LKM)的概念,允许一个设备驱动通过模块加载的方式,在内核运行起来之后"融入"内核,加载进内核的模块和本身就编译进内核的模块一模一样.一个程序在编译的地址的相对关系就已经确定了,运行的时候只是进行简单的偏移,为了使模块加载进内核后能够被放

linux module 模块编程

转载自:http://blog.csdn.net/eroswang/archive/2008/09/13/2924875.aspx 摘要Linux内核模块编程的资料有些纷繁复杂,有的过于简单,有的过于庞杂,我试图用笔记的形式想读者展示怎样来进程Linux模块编程,力图做到简明扼要,这篇文章也是作为本人备忘的资料,所以有些地方过于简略是难免的.本来这篇文章的目的就是让用户知其然,至于所以然还是请参考相应的资料,其实最好的资料莫过于Linux Kernel Source. 适用范围: Linux K

初探linux内核编程,参数传递以及模块间函数调用

一.前言                                  我们一起从3个小例子来体验一下linux内核编程.如下: 1.内核编程之hello world 2.模块参数传递 3.模块间函数调用 二.准备工作                           首先,在你的linux系统上面安装linux头文件,debian系列: 1 $:sudo apt-get install linux-headers-`uname -r` 安装后,在你的/lib/modules/目录下有你刚

【转】初探linux内核编程,参数传递以及模块间函数调用

http://www.cnblogs.com/yuuyuu/p/5119891.html ZC: 疑问,最后的 模块kernel_mod 调用 模块kernel_fun的函数fun,是成功的OK的.但是 模块kernel_mod 怎么就知道 它调用的就是 模块kernel_fun的fun函数?如果 又有一个 模块kernel_fun01它也导出了fun函数,此时 模块kernel_mod调用fun的话调用的是哪一个模块的fun函数? (ZC: 测试了一下,两个模块 有相同的导出函数的话,在 加载

我的第一个Linux 驱动模块编程实验

2014.04.28 module 首测 1)环境:Centos release 6.5 (Final) kernel: 2.6.32-358.23.2.e16.centos.plus.i686 2)源文件及Makefile 源文件:是一个入门的Hello.c文件,网上到处可以找得到. Makefile 第一版本内容如下: obj-m := hello.o 3)make 时的命令 make -C /lib/modules/$(uname -r)/build  SUBDIRS=$PWD modul

linux网络编程 no route to host 解决方案

linux网络编程 no route to host 解决方案 [整合资料] (2013-05-13 21:38:12) 转载▼ 标签: net iptables it 分类: Linux 参考资料http://1413570.blog.51cto.com/1403570/792861http://2614223.blog.51cto.com/2604223/764757 在vmvare里面配了两台mysql,发现用mysql连不上mysql服务器,用telnet登录mysql的3306端口,发

Linux内核模块编程与内核模块LICENSE -《详解(第3版)》预读

Linux内核模块简介 Linux内核的整体结构已经非常庞大,而其包含的组件也非常多.我们怎样把需要的部分都包含在内核中呢?一种方法是把所有需要的功能都编译到Linux内核.这会导致两个问题,一是生成的内核会很大,二是如果我们要在现有的内核中新增或删除功能,将不得不重新编译内核. 有没有一种机制使得编译出的内核本身并不需要包含所有功能,而在这些功能需要被使用的时候,其对应的代码被动态地加载到内核中呢?Linux提供了这样的一种机制,这种机制被称为模块(Module).模块具有这样的特点. 模块本

系统调用与模块编程

前言 转载请注明出处http://www.cnblogs.com/dvd0423/p/4183443.html 内核让人最爽的地方就是它给你站在山上看风景的感觉,一切尽收眼底.就像0号博文说的,不管它有没有用,知其所以然总是好的. 这个系列的内容围绕Linux内核展开,涉及的主要是我做KVM的过程中遇到的部分,网络.调度.KVM等等.虽然是底层的东西但是搞应用的人看一看也没有坏处.我们都知道内核太庞大,要想全了解几乎不可能,所以我们只能根据自己的需要去针对性的学习.而如此庞大的项目却能被组织的有

来自Unix/Linux的编程启示录

2017年第一篇文章,祝各位好友新年快乐. 年前由于不小心坐到了自己左手大拇指导致轻微的骨裂,没有按时更新,实在是惭愧.今年给自己订了个小目标,在安顿好新工作后,每周一篇来总结这些年所学. 话不多说,步入正题 写本文的最初灵感源于16年11月份我将工作环境切换到Mac OS上,其中一些使用"差异"让我开始对Unix/Linux中设计产生了浓厚的兴趣. 在整个探究过程中,那些经典的著作再次让我获益匪浅:C和指针,C专家编程,深入理解计算机系统(原书第3版),Linux/Unix设计思想,