请教一个问题,Netfilter过滤URL,遇到视频类网站内核崩溃
如题,用Netfilter写了一段代码来打印HOST和URI信息,编译后可正常打印出URL,当浏览器打开腾讯视频等一些内容的时候,内核就崩溃了,麻烦各位大牛帮忙分析一下,谢谢!#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/icmp.h>
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <asm/uaccess.h>
//#define DEBUG
MODULE_LICENSE("GPL");
char* h_tmp ; //HOST
char* u_tmp ; //URI
static struct nf_hook_ops nfho;
//获取HOST
void print_host(const unsigned char* start,unsigned int len)
{
char* host_tmp ;
char* url_tmp ;
int i = 0;
int j = 0;
if (len > 4)
{
if (0 == strncmp(start, "GET", 3) || 0 == strncmp(start, "POST", 4))
{
/*获取HOST的值*/
host_tmp = strstr(start,"Host:");
if(memcmp(host_tmp,"Host:",5) == 0)
{
host_tmp = host_tmp + 6; // 跳过HOST: 这6个字符
while(*host_tmp!='\r')
{
host_tmp++;
i++;
}
host_tmp -= i;
h_tmp = kmalloc((i + 1)*sizeof(char),GFP_KERNEL);
memcpy(h_tmp,host_tmp,i);
*(h_tmp+i) ='\0';
printk(">>>Host:%s",h_tmp);
kfree(h_tmp);
}
/*获取GET后面的参数*/
url_tmp = strstr(start,"/"); /*从/开始获取GET后面的URI部分*/
while(*url_tmp!=' ') /*到空格的地方结束*/
{
url_tmp++;
j++;
}
url_tmp -=j;
u_tmp = kmalloc((j + 1)*sizeof(char),GFP_KERNEL);
memcpy(u_tmp,url_tmp,j);
*(u_tmp+j) ='\0';
printk("%s\n",u_tmp);
kfree(u_tmp);
}
}
}
/* 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 *))
{
char * payload = NULL;
struct sk_buff* sb = skb; //定义一个Linux网络数据包缓存
struct iphdr *iph = ip_hdr(sb); //定义一个ip报文的数据报头
/*读取文件结束,过滤掉skb_buf为空以及iph为空的数据包*/
if(sb == NULL)
return NF_ACCEPT;
if(iph == NULL)
return NF_ACCEPT;
/*判断是否为TCP协议,不是TCP协议的数据包直接return NF_ACCEPT*/
if (iph && iph->protocol && (iph->protocol == IPPROTO_TCP)) {
//struct tcphdr* tcph = (void *)iph + iph->ihl*4; //TCP报文的头部
struct tcphdr* tcph =(void *)iph +(iph->ihl<<2);
unsigned int srcport = tcph->source; //源端口
unsigned int dstport = tcph->dest; //目的端口
unsigned int ack_seq_num = tcph->ack_seq; //ACK-SEQ的值
unsigned int seq_num = tcph->seq; //SEQ的值
unsigned int ip_saddr = ntohl(iph->saddr); //源IP
unsigned int ip_daddr = ntohl(iph->daddr); //目的IP
unsigned int len_tot = ntohs(iph->tot_len); //包总长度
unsigned int len_tcp = len_tot - iph->ihl*4 - tcph->doff*4; //TCP包的长度
/*判断tcph是否为空,为空直接返回NF_ACCEPT*******/
if(tcph == NULL)
return NF_ACCEPT;
/*判断目的端口是否为80************************/
if (ntohs(dstport) == 80 ) //筛选远端口或者目的
{
if (0 != skb_linearize(sb))
return NF_ACCEPT;
// payload = (char*)iph+(iph->ihl*4) + tcph->doff*4;
payload = (void *)tcph + (tcph->doff<<2);
print_host(payload,len_tcp); //DEBUG模式下打印HOST 和 URL
if (0 == strncmp(payload, "GET", 3) || 0 == strncmp(payload, "POST", 4))
{
printk("**************Request**************\n");
printk("In-Device :%s Out-Device:%s\n",in->name,out->name);
printk("Src IP :%d.%d.%d.%d \n", (ip_saddr & 0xff000000) >> 24,
(ip_saddr & 0x00ff0000) >> 16,
(ip_saddr & 0x0000ff00) >> 8,
(ip_saddr & 0x000000ff));
printk("Dst IP :%d.%d.%d.%d \n", (ip_daddr & 0xff000000) >> 24,
(ip_daddr & 0x00ff0000) >> 16,
(ip_daddr & 0x0000ff00) >> 8,
(ip_daddr & 0x000000ff));
printk("ID :%u\n",ntohs(iph->id));
printk("Src-Port:%d Dst-Port:%d\n", ntohs(srcport), ntohs(dstport));
printk("Seq :0x%2x\n", ntohl(seq_num));
printk("Ack_Seq :0x%2x\n", ntohl(ack_seq_num));
printk("Tcp len :%u\n",len_tcp);
printk("Next ack:%u\n",ntohl(seq_num + len_tcp ));
printk("*******************************\n");
return NF_ACCEPT;
}
return NF_ACCEPT;
}
}
return NF_ACCEPT;
}
/* 加载模块 */
int init_module() {
nfho.hook = hook_func; //钩子函数指针
nfho.hooknum = NF_INET_POST_ROUTING; //hook类型
nfho.pf = PF_INET; //协议簇,对于ipv4而言,是PF_INET
nfho.priority = NF_IP_PRI_FIRST; //优先级
nf_register_hook(&nfho);
pr_info("Filter add into kernel!\r\n");
return 0;
}
/* 清除模块 */
void cleanup_module() {
nf_unregister_hook(&nfho);
pr_info("Filter removed from kernel!\r\n");
}
回复 1# smillers
其实如果内核 oops 了,应该有一些有用的新的。
简单看了一下你解析 TCP 报文的问题,首先一个问题没有考虑,就是分片包的问题。如果是 TCP 的分片报文,那么根本就没有所谓的 tcp header 让你解引用了。
此外,一个吹毛求疵的小问题:
if(iph == NULL)
return NF_ACCEPT;
/*判断是否为TCP协议,不是TCP协议的数据包直接return NF_ACCEPT*/
if (iph && iph->protocol && (iph->protocol == IPPROTO_TCP)) {
最后那个条件判断,可以简化了为
if (iph->protocol == IPPROTO_TCP)
你 iph 都判断过了,没必要多两个冗余的条件。
具体可能还得通过kdump,或者串口抓点信息来看。
也可能是printk打印太频繁导致? Godbach 发表于 2014-06-02 22:52 static/image/common/back.gif
回复 1# smillers
其实如果内核 oops 了,应该有一些有用的新的。
版主说的这个,可以线性化一下 本帖最后由 huangbanban 于 2014-06-05 19:17 编辑
host_tmp = strstr(start,"Host:");
url_tmp = strstr(start,"/");
strstr函数的使用让我有些不安,没有限制查找的范围,因为是网络数据包
要是能够实现这样一个函数再使用,也许更安心一些吧
strnstr(char* s1, char*s2, int pos) 本帖最后由 smillers 于 2014-06-09 10:23 编辑
好像是strstr()函数的问题,重写了一个函数,解决了,现在已经不崩溃了回复 5# huangbanban
好像是strstr()函数的问题你,重写了一个,解决了,现在已经不崩溃了回复 5# huangbanban
恭喜恭喜,呵呵:D) 大哥,strstr是什么问题呀?
页:
[1]