内核数据包处理

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

内核数据包处理

数据包处理的一些建议

前言

我们大部分功能都需要解析数据,进行一系列的包匹配完成,但是目前,我们没有一个很好的框架来简化这个过程,大家处理数据包都是采用原生的linux内核接口,并且没有统一的规范要求如何使用这些接口,所以,存在大量的陷阱,一不留神就造成宕机。

获取IP头部

iph = ip_hdr(skb);

struct sk_buff {

......

sk_buff_data_t t ransport_header; /*

Transport 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 << 2);

陷阱:

数据包可能是非线性的

sk_buff

.

.

.

head

data

end

tail .

..Head room IP 头部Tail room Frags Frags TCP 头部

改进:

接口介绍:

tcpoff = skb_network_offset(skb) + (iph->ihl << 2);

skb_network_offset(struct skb_buff

计算三层头部相对于skb->data的偏移

void * skb_header_pointer(struct

从skb的指定偏移取制定长度的数据,如果要取的数据位于线性区,直接返回其开始指针,否则,则拷贝到buffer中,并将buffer指针返回。

打印信息

printk("%pI4 %d -----> %pI4 %d len: %d ID: %d\n",

&iph->saddr,

ntohs(tcph->source),

注意要点:

1) IP地址输出

Ipv4:%pI4 %pi4

IPv6:%pI6 %pi6

2) MAC地址

%pM %pm

3)字节序的转换

ntohs() ntohl() htons() htonl()

__const_ntohl() __const_ntohs() __const_htonl() __const_htons()

区别:__const_*()是编译时处理的。

获取TCP负载

风险:

4;

payload = (char *)tcph + tcph->doff *

陷阱1:

数据包可能是非线性的,同TCP头部。

陷阱2:

TCP头部数据有可能是被篡改过的,

tcph->doff如果很大怎么办?

改进1:

接口介绍:

int skb_is_nonlinear(struct sk_buff

判断skb的数据是否是非线性的

改进2:

char payload_buf[1500];

tcplen = skb->len - tcpoff;

if (tcph->doff*4 < sizeof(struct tcphdr) || tcplen < tcph->doff*4)

{

printk("Bad tcp.\n");

return NF_ACCEPT;

}

改进3:

tcplen = skb->len - tcpoff;

if (tcph->doff*4 < sizeof(struct tcphdr) || tcplen < tcph->doff*4) {

printk("Bad tcp.\n");

return NF_ACCEPT;

}

if (skb_ linearize(skb))

接口介绍:

int skb_ linearize (struct sk_buff

将skb线性化

解析数据

1)判断数据包内容

风险1:

if (payload[0] != 'G' || payload[1] != 风险2:

if ((payload[0] == 'G' && payload[1] ==

陷阱:

如果payload的长度只有1个字节怎么办?

改进:

2) 查找数据包中的某个字符串

风险:

陷阱:

可能会越界,数据包不一定是以'\0'结束。 G H /T E T T P 烫烫payload payload_len

改进:

一定要使用这一系列的函数:

strnchr

strncpy

strncat

strncmp if (payload_len < 3 || payload[0] != 'G' host = strstr(payload, "Host: "); host = strnstr(payload, "Host: ", payload_len);

相关文档
最新文档