Chinaunix首页 | 论坛 | 博客
  • 博客访问: 444634
  • 博文数量: 403
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: -70
  • 用 户 组: 普通用户
  • 注册时间: 2016-09-05 12:45
文章分类

全部博文(403)

文章存档

2014年(3)

2013年(1)

2012年(3)

2011年(21)

2010年(13)

2009年(64)

2008年(9)

2007年(36)

2006年(253)

分类: 系统运维

2007-03-30 14:56:54

2.4的结构比2.2从新定义了许多数据结构。2.22.4防火墙都采用模块机制,基本原理是一致的。

        Linux2.4内核的防火墙框架netfilterIP 内提供了五个插入点:NF_IP_PRE_ROUTING,NF_IP_LOCAL_IN,NF_IP_FORWARD,NF_IP_LOCAL_OUT,NF_IP_POST_ROUTING,分别对应IP层的五个不同位置。这样,在理论上写用户自己的内核模块便可以选择更合适的切入点。

知道netfilter内置的防火墙函数模块的接口,方便自己在编写自己的防火墙函数模块时清楚的知道内核如何调用自己写的函数模块。

IP层代码中,有一些带有NF_HOOK宏的函数,如在IP接受函数ip_rcv中有:

NF_HOOK(PF_INET,NF_IP_PRE_ROUTING,skb,dev,NULL,ip_rcv_finish);

这是在钩子点NF_IP_PRE_ROUTING定义的防火墙模块函数,其中NF_HOOK宏的定义提炼如下:

#ifdef CONFIG_NETFILTER_DEBUG

#define NF_HOOK nf_hook_show

#else

#define NF_HOOK(pf,hook,skb,indev,outdev,okfn)(list_empty(&nf_hooks[(pf)][(hook)])?(okfn)(skb):nf_hook_show((pf),(hook),(skb),(indev),(out_dev),(okfn)))

#endif

如果在编译内核时没有选择配置netfilter,则在IP接受函数中NF_HOOK宏就相当于调用一个参数,在此即执行ip_rcv_finish;如果选择配置netfilter,则进入HOOK点,执行通过nf_register_hook()登记函数。NF_HOOK宏的参数分别为:

参数pf,协议族名,netfilter构架同样可以用于IP层之外。所以这个变量同样可以有诸如PF_INET6,PF_DECnet等名字。

参数hook,钩子点的名字,对于IP层就是取上面的五个值。

参数skb,指向结构体struct sk_buff的指针。

参数indev,进来的设备,以struct net_device结构表示

参数outdev,出去的设备,以struct net_device结构表示

以上的这五个参数将传到用nf_register_hook登记的处理函数中。

这些点是已经在内核中定义好的,除非用户是这部分内核代码的维护者,否则无权增加或修改。在此检查点进行的处理,可由用户指定。像packet filter,NAT,connection track 这些功能,也是以这样方式提供。

1.登记防火墙程序到内核

登记的防火墙程序只要载入内核,在网络层内核就会去自动调用它,前提是自己必须正确的把自己写的防火墙程序登记到内核中。

 内核中提供了防火墙的登记和卸载函数,分别为nf_register_hooknf_unregister_hook,这些函数的源代码位于/linux/net/core/netfilter.c

1)关键的数据结构

防火墙模块就登记在由nf_hook_ops数据结构所形成的单向链表中。自己编写的防火墙函数模块,实际上就是生成一个struct nf_hook_ops结构的实例,并用nf_register_hook将其登记在HOOK上。

结构体nf_hook_ops

struct  nf_hook_ops

{

    /*结构体list_head用于形成链表,是Linux2.4内核中一个通用的结构体*/

    struct list_head  list;

    /*指向用户定义的在该钩子点对应的处理函数*/

    nf_hookfn  *hook;

    /*协议族*/

    int pf;

   /*核心指定的那五个钩子点之一*/

   int hooknum;

  /*该钩子点定义了函数的优先级*/

   int priority;

};

最后一个域priority是很重要的,如果钩子点定义了很多处理函数,处理的先后顺序就根据它来确定.netfilter_ipv4.h中用一个枚举类型指定了内置处理函数的优先级,

  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)登记函数

函数功能说明:内核用来登记防火墙模块的函数,登记成功返回0;登记失败返回非0。呵呵

参数说明:reg,指向结构体nf_hook_ops的指针。具体分析如下:

int nf_register_hook(struct nf_hook_ops *ops)

{

           struct  list_head  * i   ;

           /*建立锁,在一段时间里只润许一个用户登记*/

          br_write_lock_bh(BR_NETPROTO_LOCK);

         /*遍历整个防火墙链表,检查优先级。如果登记的函数模块的优先级小于内核中已经存在的函数模块的优先级,则不把该函数添加到链表中*/

          for(i = nf_hooks[reg->pf][reg->hooknum].next; i!=&nf_hooks[reg->pf][reg->hooknum];i = i->next)

          {           

                   if(reg->priority < ((struct nf_hook_ops *)i)->priority)

                   break;

           }

/*将防火墙模块添加入链表*/

          list_add(®->list,i->prev);

          br_write_unlock_bh(BR_NETPROTO_LOCK);

          return 0;

}

3)卸载函数

该函数是nf_register_hook的反调用。

函数参数说明:参数和nf_register_hook相同。

 Void nf_unregister_hook(struct nf_hook_ops *reg)

{

       /*加锁保证只能有一个用户在一段时间中卸载*/

     br_write_lock_bh(BR_NETPROTO_LOCK)

      /*从链表中取出这个防火墙模块*/

     list_del(®->list);

     br_write_unlock_bh(BR_NETPROTO_LOCK);

}

2.防火墙模块的设计

1)防火墙内置函数模块简介

netfilter框架的五个钩子点都定义了内置的函数模块,都定义为NF_HOOK宏的形式。

IP层接受包的函数ip_rcv(),调用了定义在钩子点NF_IP_PRE_ROUTING的处理函数:NF_HOOK(PF_INET,NF_IP_PRE_ROUTING,skb,dev,NULL,ip_rev_finish);

IP层向上层协议栈传递的函数ip_local_deliver()中,调用了定义在钩子点NF_IP_LOCAL_IN上的处理函数:

NF_HOOK(PF_INET,NF_IP_LOCAL_IN,skb,skb->dev,NULL,ip_local_deliver_finish);

IP层转发函数ip_forward()中,调用了定义在钩子点NF_IP_FORWARD的处理函数:

NF_HOOK(PF_INET,NF_IP_FORWARD,skb,skb->dev,dev2,ip_forward_finish);

IP层产生的数据包有直接送去本地进程排队处理的,也有送往路由处理

函数进行处理的。在路由处理函数处理之前,调用了定义在钩子点

NF_IP_LOCAL_OUT上的处理函数。当路由处理函数处理完毕后,又将调

用定义在钩子点NF_IP_POST_ROUTING上的函数。下面简要分析:

     ip_build_and_send_pkt()函数中调用下面定义的宏:

NF_HOOK(PF_INET,NF_IP_LOCAL_OUT,skb,NULL,rt->u.dst.dev,output_maybe_reroute);

     ip_finish_output()函数中调用下面的宏定义:

NF_HOOK(PF_INET,NF_IP_POST_ROUTING,skb,NULL,dev,ip_finish_output2);

     ip_mc_output()函数中调用下面定义的宏:

NF_HOOK(PF_INET,NF_IP_POST_ROUTING,newskb,NULL,newskb->dev,ip_dev_loopback_xmit);

ip_queue_xmit()函数中调用下面的宏定义:

NF_HOOK(PF_INET,NF_IP_LOCAL_OUT,skb,NULL,rt->u.dst.dev,ip_queue_xmit2);

2)防火墙程序例子

(一个简单的入侵检测功能,能检查land,winuke以及特殊扫描nmap。此代

码只能在。2.4内核下编译。

gcc  -O –c Wall user_firewall.c

user_firewall.c

#ifndef  __KERNEL__

#define __KERNEL__  /*按照内核模块编译*/

#endif

#ifndef  MODULE

#define MODULE     /*按设备驱动程序模块编译*/

#endif

/*最基本的内核模块头文件*/

#include

#include

#include

#include

#include

#include

#include

#include

static unsigned int user_firewall(unsigned int hooknum ,struct sk_buff  **skb , const struct  net_device  in , const  struct  net_device  out ,int (*okfn)(struct sk_buff  *))

{

            struct  iphdr  *iph ;

            struct  tcphdr  *tcph;

            struct udphdr  *udph;

           

            __u32 sip;

            __u32  dip;

            __u16  sport;

            __u16  dport;

        /*取出IP,IP地址.目的IP地址*/ 

           iph=(*skb)->nh.iph;

           sip=iph->saddr;

           dip=iph->daddr;

        /*检查IP头长度*/

        if(iph->ihl != 5)  {

     printk(“IP packet with packet from %d.%d.%d.%d to %d.%d.%d.%d\n”,NIPQUAD(sip),NIPQUAD(dip));

}

/*如果是TCP协议*/

if(iph->protocol == 6){

  tcph = (struct tcphdr *)((__u32 *)iph + iph->ihl);

  sport = tcph->source;

  dport = tcph->dest;

/*防止land攻击*/

if((tcph->syn)&&(sport==dport)&&(sip==dip)){

  printk(“maybe land attack\n”);

}

/*防止winnuke攻击*/

if(ntohs(tcph->dest) == 139&&tcph->urg){

  printk(“maybe winnuke a from %d.%d.%d.%d to %d.%d.%d.%d\n”,NIPQUAD(sip),NIPQUAD(dip));

}

        if(tcph->ece&&tcph->cwr){

printk(“queso from %d.%d.%d.%d to %d.%d.%d.%d\n” ,NIPQUAD(sip),NIPQUAD(dip));  

/*防止恶意扫描*/

if((tcph->fin)&&(tcph->syn)&&(! tcph->rst)&&(! tcph->psh)&&(! tcph->ack)&&(! tcph->urg)){

  printk(“SF_scan from %d.%d.%d.%d to %d.%d.%d.%d\n” ,NIPQUAD(sip),NIPQUAD(dip));

}

if((! tcph->fin)&&(! tcph->syn)&&(! tcph->rst)&&(! Tcph->psh)&&(! Tcph->ack)&&(! Tcph->urg)){

printk(“NULL_scan from %d.%d.%d.%d to %d.%d.%d.%d\n”,NIPQUAD(sip),NIPQUAD(dip));

}

if(tcph->fin && tcph->syn && tcph->rst && tcph->psh && tcph->ack && tcph->urg){

printk(“FULL_Xmas_scan from %d.%d.%d.%d to %d.%d.%d.%d \n”,NIPQUAD(sip),NIPQUAD(dip));

}

if((tcph->fin)&&(! tcph->syn)&&((! tcph->rst)&&(tcph->psh)&&(! tcph->ack)&&(tcph->urg)){

 printk(“XMAS_Scan(FPU)from %d.%d.%d.%d to %d.%d.%d.%d\n”, NIPQUAD(sip),NIPQUAD(dip));

}

/*如果协议类型为UDP*/

else if(iph->protocol == 17){

  udph = (struct udphdr *)((__u32 *)iph + iph_ihl);

  sport = udph->source;

  dport = udph->dest;

/* play udp packet here */

}

/*如果协议类型为ICMP*/

else if(iph->protocol == 1){

   }

/*如果协议类型为IGMP*/

else if(iph->protocol == 2){

  printk(“igmp packet from %d.%d.%d.%d to %d.%d.%d.%d\n”, NIPQUAD(sip),NIPQUAD(dip));

}

/*如果协议类型未知*/

else{

         printk(“unknown protocol %d packet from %d.%d.%d.%d to %d.%d.%d.%d\n”, iph->protocol,NIPQUAD(sip),NIPQUAD(dip));

}

//*接受所有的包*/

return NF_ACCEPT;

}

接着,初始化登记防火墙用到的关键数据结构,上面的处理函数定义在钩子点NF_IP_PRE_ROUTING:

static struct  nf_hook_ops  iplimitfilter =

{

   {NULL,NULL},

    user_firewall,

    PF_INET,

    NF_IP_PRE_ROUTING,

    NF_IP_PRI_FILTER-1

};

定义模块初始化函数和模块卸载函数.当用户输入命令insmod user_firewall.o ,将调用这个初始化函数.当用户输入rmmod user_firewall,将调用下面的定义卸载函数.

/*模块初始化函数*/

int init_module(void)

{

    return nf_register_hook(&iplimitfilter);

}

/*模块卸载函数*/

void cleanup_module(void){

    nf_unregister_hook(&iplimitfilter);

}

阅读(4022) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~