2009/1/7

LINUX内核中Netfilter Hook的使用

 
LINUX内核中Netfilter Hook的使用 作者:JuKevin
 
HookLinux 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
 

文章標籤
全站熱搜
創作者介紹
創作者 horace papa 的頭像
horace papa

Horace papa's life

horace papa 發表在 痞客邦 留言(0) 人氣(578)