IP分片重组的分析和常见碎片攻击 v0.2

标题: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
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值