netlink+netfilter+BloomFilter内核态过滤URL

2235阅读 0评论2009-12-18 ubuntuer
分类:LINUX

利用一天的时间在各位老大dreamice godbach  platinum等大佬的指定下,终于完成了一个内核过滤url的初级版本,只是提供一个解决方案 应用层防火墙呵呵^_^
问题肯定还是多多的,对http协议的了解也是有限的...
   可以参考我的以下帖子
       这个是内核中提取URL的
       这个是netlink+netfilter实现简单的封IP和封ICMP协议
     
   这里大致的思路是先利用netlink将需要过滤的url传到内核,内核根据bloom filter的思路来实现内核中提取的url是否需要过滤
   关于bloom filter可以看我blog里的这篇文章..用户态bloom filter的使用 http://blog.chinaunix.net/u2/76292/showart_2055618.html具体的
   使用例子google下一大堆 内核中URL过滤我借鉴了这个实现
   
   好了开始代码
   用户态url.c:

CODE:
   #include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define NETLINK_TEST 21
#define MAX_PAYLOAD 1024 /* maximum payload size*/

struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd;
struct msghdr msg;
struct option longopts[] =
{
   {"help",no_argument, NULL, 'h'},
   {"host",required_argument, NULL, 'H'},
   {0,0,0,0}
  };

void print_help(char* str)
{
fprintf(stderr,"%s --host(-H)\n",str);
fprintf(stderr,"%s --help(-h)\n",str);
fprintf(stderr,"eg:\n%s --host [url][/url]\n",str);
}
      

int main(int argc, char* argv[])
{
    int c;
    char host[20]="";
   
   while((c=getopt_long(argc, argv, "hH:", longopts, NULL))!=-1)   
    {
      switch(c)
       {
         case 'H':
          {
            sprintf(host,"%s",optarg);
            break;
          }
         case 'h':
           {
            print_help(argv[0]);
            return -1;
           }
        
         default:
          break;
       }

    }  

   sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_TEST);
   memset(&msg, 0, sizeof(msg));
   memset(&src_addr, 0, sizeof(src_addr));
   src_addr.nl_family = AF_NETLINK;
   src_addr.nl_pid = getpid(); /* self pid */
   src_addr.nl_groups = 0; /* not in mcast groups */
   bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
   memset(&dest_addr, 0, sizeof(dest_addr));
   dest_addr.nl_family = AF_NETLINK;
   dest_addr.nl_pid = 0; /* For Linux Kernel */
   dest_addr.nl_groups = 0; /* unicast */

   nlh=(struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
   /* Fill the netlink message header */
   nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
   nlh->nlmsg_pid = getpid(); /* self pid */
   nlh->nlmsg_flags = 0;
   /* Fill in the netlink message payload */
   printf("now we will filter %s\n", host);
   memcpy(NLMSG_DATA(nlh),host ,sizeof(host));

   iov.iov_base = (void *)nlh;
   iov.iov_len = nlh->nlmsg_len;
   msg.msg_name = (void *)&dest_addr;
   msg.msg_namelen = sizeof(dest_addr);
   msg.msg_iov = &iov;
   msg.msg_iovlen = 1;

   printf(" Sending message. ...\n");
   sendmsg(sock_fd, &msg, 0);
   close(sock_fd);
   return 0;
}

内核态urlfilter.c:

CODE:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define NETLINK_TEST 21
#define TABLE_SIZE   13
#define SETBIT(a, n) (a[n/32] |= (1<<(n%32)))
#define GETBIT(a, n) (a[n/32] & (1<<(n%32)))

unsigned int a[5];

static struct nf_hook_ops nfho;
struct sock *nl_sk = NULL;
EXPORT_SYMBOL_GPL(nl_sk);

static char* host = NULL;

unsigned int sax_hash(const char *key)
{
        unsigned int h=0;

        while(*key) h^=(h<<5)+(h>>2)+(unsigned char)*key++;

        return h%TABLE_SIZE;
}

unsigned int sdbm_hash(const char *key)
{
        unsigned int h=0;
        while(*key) h=(unsigned char)*key++ + (h<<6) + (h<<16) - h;
        return h%TABLE_SIZE;
}

void input (struct sock* sk, int len)
{
  struct sk_buff* skb = NULL;
  struct nlmsghdr* nlh = NULL;

  printk("net_link: data is ready to read.\n");
  while((skb = skb_dequeue(&sk->sk_receive_queue))!=NULL)
   {
    nlh = (struct nlmsghdr*)skb->data;
    host = (char *)NLMSG_DATA(nlh);
   }

  printk("host is %s\n", host);
  if(host!=NULL)
          {
                  SETBIT(a, sax_hash(host));
                  SETBIT(a, sdbm_hash(host));
          }
         
  return;
}

static int test_netlink(void) {
  nl_sk = netlink_kernel_create(NETLINK_TEST, 0, input, THIS_MODULE);

  if (!nl_sk) {
    printk(KERN_ERR "net_link: Cannot create netlink socket.\n");
    return -EIO;
  }
  printk("net_link: create socket ok.\n");
  return 0;
}

int check_http(const unsigned char* haystack, unsigned int len)
{
   char  url[100];
   char* host_tmp;
   char* url_tmp = url;
   
   if(len>4)
    {
    #if 1
     printk("len is %d\n", len);
     //printk("%s\n", haystack);
    #endif
     if(memcmp(haystack, "GET", 3)==0||memcmp(haystack,"POST", 4)==0)   
       {
         host_tmp = strstr(haystack,"Host:");
         host_tmp += 5;
         if(*host_tmp==' ')
             host_tmp++;

         while(*host_tmp!='\r')
             *url_tmp++ = *host_tmp++;

         *url_tmp='\0';  
         printk("http connect----Host:%s\n",url);
         if(GETBIT(a, sax_hash(url))&&GETBIT(a, sdbm_hash(url)))
                 {
             printk("we drop packet of host:%s", url);
             return 1;
            }
       }
   }
   return 0;
}

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 iphdr *iph = NULL;
    struct tcphdr *tcph = NULL;
    struct tcphdr _otcph;
    unsigned char* haystack;
    int hlen;


    iph = ip_hdr(*skb);
    haystack =(char*)iph+(iph->ihl*4);
    hlen = ntohs(iph->tot_len)-(iph->ihl*4);

    if (iph->protocol == IPPROTO_TCP) {
        tcph = skb_header_pointer(*skb, ip_hdrlen(*skb), sizeof(_otcph), &_otcph);
      
        haystack += tcph->doff*4;
        hlen -= tcph->doff*4;
     
     if(check_http(haystack, hlen))
             return NF_DROP;
    }

    return NF_ACCEPT;
}

static int __init hook_init(void)
{
             int i =0;
       printk("insmod url filter!\n");
       test_netlink();
       nfho.hook      = hook_func;
       nfho.hooknum   = NF_IP_LOCAL_OUT;
       nfho.pf        = PF_INET;
       nfho.priority  = NF_IP_PRI_FIRST;
   
       nf_register_hook(&nfho);

       for(;i<5;i++)
         a[i]=0;
       return 0;
}

static void __exit hook_exit(void)
{
    printk("rmmod url filter!\n");
    nf_unregister_hook(&nfho);
    if (nl_sk != NULL){
      sock_release(nl_sk->sk_socket);
     }
}

module_init(hook_init);
module_exit(hook_exit);

Makefile:

CODE:
obj-m += urlfilter.o
KDIR := /lib/modules/$(shell uname -r)/build

all:
        make -C $(KDIR) M=$(shell pwd) modules
        gcc -Wall -o url url.c
clean:
        make -C $(KDIR) M=$(shell pwd) clean
        rm -f *odule* user

使用的话
./url --host [url]过滤[/url]
./url  默认过滤

实际效果貌似不是很好^_^ 可能跟数据包的分片等有关系  希望大家能给出点完善的思路  我自己也将继续学习
也不知道思路对不对,自己瞎整的,还望各位指点

 
在CU的帖子
上一篇:内核态提取URL
下一篇:DNS中URL的提取的例子