- 论坛徽章:
- 0
|
利用一天的时间在各位老大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:
- #include <sys/stat.h>
- #include <unistd.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <sys/types.h>
- #include <string.h>
- #include <asm/types.h>
- #include <linux/netlink.h>
- #include <linux/socket.h>
- #include <getopt.h>
- #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]www.chinaunix.net[/url]\n",str);
- }
-
- int main(int argc, char* argv[])
- {
- int c;
- char host[20]="www.baidu.com";
-
- 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:
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/skbuff.h>
- #include <linux/ip.h>
- #include <linux/in.h>
- #include <net/tcp.h>
- #include <net/icmp.h>
- #include <linux/netfilter.h>
- #include <linux/netfilter_ipv4.h>
- #include <linux/types.h>
- #include <linux/sched.h>
- #include <net/sock.h>
- #include <net/netlink.h>
- #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:
- 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 www.chinaunix.net过滤[url]www.chianunix.net[/url]
./url 默认过滤www.baidu.com
实际效果貌似不是很好^_^ 可能跟数据包的分片等有关系 希望大家能给出点完善的思路 我自己也将继续学习
也不知道思路对不对,自己瞎整的,还望各位指点
[ 本帖最后由 ubuntuer 于 2009-12-17 22:43 编辑 ] |
评分
-
查看全部评分
|