LINUX内核中Netfilter Hook的使用
- 3月 22 週二 201122:40
轉貼netfilter hook範例
2009/1/7
LINUX内核中Netfilter Hook的使用 作者:JuKevin
Hook是Linux Netfilter中重要技术,使用hook可以轻松开发内核下的多种网络处理程序。下面简单介绍一下hook及其使用。
1. hook相关数据结构
struct nf_hook_ops
{
struct list_head list;
/* User fills in from here down. */
nf_hookfn *hook;
struct module *owner;
int pf;
int hooknum;
/* Hooks are ordered in ascending priority. */
int priority;
};
主要成员介绍
int pf; 协议家族类型
int hooknum 为hook执行点,它表示在报文处理的具体什么阶段执行hook函数。
Linux有以下几种执行点:
NF_IP_PRE_ROUTING 在报文作路由以前执行;
NF_IP_FORWARD 在报文转向另一个NIC以前执行;
NF_IP_POST_ROUTING 在报文流出以前执行;
NF_IP_LOCAL_IN 在流入本地的报文作路由以后执行;
NF_IP_LOCAL_OUT 在本地报文做流出路由前执行。
nf_hookfn *hook; 为hook处理回调函数。其定义为:
typedef unsigned int nf_hookfn(
unsigned int hooknum, //hook执行点
struct sk_buff **skb, //sk buffer数据
const struct net_device *in, //输入设备
const struct net_device *out, //输出设备
int (*okfn)(struct sk_buff *) //
)
nf_hookfn执行后需要返回以下返回值:
NF_ACCEPT: 继续正常的报文处理;
NF_DROP: 将报文丢弃;
NF_STOLEN: 由钩子函数处理了该报文,不要再继续传送;
NF_QUEUE: 将报文入队,通常交由用户程序处理;
NF_REPEAT: 再次调用该钩子函数。
最后一个参数为hook优先级,内核定义了以下多种优先级:
enum nf_ip_hook_priorities
{
NF_IP_PRI_FIRST = INT_MIN,
NF_IP_PRI_CONNTRACK = -200,
NF_IP_PRI_MANGLE = -150,
NF_IP_PRI_NAT_DST = -100,
NF_IP_PRI_FILTER = 0,
NF_IP_PRI_NAT_SRC = 100,
NF_IP_PRI_LAST = INT_MAX,
};
2. hook注册/注销
注册和注销函数使用起来非常简单,我们来看一下它们的函数原型:
单个hook注册和注销函数
int nf_register_hook(struct nf_hook_ops *reg);
void nf_unregister_hook(struct nf_hook_ops *reg);
多个hook注册和注销函数
int nf_register_hooks(struct nf_hook_ops *reg, unsigned int n);
void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n);
3. 一个使用hook来监听主机ICMP报文的简单内核模块程序
#include <linux/init.h>
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/netfilter_ipv4.h>
#include <linux/inet.h>
#include <linux/in.h>
#include <linux/ip.h>
static unsigned int icmp_srv(unsigned int hook,
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *)
)
{
//printk(KERN_INFO"hook_icmp::icmp_srv()\n");
struct iphdr *iph = (*pskb)->nh.iph;
if(iph->protocol == IPPROTO_ICMP)
{
printk(KERN_INFO"hook_icmp::icmp_srv: receive ICMP packet\n");
printk(KERN_INFO"src: ");
}
return NF_ACCEPT;
}
static struct nf_hook_ops icmpsrv_ops =
{
.hook = icmp_srv,
.pf = PF_INET,
.hooknum = NF_IP_PRE_ROUTING,
.priority = NF_IP_PRI_FILTER -1,
};
static int __init init_hook_icmp(void)
{
return nf_register_hook(&icmpsrv_ops);
}
static void __exit fini_hook_icmp(void)
{
nf_unregister_hook(&icmpsrv_ops);
}
MODULE_LICENSE("GPL");
module_init(init_hook_icmp);
module_exit(fini_hook_icmp);
编译改模块之后,加载该模块,之后可以在DOS下用ping命令来测试。
在linux中用dmesg查看,可以看到收到的icmp报文
hook_icmp::icmp_srv: receive ICMP packet
hook_icmp::icmp_srv: receive ICMP packet
hook_icmp::icmp_srv: receive ICMP packet
hook_icmp::icmp_srv: receive ICMP packet
文章標籤
全站熱搜
