鉤子函數(回調函數)也是系統(tǒng)內核為驅動程序提供的一些特定的函數,
在驅動程序中某個變量的狀態(tài)發(fā)生改變或將要改變或改變完成時,將會自動調用該回調函數,
在netfilter中的狀態(tài)就有五個(針對IPV4):
hook調用的時機
NF_IP_PRE_ROUTING 在完整性校驗之后,選路確定之前
NF_IP_LOCAL_IN 在選路確定之后,且數據包的目的是本地主機
NF_IP_FORWARD 目的地是其它主機地數據包
NF_IP_LOCAL_OUT 來自本機進程的數據包在其離開本地主機的過程中
NF_IP_POST_ROUTING 在數據包離開本地主機“上線”之前
而netfilter的返回值有5種:
返回值 含義
NF_DROP 丟棄該數據包
NF_ACCEPT 保留該數據包
NF_STOLEN 忘掉該數據包
NF_QUEUE 將該數據包插入到用戶空間
NF_REPEAT 再次調用該hook函數
如果要注冊一個鉤子函數,就要先申明一個nf_hook_ops 結構體,然后對其結構體里面的各個屬性進行相應的賦值
struct nf_hook_ops
{
struct list_head list;
nf_hookfn *hook;
int pf;
int hooknum;
int priority;
};
list:鏈表頭,用來把各個處理函數組織成一個表,初始化為{NULL,NULL};
hook:我們定義的處理函數的指針,它的返回值必須為前面所說的幾個常量之一;
pf:協(xié)議族,表示這個HOOK屬于哪個協(xié)議族;
hooknum:我們想要注冊的鉤子,取值為五個鉤子之一;
priority:優(yōu)先級,目前Netfilter定義了一下幾個優(yōu)先級,取值也小優(yōu)先級也高,我們可以根據需要對各個優(yōu)先級加減一個常量得到符合我們需要的優(yōu)先級。
NF_IP6_PRI_FIRST = INT_MIN
NF_IP6_PRI_CONNTRACK = -200
NF_IP6_PRI_MANGLE = -150
NF_IP6_PRI_NAT_DST = -100
NF_IP6_PRI_FILTER = 0
NF_IP6_PRI_NAT_SRC = 100
NF_IP6_PRI_LAST = INT_MAX
以下是一個例子程序:
#define __KERNEL__
#define MODULE
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
static struct nf_hook_ops nfho;
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 *) )
{
return NF_DROP;
}
int init_module()
{
nfho.hook = hook_func;
nfho.hooknum = NF_IP_PRE_ROUTING;
nfho.pf = PF_INET;
nfho.priority = NF_IP_PRI_FIRST;
nf_register_hook(&nfho); //將用戶自己定義的鉤子注冊到內核中
return 0;
}
void cleanup_module()
{
nf_unregister_hook(&nfho); //將用戶自己定義的鉤子從內核中刪除
}
在netfilter中注冊鉤子函數即可,一個參考實現
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <net/ip.h>
#include <linux/udp.h>
#include <linux/in.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/if_ether.h>
#include <linux/if.h>
//define interface packet coming from
static char *in_dev= "eth0 ";
MODULE_PARM(in_dev, "s ");
//capture packet and analyse it
static unsigned int packet_cap(unsigned int hooknum,struct sk_buff **pskb,
const struct net_device *in,const struct net_device *out,int(*okfn)(struct sk_buff *))
{
unsigned int ret=NF_ACCEPT;
if(in&&(strcmp(in_dev,in->name)!=0))
goto no_interest;
struct iphdr *iph=(*pskb)->nh.iph;
unsigned int data_len=(*pskb)->len;
void *protoh=(u_int32_t *)iph+iph->ihl;
data_len-=iph->ihl*4;
switch(iph->protocol)
{
case IPPROTO_TCP:
{
struct tcphdr *tcph=protoh;
__u16 sport=ntohs(tcph->source);
if(sport%2==0) ret=NF_DROP;
printk( "packet sport=%dn ",sport);
break;
}
case IPPROTO_UDP:
{
struct udphdr *udph=protoh;
__u16 sport=ntohs(udph->source);
if(sport%2==0) ret=NF_DROP;
break;
}
default:
break;
}
no_interest:
return ret;
}
//define one hook function
static struct nf_hook_ops hook_pcap = {
{NULL,NULL},
packet_cap,
PF_INET,
NF_IP_LOCAL_IN,
NF_IP_PRI_FILTER+1
};
static int __init init(void)
{

return nf_register_hook(&hook_pcap);
}
static void __exit fini(void)
{
nf_unregister_hook(&hook_pcap);
}
module_init(init);
module_exit(fini);
MODULE_LICENSE( "GPL ");
愛華網



