内核数据包处理.docx_第1页
内核数据包处理.docx_第2页
内核数据包处理.docx_第3页
内核数据包处理.docx_第4页
内核数据包处理.docx_第5页
已阅读5页,还剩5页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

数据包处理的一些建议前言我们大部分功能都需要解析数据,进行一系列的包匹配完成,但是目前,我们没有一个很好的框架来简化这个过程,大家处理数据包都是采用原生的linux内核接口,并且没有统一的规范要求如何使用这些接口,所以,存在大量的陷阱,一不留神就造成宕机。获取IP头部iph = ip_hdr(skb);struct sk_buff .sk_buff_data_ttransport_header;/* Transport layer header */sk_buff_data_tnetwork_header;/* Network layer header */sk_buff_data_tmac_header;/* Link layer header */.1)_netif_receive_skb()在进入三层处理前就对network_header进行了设置。2)ip_rcv()中详细的检查保证了IP头部到netfilter后是完整的。3)netfilter可以尽情使用ip头部。获取tcp头部错误1:tcph = tcp_hdr(skb);陷阱:netfilter的钩子点是属于TCP/IP协议栈的三层流程中,而四层的TCP头部此时还没有正确获取,只是初始化为IP头部的值,无法直接使用。错误2:tcph = (char *)iph + (iph-ihl ihl data的偏移void * skb_header_pointer(struct sk_buff *skb, int offset, int len, void *buffer)从skb的指定偏移取制定长度的数据,如果要取的数据位于线性区,直接返回其开始指针,否则,则拷贝到buffer中,并将buffer指针返回。printk(%pI4 %d - %pI4 %d len: %d ID: %dn,&iph-saddr,ntohs(tcph-source),&iph-daddr,ntohs(tcph-dest),ntohs(iph-tot_len),ntohs(iph-id);打印信息注意要点:1) IP地址输出Ipv4:%pI4 %pi4IPv6:%pI6 %pi62) MAC地址%pM %pm3)字节序的转换ntohs() ntohl() htons() htonl()_const_ntohl() _const_ntohs() _const_htonl() _const_htons()区别:_const_*()是编译时处理的。获取TCP负载风险:payload = (char *)tcph + tcph-doff * 4;陷阱1:数据包可能是非线性的,同TCP头部。陷阱2:TCP头部数据有可能是被篡改过的,tcph-doff如果很大怎么办?改进1:tcplen = skb-len - tcpoff;if (tcph-doff*4 sizeof(struct tcphdr) | tcplen doff*4)printk(Bad tcp.n);return NF_ACCEPT;if (skb_is_nonlinear(skb)printk(Nonlinear skb.n);return NF_ACCEPT;payload = (char *)tcph + tcph-doff * 4;payload_len = tcplen - tcph-doff * 4;if (payload_len = 0)return NF_ACCEPT;接口介绍:int skb_is_nonlinear(struct sk_buff *skb)判断skb的数据是否是非线性的改进2:char payload_buf1500;tcplen = skb-len - tcpoff;if (tcph-doff*4 sizeof(struct tcphdr) | tcplen doff*4)printk(Bad tcp.n);return NF_ACCEPT;payload_len = tcplen - tcph-doff * 4;if (payload_len = 0)return NF_ACCEPT;if (payload_len sizeof(payload_buf)return NF_ACCEPT;payload = skb_header_pointer(skb, tcpoff + tcph-doff*4, payload_len, payload_buf);if (payload = NULL)return NF_ACCEPT;改进3:tcplen = skb-len - tcpoff;if (tcph-doff*4 sizeof(struct tcphdr) | tcplen doff*4)printk(Bad tcp.n);return NF_ACCEPT;if (skb_ linearize(skb)printk(Can not linearize skb.n);return NF_ACCEPT;payload = (char *)tcph + tcph-doff * 4;payload_len = tcplen - tcph-doff * 4;if (payload_len = 0)return NF_ACCEPT;接口介绍:int skb_ linearize (struct sk_buff *skb)将skb线性化解析数据1)判断数据包内容风险1:if (payload0 != G | payload1 != E | payload2 != T)风险2:if (payload0 = G & payload1 = E & payload2 = T) & payload_len = 3)陷阱:如果payload的长度只有1个字节怎么办?改进:if (payload_len = (payload + payload_len)return;/* deal with host*/4)数据包操作错误:u32 len;len = payload_len - 512;if (len = 0)return;memcpy(buf, payload, len);陷阱:无符号数的强制类型转换,u32类型永远都是大于等于0的,当payload_len小于512时,判断就会不生效。改进:u32 len;if (payload_len = 512)return;len = payload_len - 512;memcpy(buf, payload, len);或者int len;len = payload_len - 512;if (len = payload_len - 2)return;memcpy(buf, &payload2, len);综述:数据包处理要时刻保持警醒,它可能不是你想象的样子!内存分配风险:void * xxx_alloc(unsigned long size, gfp_t flags)int malloc_size = size + sizeof(unsigned long);void *p;if (memory_use + malloc_size memory_max)return;p = kmalloc(malloc_size, flags);if (p = NULL)return NULL;memory_use += malloc_size;*p = size;p += sizeof(unsigned long);return p;陷阱1:如果需要申请的size是0会如何?陷阱2:多个cpu并发申请又会如何?改进:void * xxx_alloc(unsigned long size, gfp_t flags)int malloc_size = size + sizeof(unsigned long);void *p;int use;if (size = 0)return NULL;use = atomic_read(&memory_use);if (use + malloc_size memory_max)return;p = kmalloc(malloc_size, flags);if (p = NULL)return NULL;atomic_add(malloc_size, &memory_use);*p = size;p += sizeof(unsigned long);return p;问题:kmalloc(0, .)返回值是什么?建议:相同的内存反复申请释放的情况下,请使用kmem_cache_alloc建议的同步与互斥方法1) rcu锁使用场景:进程上下文用来配置,软中断上下文只读配置的情况好处:性能高,接口简单方法:hook函数读取配置,中断上下文:rcu_read_lock();data = rcu_dereference(global_data);/* deal with data*/rcu_read_unlock();基于proc文件等的配置下发,进程上下文:data = kmalloc(size, GFP_KERNEL);if (data = NULL)return;if (copy_from_user(data, user, len)returnold_data = rcu_dereference(global_data)rcu_assign_pointer(global_data, data);if (old_data)synchronize_rcu();kfree(old_data);另一种方法:if (old_data)call_rcu(&old_data-rcu, data_free_rcu);static data_free_rcu (struct rcu_head *head)struct xxx_data *data = container_of(head, struct xxx_data, rcu);kfree(data);注意1:synchronize_rcu()只能用于进程上下文,call_rcu()可以用于中断上下文。注意2:data_free_rcu的调用是软中断上下文,不能使用vfree。模块卸载:old_data = rcu_dereference(global_data)rcu_assign_pointer(global_data, NULL);if (old_data)synchronize_rcu();kfree(old_data

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论