内核编程学习(2)netfilter初探

来源:互联网 发布:股票不允许网络销售吗 编辑:程序博客网 时间:2024/05/29 07:49

本次的任务是要在linux下利用netfilter往内核挂钩子,截获数据包。

这几天的练习,发现很多结构体以及技术涉及到内核版本,如果你发现有些结构体的成员什么的未定义,大多是这种问题。本机内核版本2.6.32-21-generic。查看内核版本命令uanme -r。

通俗的说,netfilter的架构就是在整个网络流程的若干位置放置了一些检测点(HOOK),而在每个检测点上登记了一些处理函数进行处理(如包过滤,NAT等,甚至可以是 用户自定义的功能)。

  IP层的五个HOOK点的位置如下所示
  [1]:NF_IP_PRE_ROUTING:刚刚进入网络层的数据包通过此点(刚刚进行完版本号,校验和等检测), 目的地址转换在此点进行;
  [2]:NF_IP_LOCAL_IN:经路由查找后,送往本机的通过此检查点,INPUT包过滤在此点进行;
  [3]:NF_IP_FORWARD:要转发的包通过此检测点,FORWORD包过滤在此点进行;
  [4]:NF_IP_POST_ROUTING:所有马上便要通过网络设备出去的包通过此检测点,内置的源地址转换功能(包括地址伪装)在此点进行;
  [5]:NF_IP_LOCAL_OUT:本机进程发出的包通过此检测点,OUTPUT包过滤在此点进行。
    进入HOOK点,执行通过nf_register_hook()登记的功能,如果我们想加入自己的代码,便要用nf_register_hook函数,其函数原型为:
  int nf_register_hook(struct nf_hook_ops *reg)。 我们考察一下struct nf_hook_ops结构:struct nf_hook_ops
{
        struct list_head list;                        //链表成员
        /* User fills in from here down. */
        nf_hookfn *hook;                        //钩子函数指针
        struct module *owner;
        int pf;                                        //协议簇,对于ipv4而言,是PF_INET
        int hooknum;                                //hook类型
        /* Hooks are ordered in ascending priority. */
        int priority;                                //优先级
};
  我们的工作便是生成一个struct nf_hook_ops结构的实例,并用nf_register_hook将其HOOK上。其中list项我们总要初始化为{NULL,NULL};由于一般在IP层工作,pf总是PF_INET;hooknum就是我们选择的HOOK点;一个HOOK点可能挂多个处理函数,谁先谁后,便要看优先级,即priority的指定了。netfilter_ipv4.h中用一个枚举类型指定了内置的处理函数的优先级:hook是提供的处理函数,也就是我们的主要工作.它的五个参数将由NFHOOK宏传进去。
本例简单地截获所有的数据包,并丢弃,这样就阻断了系统的网络链接,网页、ping等都收不到数据包。

#include <stdio.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
/* 用于注册我们的函数的数据结构 */
static struct nf_hook_ops nfho;
int count=0;
/* 注册的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 *))
{
        if(count==10)
        {
                FILE *fp;
                fp=fopen("text.txt","r+");
                fprintf(fp,"ip:%s",(*skb)->network_header->ihl);
                fclose(fp);
        }
        if(count<=10)
                count++;
        return NF_DROP;           /* 丢弃所有的数据包 */
}
/* 初始化程序 */
int init_module()
{
    /* 填充我们的hook数据结构 */
    nfho.hook = hook_func;         /* 该钩子对应的处理函数 */
    nfho.hooknum  = NF_INET_PRE_ROUTING; /* 使用IPv4的第一个hook */
    nfho.pf       = PF_INET;
    nfho.priority = NF_IP_PRI_FIRST;   /* 让我们的函数首先执行 */
     nf_register_hook(&nfho);  //将用户自己定义的钩子注册到内核中
    return 0;
}
/* 清除程序 */
void cleanup_module()
{
    nf_unregister_hook(&nfho); //将用户自己定义的钩子从内核中删除
}

                                                                                          
需要说明的是在钩子函数不要使用printk输出,不然系统会崩溃。还有本例想将截获的数据包保留保留部分信息写入文件,
但是编译时显示stdio.h文件未找到,估计是由于makefile中重定向了路径的问题,暂时还没有找到解决办法,钩子也很草率,现记下。