免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 18915 | 回复: 16
打印 上一主题 下一主题

netlink+netfilter+BloomFilter内核态过滤URL [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-12-17 22:42 |只看该作者 |倒序浏览
利用一天的时间在各位老大dreamice godbach  platinum等大佬的指定下,终于完成了一个内核过滤url的初级版本,只是提供一个解决方案 应用层防火墙呵呵^_^
问题肯定还是多多的,对http协议的了解也是有限的...
   可以参考我的以下帖子
     http://linux.chinaunix.net/bbs/thread-1149479-1-1.html  这个是内核中提取URL的
     http://linux.chinaunix.net/bbs/v ... =1134519&extra=  这个是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:
  1.    #include <sys/stat.h>
  2. #include <unistd.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <sys/socket.h>
  6. #include <netinet/in.h>
  7. #include <arpa/inet.h>
  8. #include <sys/types.h>
  9. #include <string.h>
  10. #include <asm/types.h>
  11. #include <linux/netlink.h>
  12. #include <linux/socket.h>
  13. #include <getopt.h>

  14. #define NETLINK_TEST 21
  15. #define MAX_PAYLOAD 1024 /* maximum payload size*/

  16. struct sockaddr_nl src_addr, dest_addr;
  17. struct nlmsghdr *nlh = NULL;
  18. struct iovec iov;
  19. int sock_fd;
  20. struct msghdr msg;
  21. struct option longopts[] =
  22. {
  23.    {"help",no_argument, NULL, 'h'},
  24.    {"host",required_argument, NULL, 'H'},
  25.    {0,0,0,0}
  26.   };

  27. void print_help(char* str)
  28. {
  29. fprintf(stderr,"%s --host(-H)\n",str);
  30. fprintf(stderr,"%s --help(-h)\n",str);
  31. fprintf(stderr,"eg:\n%s --host [url]www.chinaunix.net[/url]\n",str);
  32. }
  33.       

  34. int main(int argc, char* argv[])
  35. {
  36.     int c;
  37.     char host[20]="www.baidu.com";
  38.    
  39.    while((c=getopt_long(argc, argv, "hH:", longopts, NULL))!=-1)   
  40.     {
  41.       switch(c)
  42.        {
  43.          case 'H':
  44.           {
  45.             sprintf(host,"%s",optarg);
  46.             break;
  47.           }
  48.          case 'h':
  49.            {
  50.             print_help(argv[0]);
  51.             return -1;
  52.            }
  53.         
  54.          default:
  55.           break;
  56.        }

  57.     }  

  58.    sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_TEST);
  59.    memset(&msg, 0, sizeof(msg));
  60.    memset(&src_addr, 0, sizeof(src_addr));
  61.    src_addr.nl_family = AF_NETLINK;
  62.    src_addr.nl_pid = getpid(); /* self pid */
  63.    src_addr.nl_groups = 0; /* not in mcast groups */
  64.    bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
  65.    memset(&dest_addr, 0, sizeof(dest_addr));
  66.    dest_addr.nl_family = AF_NETLINK;
  67.    dest_addr.nl_pid = 0; /* For Linux Kernel */
  68.    dest_addr.nl_groups = 0; /* unicast */

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

  77.    iov.iov_base = (void *)nlh;
  78.    iov.iov_len = nlh->nlmsg_len;
  79.    msg.msg_name = (void *)&dest_addr;
  80.    msg.msg_namelen = sizeof(dest_addr);
  81.    msg.msg_iov = &iov;
  82.    msg.msg_iovlen = 1;

  83.    printf(" Sending message. ...\n");
  84.    sendmsg(sock_fd, &msg, 0);
  85.    close(sock_fd);
  86.    return 0;
  87. }
复制代码



内核态urlfilter.c:
  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/skbuff.h>
  4. #include <linux/ip.h>
  5. #include <linux/in.h>
  6. #include <net/tcp.h>
  7. #include <net/icmp.h>
  8. #include <linux/netfilter.h>
  9. #include <linux/netfilter_ipv4.h>
  10. #include <linux/types.h>
  11. #include <linux/sched.h>
  12. #include <net/sock.h>
  13. #include <net/netlink.h>

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

  18. unsigned int a[5];

  19. static struct nf_hook_ops nfho;
  20. struct sock *nl_sk = NULL;
  21. EXPORT_SYMBOL_GPL(nl_sk);

  22. static char* host = NULL;

  23. unsigned int sax_hash(const char *key)
  24. {
  25.         unsigned int h=0;

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

  27.         return h%TABLE_SIZE;
  28. }

  29. unsigned int sdbm_hash(const char *key)
  30. {
  31.         unsigned int h=0;
  32.         while(*key) h=(unsigned char)*key++ + (h<<6) + (h<<16) - h;
  33.         return h%TABLE_SIZE;
  34. }

  35. void input (struct sock* sk, int len)
  36. {
  37.   struct sk_buff* skb = NULL;
  38.   struct nlmsghdr* nlh = NULL;

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

  45.   printk("host is %s\n", host);
  46.   if(host!=NULL)
  47.           {
  48.                   SETBIT(a, sax_hash(host));
  49.                   SETBIT(a, sdbm_hash(host));
  50.           }
  51.          
  52.   return;
  53. }

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

  56.   if (!nl_sk) {
  57.     printk(KERN_ERR "net_link: Cannot create netlink socket.\n");
  58.     return -EIO;
  59.   }
  60.   printk("net_link: create socket ok.\n");
  61.   return 0;
  62. }

  63. int check_http(const unsigned char* haystack, unsigned int len)
  64. {
  65.    char  url[100];
  66.    char* host_tmp;
  67.    char* url_tmp = url;
  68.    
  69.    if(len>4)
  70.     {
  71.     #if 1
  72.      printk("len is %d\n", len);
  73.      //printk("%s\n", haystack);
  74.     #endif
  75.      if(memcmp(haystack, "GET", 3)==0||memcmp(haystack,"POST", 4)==0)   
  76.        {
  77.          host_tmp = strstr(haystack,"Host:");
  78.          host_tmp += 5;
  79.          if(*host_tmp==' ')
  80.              host_tmp++;

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

  83.          *url_tmp='\0';  
  84.          printk("http connect----Host:%s\n",url);
  85.          if(GETBIT(a, sax_hash(url))&&GETBIT(a, sdbm_hash(url)))
  86.                  {
  87.              printk("we drop packet of host:%s", url);
  88.              return 1;
  89.             }
  90.        }
  91.    }
  92.    return 0;
  93. }

  94. unsigned int hook_func(unsigned int hooknum,
  95.                        struct sk_buff **skb,
  96.                        const struct net_device *in,
  97.                        const struct net_device *out,
  98.                        int (*okfn)(struct sk_buff *))
  99. {
  100.   struct iphdr *iph = NULL;
  101.     struct tcphdr *tcph = NULL;
  102.     struct tcphdr _otcph;
  103.     unsigned char* haystack;
  104.     int hlen;


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

  108.     if (iph->protocol == IPPROTO_TCP) {
  109.         tcph = skb_header_pointer(*skb, ip_hdrlen(*skb), sizeof(_otcph), &_otcph);
  110.       
  111.         haystack += tcph->doff*4;
  112.         hlen -= tcph->doff*4;
  113.      
  114.      if(check_http(haystack, hlen))
  115.              return NF_DROP;
  116.     }

  117.     return NF_ACCEPT;
  118. }

  119. static int __init hook_init(void)
  120. {
  121.              int i =0;
  122.        printk("insmod url filter!\n");
  123.        test_netlink();
  124.        nfho.hook      = hook_func;
  125.        nfho.hooknum   = NF_IP_LOCAL_OUT;
  126.        nfho.pf        = PF_INET;
  127.        nfho.priority  = NF_IP_PRI_FIRST;
  128.    
  129.        nf_register_hook(&nfho);

  130.        for(;i<5;i++)
  131.          a[i]=0;
  132.        return 0;
  133. }

  134. static void __exit hook_exit(void)
  135. {
  136.     printk("rmmod url filter!\n");
  137.     nf_unregister_hook(&nfho);
  138.     if (nl_sk != NULL){
  139.       sock_release(nl_sk->sk_socket);
  140.      }
  141. }

  142. module_init(hook_init);
  143. module_exit(hook_exit);
复制代码


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

  3. all:
  4.         make -C $(KDIR) M=$(shell pwd) modules
  5.         gcc -Wall -o url url.c
  6. clean:
  7.         make -C $(KDIR) M=$(shell pwd) clean
  8.         rm -f *odule* user
复制代码


使用的话
./url --host www.chinaunix.net过滤[url]www.chianunix.net[/url]
./url  默认过滤www.baidu.com

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


[ 本帖最后由 ubuntuer 于 2009-12-17 22:43 编辑 ]

评分

参与人数 1可用积分 +30 收起 理由
T-Bagwell + 30 精品文章

查看全部评分

论坛徽章:
0
2 [报告]
发表于 2009-12-17 22:44 |只看该作者
从图中可以看出是drop了部分包的,可能由于分片等之类结果可能不尽人意,希望大家给点思路

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
3 [报告]
发表于 2009-12-17 22:58 |只看该作者

回复 #2 ubuntuer 的帖子

其实你过滤的是www.chinaunix.net这个域名的包,呵呵,URL是什么东东,概念有点混啊

论坛徽章:
0
4 [报告]
发表于 2009-12-18 13:03 |只看该作者
恩  这个要考虑的问题太多了....
一般这应用层防火墙是这么做的吗?  在内核中千辛万苦的抓包分析DEBUG.....   太难了^_^

论坛徽章:
0
5 [报告]
发表于 2009-12-18 13:09 |只看该作者
姜哥看看这个
http://blog.chinaunix.net/u/12313/showart_148073.html
九贱大哥写的DNS过滤 vs URL过滤  受益匪浅   
研究下DNS协议

论坛徽章:
5
摩羯座
日期:2014-07-22 09:03:552015元宵节徽章
日期:2015-03-06 15:50:392015亚冠之大阪钢巴
日期:2015-06-12 16:01:352015年中国系统架构师大会
日期:2015-06-29 16:11:2815-16赛季CBA联赛之四川
日期:2018-12-17 14:10:21
6 [报告]
发表于 2009-12-18 13:58 |只看该作者
楼主是做这个工作吧?

论坛徽章:
0
7 [报告]
发表于 2009-12-18 14:02 |只看该作者
偶做的是基于DNS过滤URL的,效果比较明显。
如果基于http报文来过滤的话,感觉比较麻烦:wink:

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
8 [报告]
发表于 2009-12-18 14:04 |只看该作者
原帖由 duanjigang 于 2009-12-18 14:02 发表
偶做的是基于DNS过滤URL的,效果比较明显。
如果基于http报文来过滤的话,感觉比较麻烦:wink:


相当于是在源头做处理了, 通过DNS也请求不到域名对应的IP

论坛徽章:
0
9 [报告]
发表于 2009-12-18 14:28 |只看该作者
原帖由 Godbach 于 2009-12-18 14:04 发表


相当于是在源头做处理了, 通过DNS也请求不到域名对应的IP

yes,但是他如果通过IP来访问的话,就没治了,正如九贱说的

论坛徽章:
0
10 [报告]
发表于 2009-12-18 15:01 |只看该作者
原帖由 T-Bagwell 于 2009-12-18 13:58 发表
楼主是做这个工作吧?

我还没毕业,呵呵!!!  今年研三刚找完工作,现在是出于无聊中!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP