Linux kernel过滤网络数据包
来源:互联网 发布:程序员的逻辑题 编辑:程序博客网 时间:2024/05/19 18:46
原理剖析
内核过滤数据包,第一个想到的是iptables,这个东西是用户层的, 深入点就是netfilter了。 netfilter的5个钩子点可以实现这个。
对内核熟悉点的人会知道layer7, 有的使用框架snort,layer7已经不更新,继承者是ipp2p, 这些都可以。还有Libpcap不知道怎么做,目前没有去深入研究过。
方案选定
我的本意是针对含有特殊字符串的数据包重定向端口,其他的数据包直接发送到网络上。
但是实际情况如何,目前我也没时间移植到系统是,只是在本地做了实验,原理上是可以实现的。
测试代码如下
#include <linux/types.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/netfilter_ipv4.h>#include <linux/ip.h>#include <linux/tcp.h>#define DRIVER_AUTHOR "AlexKey"#define DRIVER_DESC "HTTP packets manipulations"#define DEBUG 1static struct nf_hook_ops nfho;static 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 *ip_header; struct tcphdr *tcp_header; struct ethhdr *eth_header; u32 saddr, daddr; u16 source, dest; int i = 0; int found = 0; struct ts_config *conf; struct ts_state state; const char *pattern = "GET / HTTP/1.1"; conf = textsearch_prepare("kmp", pattern, strlen(pattern), GFP_KERNEL, TS_AUTOLOAD); if (IS_ERR(conf)) { //err = PTR_ERR(conf); return NF_ACCEPT; } /* Get all the headers */ eth_header = (struct ethhdr *)skb_mac_header(skb); ip_header = (struct iphdr *)skb_network_header(skb); skb_set_transport_header(skb, ip_header->ihl * 4); tcp_header = (struct tcphdr *)skb_transport_header(skb); /* If the packet source or dest are not 80 then the packet is not for us :) */ //if(tcp_header->source != ntohs(80) && tcp_header->dest != ntohs(80)) if(tcp_header->source == ntohs(80)) { printk(KERN_INFO "Recv skb_len=%d, data_len=%d, truesize=%d\n", skb->len, skb->data_len, skb->truesize); //if (skb->data_len > 0) { printk(KERN_INFO "\n[%s]\n", skb->data); } return NF_ACCEPT; } else if (tcp_header->dest == ntohs(80) && found == 0) { printk(KERN_INFO "Send skb_len=%d, data_len=%d, truesize=%d\n", skb->len, skb->data_len, skb->truesize); /*if (skb->len > 0) { for (i=0; i < skb->len; i++) { //Below is 'GE' from "GET / HTTP/1.1" if (0x47 == *(skb->data+i) && 0x45 == *(skb->data+i + 1)) { printk(KERN_INFO "===========Found GET===1==========\n"); found = 1; } if (0x45 == *(skb->data+i) && 0x47 == *(skb->data+i + 1)) { printk(KERN_INFO "===========Found GET===2==========\n"); return NF_ACCEPT; }*/ //printk(KERN_INFO "%x ", *(skb->data+i)); //if (i % 8 == 0) // printk("\nline=[%d]", i); if (UINT_MAX != skb_find_text(skb, 0, skb->len, conf, &state)) { printk(KERN_INFO "skb_find_text find the test\n"); //break; } else { printk(KERN_INFO "Not found anything\n"); } //textsearch_destroy(conf); //} //} return NF_ACCEPT; } else { printk(KERN_INFO "dest (%d) skb_len=%d, data_len=%d, truesize=%d\n", tcp_header->dest, skb->len, skb->data_len, skb->truesize); return NF_ACCEPT; }#if DEBUG > 0 printk(KERN_INFO "[HTTP] Got packet on %d from %d\n", htons(tcp_header->dest), htons(tcp_header->source));#endif saddr = ip_header->saddr; daddr = ip_header->daddr; source = tcp_header->source; dest = tcp_header->dest; /* In link layer header change sender mac to our ethernet mac and destination mac to sender mac :) ping-pong */ memcpy(eth_header->h_dest,eth_header->h_source,ETH_ALEN); memcpy(eth_header->h_source,skb->dev->dev_addr,ETH_ALEN); /* Set new link layer headers to socket buffer */ skb->data = (unsigned char *)eth_header; skb->len += ETH_HLEN; /* Setting it as outgoing packet */ skb->pkt_type = PACKET_OUTGOING; /* Swap the IP headers sender and destination addresses */ memcpy(&ip_header->saddr, &daddr, sizeof(u32)); memcpy(&ip_header->daddr, &saddr, sizeof(u32)); /* If transmission suceeds then report it stolen if it fails then drop it */ if(dev_queue_xmit(skb)==NET_XMIT_SUCCESS){#if DEBUG > 0printk(KERN_INFO "[HTTP] Successfully sent packet\n");#endif return NF_STOLEN; } else {#if DEBUG > 0printk(KERN_INFO "[HTTP] Sending failed\n");#endif return NF_DROP; }}static int __init init_main(void) { nfho.hook = hook_func; //nfho.hooknum = 0; nfho.pf = PF_INET; nfho.priority = NF_IP_PRI_FIRST; nfho.hooknum = NF_INET_POST_ROUTING; /*NF_INET_PRE_ROUTING;*/ nf_register_hook(&nfho);#if DEBUG > 0 printk(KERN_INFO "[HTTP] Successfully inserted protocol module into kernel.\n");#endif return 0;}static void __exit cleanup_main(void) { nf_unregister_hook(&nfho);#if DEBUG > 0 printk(KERN_INFO "[HTTP] Successfully unloaded protocol module.\n");#endif}module_init(init_main);module_exit(cleanup_main);MODULE_LICENSE("GPL v3");MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);
样例代码注解
初始化,是采用检测发送POSTROUTING 锚点,
一开始是通过对比二进制数据GET判断这个请求是什么。
后来找到了更高级的函数skb_find_text(). 非常实用, 由这个函数来寻找数据。
对于目的端口不是80的数据则通过dev_queue_xmit(skb)直接发送。
源码地址qianguozheng
0 0
- Linux kernel过滤网络数据包
- linux kernel 处理网络数据包流程
- Linux网络数据包分析
- 【Linux 驱动】Netfilter/iptables (五) 数据包过滤
- 过滤数据包
- linux kernel网络驱动
- Linux 中的网络数据包捕获
- Linux traceroute --追踪网络数据包
- 【笔记】wincap网络数据包的过滤与分析
- 基于Windows系统下网络数据包过滤方法的分析
- Linux Kernel 内存管理 - 网络
- linux kernel 网络协议栈
- linux 函数hook实现数据包过滤基本框架
- Linux 钩子函数 实现数据包的过滤实例
- Linux 钩子函数 实现数据包的过滤实例
- linux 函数hook实现数据包过滤基本框架
- Linux内核网络部分数据包流程
- linux网络编程之:UDP数据包格式
- uva 11549 Calculator Conundrum 周期,哇!这也能过
- 开篇 奋斗
- 关于caffe安装中的一些小问题
- JavaScript原型链
- hive调用Linux的shell命令测试
- Linux kernel过滤网络数据包
- 算法学习--二分法查找
- nat穿透
- ROS navigation相关概念小结
- R-CNN和SPP-net
- RelativeLayout
- 博客迁移
- Red Hat Linux下安装JDK
- KVO要传递对象而不是属性