上一篇点击打开链接介绍了netfilter的机制,本篇通过一个极简单的内核模块实践一下该机制。module代码nf_hook.c如下,在NF_INET_LOCAL_IN上挂hook_func钩子并判断如果报文目的地址是10.10.10.10就打印一下,仅此而已。
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/module.h>
#include <linux/ip.h>
static struct nf_hook_ops nfho;
//function to be called by hook
unsigned int hook_func(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (* okfn)(struct sk_buff *))
{
int ret = 0;
struct iphdr *iph = NULL;
struct udphdr *udp = NULL;
iph = (struct iphdr *)skb_network_header(skb);
if (ntohl(iph->daddr) == 0x0A0A0A0A) //10.10.10.10
{
printk("%s rcv packet \n\r",__func__);
}
return NF_ACCEPT;
}
int nf_hook_install(void)
{
nfho.hook = hook_func; //function to call when conditions below met
nfho.hooknum = NF_INET_LOCAL_IN; //called right after packet recieved, first hook in Netfilter
nfho.pf = PF_INET; //IPV4 packets
nfho.priority = NF_IP_PRI_FIRST; //set to highest priority over all other hook functions
nf_register_hook(&nfho); //register hook
return 0; //return 0 for success
}
int nf_hook_remove(void)
{
nfho.hook = hook_func; //function to call when conditions below met
nfho.hooknum = NF_INET_LOCAL_IN; //called right after packet recieved, first hook in Netfilter
nfho.pf = PF_INET; //IPV4 packets
nfho.priority = NF_IP_PRI_FIRST; //set to highest priority over all other hook functions
nf_unregister_hook(&nfho); //register hook
return 0; //return 0 for success
}
static int __init mymodule_init(void)
{
printk("module init\n\r");
nf_hook_install();
return 0;
}
static int __exit mymodule_exit(void)
{
printk("module exit\n\r");
nf_hook_remove();
return 0;
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("River");
MODULE_DESCRIPTION("nf_test");
module_init(mymodule_init);
module_exit(mymodule_exit);
makefile
ifneq ($(KERNELRELEASE),)
obj-m:=nf_hook.o
else
KERNELDIR:=/lib/modules/$(shell uname -r)/build
PWD:=$(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *.mod.c *.mod.o *.ko
endif
在主机上配置10.10.10.10地址,ping 10.10.10.10。 dmesg 查看内核日志可以看到自己的打印。
扩展:之前产品的gtp报文(udp port 2152)处理的方案是修改内核代码重出内核,用此方案可以不修改标准内核。