Linux内核动态加载netfilter模块并修改数据包源IP地址

这次加载netfilter模块比上篇的helloworld能稍微难一点,但万变不离其宗,一些细节就不赘述,本文引用了这篇文章部分代码。内核是3.10版本。

1.编写http.c文件

#include 
#include 
#include 
#include 
#include 

unsigned int my_hookfn(unsigned int hooknum,
		      struct sk_buff *skb,
		      const struct net_device *in,
		      const struct net_device *out,
		      int (*okfn)(struct sk_buff *))
{
	struct iphdr *iph = ip_hdr(skb);
	printk(KERN_INFO"source IP is %pI4\n", &iph->saddr);
	iph->saddr = in_aton("9.9.9.9");
	return NF_ACCEPT;
}

static struct nf_hook_ops nho = {
	.hook = my_hookfn,
	.pf = PF_INET,
	.hooknum = NF_INET_PRE_ROUTING,
	.priority = NF_IP_PRI_FIRST,
	.owner = THIS_MODULE,
};

static int http_init(void)
{
	if (nf_register_hook(&nho)) {
		printk(KERN_ERR"failed\n");
		return -1;
	} else {
		printk(KERN_INFO"succeeded\n");
		return 0;
	}
}

static void http_exit(void)
{
	nf_unregister_hook(&nho);
	printk(KERN_INFO"removed\n");
}

module_init(http_init);
module_exit(http_exit);

my_hookfn是自定义的钩子函数,函数原型是定义在/include/linux/netfilter.h中的nf_hookfn:

typedef unsigned int nf_hookfn(unsigned int hooknum,
          struct sk_buff *skb,
          const struct net_device *in,
          const struct net_device *out,
          int (*okfn)(struct sk_buff *));

hooknum:五个netfilter的Hook点之一
skb:表示数据包的结构体
in:数据包流入的网络设备
out:数据包流出的网络设备
okfn:函数指针,钩子函数调用完后调用的方法

iphdr是表示IP头部的结构体,里面的saddr就是source address。in_aton是字符串转换成IPv4地址的函数,定义在/include/linux/inet.h中,这里将源IP地址改成了9.9.9.9。返回的NF_ACCEPT表示数据包将接收此数据包。

接下来需要定义一个表示钩子函数的结构体,原型:

struct nf_hook_ops {
	struct list_head list;

	/* User fills in from here down. */
	nf_hookfn *hook;
	struct module *owner;
	u_int8_t pf;
	unsigned int hooknum;
	/* Hooks are ordered in ascending priority. */
	int priority;
};

最重要的是把具体要调用的hook函数指定为my_hookfn。

2.编写Makefile文件

ifneq($(KERNELRELEASE),)
	obj-m := http.o
else
	KDIR := /usr/src/kernels/3.10.0-1062.9.1.el7.x86_64
	PWD := /root
all:
	make -C $(KDIR) M=$(PWD) modules
clean:
	rm -f *.ko *.o *.mod.o *mod.c *.symvers *.order
endif	

3.执行make命令

4.加载、卸载模块(insmod、rmmod)

如果最后要验证一下的话,加载模块之前先安装tcpdump,不然加载之后安装不了(yum -y install tcpdump)
执行insmod http.ko命令后查看/var/log/messages如下图:
在这里插入图片描述

5.验证是否将数据包源IP改为9.9.9.9

① 由于是命令行操作,所以先把tcpdump挂到后台去运行,nohup tcpdump -i ens33 -n &,其中nohup加&代表退出账户后这个进程也不会停止,-i选项是指定网卡,-n是不把IP地址解析成域名显示,这样子所有的输出就会到当前目录下的nohup.out文件中。
② 修改nohup.out的权限(chmod 777 nohup.out)
③ 随便发起一个http连接:curl www.baidu.com,没有反应,因为百度发回的数据包IP地址被改成了9.9.9.9,ctrl C,查看nohup.out:
在这里插入图片描述
④ 卸载模块:
在这里插入图片描述
再curl www.baidu.com:
Linux内核动态加载netfilter模块并修改数据包源IP地址_第1张图片
⑤ 最后别忘了把tcpdump进程杀掉,要不然nohup.out会越来越大。
在这里插入图片描述

你可能感兴趣的:(Linux内核)