标题:IP分片重组的分析和常见碎片攻击 v0.2 作者:yawl@nsfocus.com 主页: www.nsfocus.com 时间:v0.1:2000/07; v0.2:2000/09 一前言 本文对linux的IP组装算法进行了分析,因为IP碎片经常用于DOS等攻击,在文章后面我结合 了一些攻击方法进行了更进一步的说明。内核主要参考版本是2.2.16,另外简要的介绍了 2.4.0-test3中的一些变化. 这篇文章基于我今年7月的一份笔记,但增加了许多新的内容。其实本来这月的月刊投稿准备 写一些netfilter的东西,但工作太紧,只好写自己比较熟悉的题材了:-)。成文比较仓促 ,如果出现了什么问题,欢迎指正。 二目录 1-概述 2-关键数据结构 3-重要函数说明 4-2.4系列的变化 5-常见碎片攻击 1. 概述 在linux源代码中,ip分片重组的全部程序几乎都在都在/net/ipv4/ip_fragment.c 文件中。其对外提供一个函数接口ip_defrag()。其函数原型如下: struct sk_buff *ip_defrag(struct sk_buff *skb) 众所周知,网络数据报在linux的网络堆栈中是以sk_buff的结构传送的,ip_defrag()的 功能就是接受分片的数据包(sk_buff),并试图进行组合,当完整的包组合好时,将新的 sk_buff返还,否则返回一个空指针。 此函数在其他文件中的调用如下: ip层接收主函数为ip_rcv()(/net/ipv4/ip_input.c),任何IP包都需经过此函数处理。 如果此包是发往本机,则调用ip_local_deliver()函数(/net/ipv4/ip_input.c)进行 处理,一般的系统碎片只有在到达最终目的的时候才进行重组(尽管在传输过程中可 能被进一步分成更小的片)。在ip_local_deliver()中我们可发现如下代码: if (sysctl_ip_always_defrag == 0 && /*编译时未设置提前组装*/ (iph->frag_off & htons(IP_MF|IP_OFFSET))) { /*判断是否是分片包*/ skb = ip_defrag(skb); /*条件满足,进行组装*/ if (!skb) /*若组装好则进行下一步处理,出错 return 0; 或仍未组装完返回*/ iph = skb->nh.iph; /*重新定位ip头的指针*/ } iph->frag_off只有在设置MF(more fragment)或offset!=0才意味着是分片包,因此 此处的检验理所当然,但为什么判断sysctl_ip_always_defrag == 0呢? 在看ip_rcv()时我们应该已经注意到在刚进行了版本号,长度,校验和等判断后,有如下 一段代码: if (sysctl_ip_always_defrag != 0 && iph->frag_off & htons(IP_MF|IP_OFFSET)) { skb = ip_defrag(skb); if (!skb) return 0; iph = skb->nh.iph; ip_send_check(iph); } 即如果sysctl_ip_always_defrag==1的话,ip_defrag()的调用位置将有变化,对任何 进来的IP分片都要进行重组,可以想像,如果此机器作路由器的话,将对所有的分片 组装好后,才会进行转发。此举一般是没有必要的。这个值可以通过sysctl命令动态 设置,用sysctl -a可以看到在一般的系统中,此值被设为0: #sysctl -a ...... net.ipv4.ip_always_defrag = 0 ...... 2. 关键数据结构(2.2系列) 每一个分片用ipfrag结构表示: /* Describe an IP fragment. */ struct ipfrag { int offset; /* offset of fragment in IP datagram */ int end; /* last byte of data in datagram */ int len; /* length of this fragment */ struct sk_buff *skb; /* complete received fragment */ unsigned char *ptr; /* pointer into real fragment data */ struct ipfrag *next; /* linked list pointers */ struct ipfrag *prev; }; 这些分片形成一个双向链表(在linux内核中,若需要使用链表,除非有特殊需要,否则推荐 双向链表,见document/CodingStyle),表示一个未组装完的分片队列(属于一个ip包)。 这个链表的头指针要放在ipq结构中: /* Describe an entry in the "incomplete datagrams" queue. */ struct ipq { struct iphdr *iph; /* pointer to IP header */ struct ipq *next; /* linked list pointers */ struct ipfrag *fragments; /* linked list of received fragments */ int len; /* total length of original datagram */ short ihlen; /* length of the IP header */ struct timer_list timer; /* when will this queue expire? */ struct ipq **p
IP分片重组的分析和常见碎片攻击 v0.2
最新推荐文章于 2022-02-22 09:10:46 发布