内核数据包处理
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 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);