Beispiel #1
0
/* Process an incoming IP datagram fragment. */
static char *
ip_defrag(struct ip *iph, struct sk_buff *skb)
{
  struct ipfrag *prev, *next, *tmp;
  struct ipfrag *tfp;
  struct ipq *qp;
  char *skb2;
  unsigned char *ptr;
  int flags, offset;
  int i, ihl, end;

  if (!hostfrag_find(iph) && skb)
    hostfrag_create(iph);

  /* Start by cleaning up the memory. */
  if (this_host)
    if (this_host->ip_frag_mem > IPFRAG_HIGH_THRESH)
      ip_evictor();

  /* Find the entry of this IP datagram in the "incomplete datagrams" queue. */
  if (this_host)
    qp = ip_find(iph);
  else
    qp = 0;

  /* Is this a non-fragmented datagram? */
  offset = ntohs(iph->ip_off);
  flags = offset & ~IP_OFFSET;
  offset &= IP_OFFSET;
  if (((flags & IP_MF) == 0) && (offset == 0)) {
    if (qp != NULL)
      ip_free(qp);		/* Fragmented frame replaced by full
				   unfragmented copy */
    return 0;
  }

  /* ip_evictor() could have removed all queues for the current host */
  if (!this_host)
    hostfrag_create(iph);

  offset <<= 3;			/* offset is in 8-byte chunks */
  ihl = iph->ip_hl * 4;

  /*
    If the queue already existed, keep restarting its timer as long as
    we still are receiving fragments.  Otherwise, create a fresh queue
    entry.
  */
  if (qp != NULL) {
    /* ANK. If the first fragment is received, we should remember the correct
       IP header (with options) */
    if (offset == 0) {
      qp->ihlen = ihl;
      memcpy(qp->iph, iph, ihl + 8);
    }
    del_timer(&qp->timer);
    qp->timer.expires = jiffies() + IP_FRAG_TIME;	/* about 30 seconds */
    qp->timer.data = (unsigned long) qp;	/* pointer to queue */
    qp->timer.function = ip_expire;	/* expire function */
    add_timer(&qp->timer);
  }
  else {
    /* If we failed to create it, then discard the frame. */
    if ((qp = ip_create(iph)) == NULL) {
      kfree_skb(skb, FREE_READ);
      return NULL;
    }
  }
  /* Attempt to construct an oversize packet. */
  if (ntohs(iph->ip_len) + (int) offset > 65535) {
    // NETDEBUG(printk("Oversized packet received from %s\n", int_ntoa(iph->ip_src.s_addr)));
    nids_params.syslog(NIDS_WARN_IP, NIDS_WARN_IP_OVERSIZED, iph, 0);
    kfree_skb(skb, FREE_READ);
    return NULL;
  }
  /* Determine the position of this fragment. */
  end = offset + ntohs(iph->ip_len) - ihl;

  /* Point into the IP datagram 'data' part. */
  ptr = (unsigned char *)(skb->data + ihl);

  /* Is this the final fragment? */
  if ((flags & IP_MF) == 0)
    qp->len = end;

  /*
    Find out which fragments are in front and at the back of us in the
    chain of fragments so far.  We must know where to put this
    fragment, right?
  */
  prev = NULL;
  for (next = qp->fragments; next != NULL; next = next->next) {
    if (next->offset >= offset)
      break;			/* bingo! */
    prev = next;
  }
  /*
    We found where to put this one.  Check for overlap with preceding
    fragment, and, if needed, align things so that any overlaps are
    eliminated.
  */
  if (prev != NULL && offset < prev->end) {
    nids_params.syslog(NIDS_WARN_IP, NIDS_WARN_IP_OVERLAP, iph, 0);
    i = prev->end - offset;
    offset += i;		/* ptr into datagram */
    ptr += i;			/* ptr into fragment data */
  }
  /*
    Look for overlap with succeeding segments.
    If we can merge fragments, do it.
  */
  for (tmp = next; tmp != NULL; tmp = tfp) {
    tfp = tmp->next;
    if (tmp->offset >= end)
      break;			/* no overlaps at all */
    nids_params.syslog(NIDS_WARN_IP, NIDS_WARN_IP_OVERLAP, iph, 0);

    i = end - next->offset;	/* overlap is 'i' bytes */
    tmp->len -= i;		/* so reduce size of    */
    tmp->offset += i;		/* next fragment        */
    tmp->ptr += i;
    /*
      If we get a frag size of <= 0, remove it and the packet that it
      goes with. We never throw the new frag away, so the frag being
      dumped has always been charged for.
    */
    if (tmp->len <= 0) {
      if (tmp->prev != NULL)
	tmp->prev->next = tmp->next;
      else
	qp->fragments = tmp->next;

      if (tmp->next != NULL)
	tmp->next->prev = tmp->prev;

      next = tfp;		/* We have killed the original next frame */

      frag_kfree_skb(tmp->skb, FREE_READ);
      frag_kfree_s(tmp, sizeof(struct ipfrag));
    }
  }
  /* Insert this fragment in the chain of fragments. */
  tfp = NULL;
  tfp = ip_frag_create(offset, end, skb, ptr);

  /*
    No memory to save the fragment - so throw the lot. If we failed
    the frag_create we haven't charged the queue.
  */
  if (!tfp) {
    nids_params.no_mem("ip_defrag");
    kfree_skb(skb, FREE_READ);
    return NULL;
  }
  /* From now on our buffer is charged to the queues. */
  tfp->prev = prev;
  tfp->next = next;
  if (prev != NULL)
    prev->next = tfp;
  else
    qp->fragments = tfp;

  if (next != NULL)
    next->prev = tfp;

  /*
    OK, so we inserted this new fragment into the chain.  Check if we
    now have a full IP datagram which we can bump up to the IP
    layer...
  */
  if (ip_done(qp)) {
    skb2 = ip_glue(qp);		/* glue together the fragments */
    fprintf(stderr,"this is ipfragment.sd");
	return (skb2);
  }
  return (NULL);
}
Beispiel #2
0
// 每重组一个ip碎片,就会更新对应ipq的timer
//
//
static char *
ip_defrag(struct ip *iph, struct sk_buff *skb)
{
	struct ipfrag *prev, *next, *tmp;
	// 指向一个碎片
	struct ipfrag *tfp;
	// 指向一个队列
	struct ipq *qp;
	// 用来放返回值
	char *skb2;
	// 用来进行字节操作
	unsigned char *ptr;
	int flags, offset;
	int i, ihl, end;

	// 如果成功更新全局变量this_host, 并且skb是有内容的
	if (!hostfrag_find(iph) && skb)
		// 生成一个碎片
		hostfrag_create(iph);

	/* Start by cleaning up the memory. */
	// 如果当前host不为空
	if (this_host)
		// 如果大于上限
		if (this_host->ip_frag_mem > IPFRAG_HIGH_THRESH)
			// 裁剪掉一些ip碎片,直到 ip_frag_mem < IPFRAG_LOW_THRESH
			ip_evictor();

	/* Find the entry of this IP datagram in the "incomplete datagrams" queue. */
	// 如果host存在
	if (this_host)
		// 找到与这个ip头相关的ip队列
		qp = ip_find(iph);
	else
		// 否则设置队列为空
		qp = 0;
	

	/* Is this a non-fragmented datagram? */
	// ip_off是一个16位的字段,高3位用来保存标志信息,低12位用来保存当前碎片的偏移
	offset = ntohs(iph->ip_off);  /* 先把ip_offset这个字段取出来 */
	// 把高3位取出来
	flags = offset & ~IP_OFFSET;
	// 把低13位取出来
	offset &= IP_OFFSET;
	// IP_MF==0表示当前收到是碎片后面没有碎片了,并且当前收到碎片是第一个碎片,
	// 显然当前碎片虽在的ip报文仅仅有一个碎片
	// 那么当前碎片(刚刚收到的碎片)并不需要重组,因此可以返回了
	if (((flags & IP_MF) == 0) && (offset == 0))
	{
		// 如果队列不为空就释放掉
		if (qp != NULL)
			ip_free(qp);		/* Fragmented frame replaced by full unfragmented copy */
		return 0;
	}

	/* ip_evictor() could have removed all queues for the current host */
	// 如果host全部被移出了,那么重新创建一个,针对当前ip头的host
	// 但是,这个host并不会包括任何东西,它是一个空的,没有ip队列
	if (!this_host)
		hostfrag_create(iph);
	// 计算offset和头长度
	// 这个offset是刚刚收到的这个碎片的offset
	offset <<= 3;			/* offset is in 8-byte chunks */
	ihl = iph->ip_hl * 4;


	/*
	  If the queue already existed, keep restarting its timer as long as
	  we still are receiving fragments.  Otherwise, create a fresh queue
	  entry.
	*/
	// 如果队列存在
	if (qp != NULL)
	{
		/* ANK. If the first fragment is received, we should remember the correct
		   IP header (with options) */
		// 如果偏移量为0,可能是该pi报文中的第一个碎片,因此要把前8字节保存下来
		if (offset == 0)
		{
			// 保存头长度
			qp->ihlen = ihl;
			// 拷贝头信息+8字节
			memcpy(qp->iph, iph, ihl + 8);
		}
		// 停止计时
		del_timer(&qp->timer);
		// 重新计时
		qp->timer.expires = jiffies() + IP_FRAG_TIME;	/* about 30 seconds */
		// 设置关联
		qp->timer.data = (unsigned long) qp;	/* pointer to queue */
		// 注册回调函数
		qp->timer.function = ip_expire;	/* expire function */
		// 添加计数器
		add_timer(&qp->timer);
	}
	// 否则队列不存在
	else
	{
		/* If we failed to create it, then discard the frame. */
		// 试图创建一个
		if ((qp = ip_create(iph)) == NULL)
		{
			// 如果创建队列失败,那么释放当前碎片的空间并返回
			kfree_skb(skb, FREE_READ);
			return NULL;
		}
	}

	
	/* Attempt to construct an oversize packet. */
	// 如果头+长度 超长, 释放空间
	if (ntohs(iph->ip_len) + (int) offset > 65535)
	{
		// NETDEBUG(printk("Oversized packet received from %s\n", int_ntoa(iph->ip_src.s_addr)));
		nids_params.syslog(NIDS_WARN_IP, NIDS_WARN_IP_OVERSIZED, iph, 0);
		kfree_skb(skb, FREE_READ);
		return NULL;
	}

	
	/* Determine the position of this fragment. */
	// 刚刚收到的碎片分组 + 刚刚收到的碎片ip包大小 - 刚刚收到的碎片ip包头大小
	// = 刚刚收到的分组的结尾
	end = offset + ntohs(iph->ip_len) - ihl;

	/* Point into the IP datagram 'data' part. */
	// 将指针,指向刚刚收到的碎片ip包的数据开头部分
	// prt 指向肉
	ptr = (unsigned char *)(skb->data + ihl);

	/* Is this the final fragment? */
	// 如果这是最后一个碎片,那么,整个队列的长度,就是当前的end
	// 否则qp->len会在后面更改,因为会有重叠部分
	if ((flags & IP_MF) == 0)
		qp->len = end;

	/*
	  Find out which fragments are in front and at the back of us in the
	  chain of fragments so far.  We must know where to put this
	  fragment, right?
	*/
	prev = NULL;
	// 给定一个offset,在所有的fragments中找到第一个
	// 拥有不小于给定offset的offset的碎片,然后终止循环
	// 由此可以猜测,这一个函数,其实是将某一个新来的碎片插入到
	// 队列合适的位置,保证offset升序排列
	// next 指向的是第一个不小于当前offset的碎片
	// pre指向的是前一个碎片
	for (next = qp->fragments; next != NULL; next = next->next)
	{
		if (next->offset >= offset)
			break;			/* bingo! */
		prev = next;
	}
	/*--------------------------------------------------------------
	注意: 
		next 指向的是第一个排在当前碎片后面的 碎片;
		pre  指向的是第一个排在当前碎片前面的 碎片。
		next 有可能offset与当前碎片的offset一样
	----------------------------------------------------------------*/
	
	
	/*
	  We found where to put this one.  Check for overlap with preceding
	  fragment, and, if needed, align things so that any overlaps are
	  eliminated.
	*/
	// 如果有排在当前碎片前面的分组,并且, 该分组的结束比当前分组的offset大
	// 说明有重叠,应噶修正当前offset,以先来的为准
	if (prev != NULL && offset < prev->end)
	{
		nids_params.syslog(NIDS_WARN_IP, NIDS_WARN_IP_OVERLAP, iph, 0);
		i = prev->end - offset;
		// 将当前收到的碎片的offset增加i
		offset += i;		/* ptr into datagram */
		// 将当前收到的碎片的指正向后移动i
		ptr += i;			/* ptr into fragment data */
	}
	
	/*
	  Look for overlap with succeeding segments.
	  If we can merge fragments, do it.
	*/
	// 现在往后查看是否有重叠的
	// 从next开始
	for (tmp = next; tmp != NULL; tmp = tfp)
	{
		// temp总是等于next
		tfp = tmp->next;
		// 如果next的 offset >= 当前分组的end,那就没有问题
		if (tmp->offset >= end)
			break;			/* no overlaps at all */

		// 否则警报
		nids_params.syslog(NIDS_WARN_IP, NIDS_WARN_IP_OVERLAP, iph, 0);
		// 记录当前的结束与下一个碎片的开始重叠多少
		i = end - next->offset;	/* overlap is 'i' bytes */
		// 将next碎片的长度减少i
		tmp->len -= i;		/* so reduce size of    */
		// 将next碎片的开始增加i
		tmp->offset += i;		/* next fragment        */
		// 将指针也要向后移动i
		tmp->ptr += i;
		/*
		  If we get a frag size of <= 0, remove it and the packet that it
		  goes with. We never throw the new frag away, so the frag being
		  dumped has always been charged for.
		*/
		// 如果此时next碎片的长度小于0, 那么摘掉next节点
		if (tmp->len <= 0)
		{
			if (tmp->prev != NULL)
				tmp->prev->next = tmp->next;
			else
				qp->fragments = tmp->next;

			if (tmp->next != NULL)
				tmp->next->prev = tmp->prev;

			// tfp原来就等于next->next,所以原来的next节点被摘掉了
			next = tfp;		/* We have killed the original "next" frame */

			// 释放掉frag节点对应的内存
			frag_kfree_skb(tmp->skb, FREE_READ);
			// 释放掉frag节点
			frag_kfree_s(tmp, sizeof(struct ipfrag));
		}
	}

	
	/* Insert this fragment in the chain of fragments. */
	tfp = NULL;
	// offset是刚刚接收到的碎片偏移,按字节
	// end   是刚刚接收到的碎片的结束字节
	// skb   是传进来的一个内存空间,应该事先分配好
	// prt   是指向这个碎片第一个数据的指针
	tfp = ip_frag_create(offset, end, skb, ptr);
	/*---------------------------------------------------
	注意:  
		ip_frag_create函数只是创建一个ip_frag,还没有吧
		它挂载到队列中
	-----------------------------------------------------*/

	/*
	  No memory to save the fragment - so throw the lot. If we failed
	  the frag_create we haven't charged the queue.
	*/
	if (!tfp)
	{
		nids_params.no_mem("ip_defrag");
		kfree_skb(skb, FREE_READ);
		return NULL;
	}
	
	/* From now on our buffer is charged to the queues. */
	// 将刚刚创建的ip_frag挂载到队列中去了
	tfp->prev = prev;
	tfp->next = next;
	if (prev != NULL)
		prev->next = tfp;
	else
		qp->fragments = tfp;

	if (next != NULL)
		next->prev = tfp;

	/*
	  OK, so we inserted this new fragment into the chain.  Check if we
	  now have a full IP datagram which we can bump up to the IP
	  layer...
	*/
	// 检查是否完整
	if (ip_done(qp))
	{
		skb2 = ip_glue(qp);		/* glue together the fragments */
		return (skb2);
	}

	// 如果没有完整,那么返回空,继续执行
	return (NULL);
}