全部博文(306)
分类: LINUX
2009-05-27 22:15:28
1. 数据包捕获:netfilter通过在内核中所设不同位置的hook点捕获通过的IP数据包。
2. 数据包处理:根据每个hook点上hook链上的处理模块处理经过的skb。
3. hook注册:用户、SElinux或者iptable根据自己的需要,在hook点上注册自己的数据处理模块。
int nf_register_hook(struct nf_hook_ops
*reg) //(linux kernel
{
struct nf_hook_ops *elem;
int err;
err = mutex_lock_interruptible(&nf_hook_mutex);
if (err < 0)
return err;
list_for_each_entry(elem, &nf_hooks[reg->pf][reg->hooknum], list) {
if (reg->priority < elem->priority)
break;
}
list_add_rcu(®->list, elem->list.prev);
mutex_unlock(&nf_hook_mutex);
return 0;
}
void nf_unregister_hook(struct nf_hook_ops *reg)
{
mutex_lock(&nf_hook_mutex);
list_del_rcu(®->list);
mutex_unlock(&nf_hook_mutex);
synchronize_net();
}
内核中5个hook点的轮询:
1、轮询NF_INET_PRE_ROUTING:
int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) // net/ipv4/ip_input.c
{
……
return NF_HOOK(PF_INET, NF_INET_PRE_ROUTING, skb, dev, NULL,
ip_rcv_finish);
……
}
多数netfilter函数为do_something 和do_something_finish或者do_something2,前者一般作check工作或者其他,而真正完成任务的在后者,前者通过NF_HOOK(……)调用后者。
2,轮询NF_INET_LOCAL_IN:
* Deliver IP Packets to the higher protocol layers.
int ip_local_deliver(struct sk_buff *skb) // net/ipv4/ip_input.c
{
/*
* Reassemble IP fragments.
*/
if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
if (ip_defrag(skb, IP_DEFRAG_LOCAL_DELIVER))
return 0;
}
return NF_HOOK(PF_INET, NF_INET_LOCAL_IN, skb, skb->dev, NULL,
ip_local_deliver_finish);
}
3、轮询NF_INET_FORWARD:
int ip_forward(struct sk_buff *skb) // net/ipv4/ip_forward.c
{
……
return NF_HOOK(PF_INET, NF_INET_FORWARD, skb, skb->dev, rt->u.dst.dev,
ip_forward_finish);
……
}
4、轮询NF_INET_LOCAL_OUT:
int __ip_local_out(struct sk_buff *skb) // net/ipv4/ip_ouput.c
{
struct iphdr *iph = ip_hdr(skb);
iph->tot_len = htons(skb->len);
ip_send_check(iph);
return nf_hook(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, skb->dst->dev,
dst_output);
}
int ip_local_out(struct sk_buff *skb)
{
int err;
err = __ip_local_out(skb);
if (likely(err == 1))
err = dst_output(skb);
return err;
}
5、轮询NF_INET_POST_ROUTING:
int ip_output(struct sk_buff *skb)
{
struct net_device *dev = skb->dst->dev;
IP_INC_STATS(dev_net(dev), IPSTATS_MIB_OUTREQUESTS);
skb->dev = dev;
skb->protocol = htons(ETH_P_IP);
return NF_HOOK_COND(PF_INET, NF_INET_POST_ROUTING, skb, NULL, dev,
ip_finish_output,
!(IPCB(skb)->flags & IPSKB_REROUTED));
}
int ip_mc_output(struct sk_buff *skb)
{
……
}
输出设备不是环回接口设备,则使用输出函数ip_mc_output,否则使用输出函数ip_output。
http://hi.baidu.com/linux_kernel/blog/item/58eafaf2bc87c713b17ec55b.html
用户自定义netfilter模块:
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef __MODULE__
#define __MODULE__
#endif
#include
#include
#include
#include
#include
#include
#define NF_IP_PRE_ROUTING 0
static struct nf_hook_ops nfho;
static unsigned char *drop_ip = "\x
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 *))
{
// struct sk_buff *sb = *skb;
struct iphdr *iph ;
struct sk_buff *sb;
sb = skb;
iph = ip_hdr(sb);
pr_info("Packet from %d.%d.%d.%d\n",NIPQUAD(iph->saddr));
if ( iph->saddr == *(__be32 *) drop_ip)
{
pr_info("Dropped packet from ... %d.%d.%d.%d\n",*drop_ip, *(drop_ip+1), *(drop_ip+2), *(drop_ip+3) );
return NF_DROP;
}else {
return NF_ACCEPT;
}
}
int init_module()
{
pr_info("i'm now in the kernel space!\n");
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);
pr_info("module removed from kernel!\n");
}
Makefile:
obj-m +=netfilter.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
rm Module.symvers
install:
/sbin/insmod simpFilter.ko
remove:
/sbin/rmmod simpFilter
PS:以上模块在数据包到达后理论上全部丢弃来自本地的ip数据包