libnids中TCP/IP栈实现细节分析(下)——IP分片重组

利用libnids和ibcap进行tcp会话的重组 利用libnids 和ibcap进行tcp会话的重组 立即下载

在此之前,如果不懂IP分片技术的话,请参照这里。IP分片技术比较简单暴力,没有TCP那样复杂复杂的窗口协议。基本上只是暴力的拆分和重组,代码基本在ip_defragment.c中。

先从总体上说说。首先,每个IP(主机)都会有IP分片包(注意是IP,不是IP对)。所以,每个IP都有一个如下的结构体来维护上面的所以IP分片:

struct hostfrags {
  struct ipq *ipqueue;//这里维护IP碎片队列
  int ip_frag_mem;
  u_int ip;//主机对应的IP地址
  //很明显,下面三行告诉我们,这是哈希表的一个元素
  int hash_index;
  struct hostfrags *prev;
  struct hostfrags *next;
};
//下面这个就是维护所有IP的哈希表了。
static struct hostfrags **fragtable;

每个IP下面又有很多的被分片的IP包——IP碎片队列,IP碎片队列的定义在这:

/* Describe an entry in the "incomplete datagrams" queue. */
struct ipq {
  unsigned char *mac;        /* pointer to MAC header                */
  struct ip *iph;        /* pointer to IP header                 */
  int len;            /* total length of original datagram    */
  short ihlen;            /* length of the IP header              */
  short maclen;            /* length of the MAC header             */
  struct timer_list timer;    /* when will this queue expire?         */
  struct ipfrag *fragments;    /* linked list of received fragments    */
  struct hostfrags *hf;
  struct ipq *next;        /* linked list pointers                 */
  struct ipq *prev;
  // struct device *dev;    /* Device - for icmp replies */
};

最终的IP碎片的定义在这:

/* 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;
};

由于libnids中的分片重组代码是从内核中拿出来修改的,所以保留了内核的注释。这里就不多做解释了。

好了步入处理逻辑,照例,先看初始化:

void ip_frag_init(int n)
{
  struct timeval tv;
 
  gettimeofday(&tv, 0);
  time0 = tv.tv_sec;
  fragtable = (struct hostfrags **) calloc(n, sizeof(struct hostfrags *));
  if (!fragtable)
    nids_params.no_mem("ip_frag_init");
  hash_size = n;
}

简单到不能再简单——分片了一个主机的哈希表。分完手工。好吧,看重组逻辑:

//先是判断是否为分片的函数
int ip_defrag_stub(struct ip *iph, struct ip **defrag)
{
    int offset, flags, tot_len;
    struct sk_buff *skb;

    numpack++;
    //先处理超时事件
    timenow = 0;//刷新时间
    while (timer_head && timer_head->expires < jiffies())
    {
        this_host = ((struct ipq *) (timer_head->data))->hf;
        timer_head->function(timer_head->data);
    }

    //然后计算分片的偏移
    offset = ntohs(iph->ip_off);
    flags = offset & ~IP_OFFSET;
    offset &= IP_OFFSET;

    //此包不是分片
    if (((flags & IP_MF) == 0) && (offset == 0))
    {
        ip_defrag(iph, 0);
        return IPF_NOTF;
    }

    //此包是分片,先申请一个sk_buff把分片的数据保存起来,然后交给defrag函数
    tot_len = ntohs(iph->ip_len);
    skb = (struct sk_buff *) malloc(tot_len + sizeof(struct sk_buff));
    if (!skb)
        nids_params.no_mem("ip_defrag_stub");
    skb->data = (char *) (skb + 1);
    memcpy(skb->data, iph, tot_len);
    skb->truesize = tot_len + 16 + nids_params.dev_addon;
    skb->truesize = (skb->truesize + 15) & ~15;
    skb->truesize += nids_params.sk_buff_size;

    //如果集齐了一个ip包的所有分片ip_defrag将返回合并后的ip包,此时返回IPF_NEW,进行下一步的ip包处理
    //否则,返回IPF_ISF,跳过ip包处理
    if ((*defrag = (struct ip *)ip_defrag((struct ip *) (skb->data), skb)))
        return IPF_NEW;

    return IPF_ISF;
}


/* 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;

    //如果是分片,而且host哈希表里还没有对应的host项的话,果断新建一个
    //此处还负责将this_host变量设为当前ip对应的host
    if (!hostfrag_find(iph) && skb)
        hostfrag_create(iph);

    /* Start by cleaning up the memory. */
    //内存用太多了,panic之,然后释放当前host分片所用的内存
    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. */
    //这里,找到这个ip包对应的ip分片链表
    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.
    */
    //如果当前host下来过此包的碎片
    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. */
    //再大的ip包也不能大过65535啊,一经发现,直接放弃
    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...
    */
    //查看是不是碎片都搜集齐了,如果齐了,组合成一个大ip包返回
    if (ip_done(qp))
    {
        skb2 = ip_glue(qp);     /* glue together the fragments */
        return (skb2);
    }
    return (NULL);
}


DNS入侵检测 datacon2020 DNS入侵检测 datacon2020。 阅读详情

相关推荐

告别TI官网迷路!手把手教你用C2000Ware为TMS320F28027搭建Proteus仿真工程模板

本文详细指导如何使用C2000Ware为TMS320F28027搭建Proteus仿真工程模板,帮助DSP开发者快速上手。从资源获取、工程目录设计到关键文件配置,再到CCS与Proteus的联调技巧,全面解析仿真工程搭建的每个步骤,特别适合初学者和工程师参考。

weixin_42715608的博客 472

IP分片实现分析

数据包的分片与重组发生在IP层, 当IP数据包的长度超过PMTU,并且允许IP分片时,就会进行分片操作,分片后的数据包有独立的IP报头,并且独立路由,在接收端的IP层进行重组. 目前有两种分片处理方式,快速分片和慢速分片. 分片工作 层在处理分片时,把TCP/UPD的负载分割成MTU大小的片段,并且为每个片段设置IP报头,更新IP报头offset和检验和,如果是慢速分片,还需要进行数据的拷贝(...

bin_linux96的专栏 1468

VMware ESXI 7.0实战:4T硬盘RAID1配置与性能调优全记录

本文详细记录了在VMware ESXI 7.0环境下,为Dell服务器配置两块4T硬盘组建RAID1并进行深度性能调优的全过程。文章重点解析了RAID控制器写入策略(Write-Back with BBU)、读取策略(Read-Ahead)的关键选择,并深入探讨了在ESXI虚拟机层面通过选用PVSCSI控制器、调整虚拟磁盘缓存策略(scsiX:Y.caching)等技巧,以最大化满足数据分析等IO密集型工作负载的需求,最终实现性能的显著提升。

gaochao的博客 259

ip分片重组函数-ip_frag_queue

在讲解此函数前 有个概念需要再次说明一下,即分片重叠的问题  比如在没有接收到新来的分片时候 分片队列的分布如下: 当在接收到一个分片的时候,遍历链表(已经升序排序好)后找到插入位置后根据重叠与非重叠 有如下情况: (1)不发生重叠的正常情况: 比如新分片的offset=300 len=99 则插入情况如下: (2)发生前重叠 比如新分片的offset=280 len=119 则插...

yldfree的博客 4585

用Python写个彩票小助手:自动生成双色球/大乐透号码并保存到桌面

本文介绍如何使用Python开发一个智能彩票助手,实现双色球和大乐透号码的随机生成与桌面文件保存功能。通过详细的代码示例,包括随机号码生成、文件操作、用户交互和错误处理,帮助Python初学者快速掌握实用工具开发技巧。

weixin_42566121的博客 515

WPF 解决listview值更改时页面没有刷新

WPF 解决listview值更改时页面没有刷新。

weixin_52475977的博客 1385

tcp/ip源代码(17)——ip_fragment

作者:gfree.wind@gmail.com博客:linuxfocus.blog.chinaunix.net 今天学习上次剩下的最后一个UDP 发送数据调用中的最后一个函数,ip_fragment。这个函数用于当IP数据包过大时,对其进行分片发送。 /* *This IP datagram is too large to ...

weixin_34419321的博客 423

【ARM Coresight | AMBA BUS | Cache 与 MMU/MPU | CoreLink | GCC | CSH 专栏导读】

1. ARM Coresight(SoC-400/SoC-600) 专栏 2. ARMv8/v9 CPU/Cache 专栏 3. Linux ARM AMBA 总线 专栏 4. Trace32/DS-5 专栏。。。

CodingCos的博客 8241

libnids-TCP流重组

1.  Void process_tcp(u_char * data, int skblen)  2.  {  3.     4.    struct ip *this_iphdr = (struct ip *)data;  5.    /*tcphdr 的头*/  6.    struct tcphdr *this_tcphdr = (struct tcphdr *)(data +

lotus302的专栏 4648

PCL点云DBSCAN聚类算法:基于密度的点云聚类

核心点是在给定半径内拥有足够多邻居点的点,边界点是在给定半径内没有足够多邻居点但是位于核心点的邻域内的点,噪声点是既不是核心点也不是边界点的点。本文将介绍PCL中的DBSCAN(基于密度的空间聚类应用噪声)算法,用于点云数据的聚类。上述示例代码首先从PCD文件中读取点云数据,并设置了DBSCAN聚类的参数,包括邻域搜索半径(epsilon)和邻域内最小点数(min_points)。需要注意的是,示例代码中的点云数据格式为pcl::PointXYZ,如果使用其他类型的点云数据,需要相应地修改代码。

LpmShell的博客 1237

【Halcon 】Halcon 实战:如何为 XLD 模板添加极性信息以提升匹配精度?

本文介绍了Halcon中为XLD轮廓模板添加极性信息的实用技巧。通过先以"ignore_local_polarity"模式创建模板,首次匹配获得位置后,使用set_shape_model_metric运算符结合真实图像为模板注入极性信息(边缘明暗方向)。这种方法弥补了XLD模板初始不支持极性的缺陷,可显著提升后续匹配的精度和抗干扰能力。实验显示,添加极性信息后的模板匹配效果明显优于无极性的匹配结果。该技术特别适用于基于手动绘制或处理后的XLD轮廓创建模板的场景。

songhuangong123的博客 750

libnids在Windows下的安装

libnids中TCP/IP栈实现细节分析(下)——IP分片重组  http://blog.youkuaiyun.com/MSDA/article/details/8494575 libnids分析(8)  http://blog.youkuaiyun.com/xieqb/article/details/7678557 windows下安装时问题: 一、配置的准备工作       目前网上的能稳定支持

Sunshine的专栏 2995

9.16华为OD机试真题 新系统 - 统计特殊数字 (Java/Py/C/C++/Js/Go)

9.16华为OD机试真题 新系统 - 统计特殊数字 (Java/Py/C/C++/Js/Go)

算法大师! 753

libnids中TCP/IP栈实现细节分析——TCP会话重组

libnids中TCP/IP栈实现细节分析——TCP会话重组   libnids是网络安全方面的一个库,可以用来检测网络上的攻击行为。其中最有价值的部分是,它模拟了linux内核中3层和4层的协议栈。可以供我们进一步研究linux内核中的TCP/IP协议栈做一些有价值的参考。这里简单谈谈这个库中模拟3、4层协议的实现细节(在继续读下去之前,有必要复习一下TCP/IP协议相关理论,主要是滑动

xywlzd的专栏 3994

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

libnids中TCP/IP栈实现细节分析(上)——TCP会话重组

dccmx 于 2011年 三月 7日 发表 | 最后修改于 2011年 三月 22日 libnids是网络安全方面的一个库,可以用来检测网络上的攻击行为。其中最有价值的部分是,它模拟了linux内核中3层和4层的协议栈。可以供我们进一步研究linux内核中的TCP/IP协议栈做一些有价值的参考。这里简单谈谈这个库中模拟3、4层协议的实现细节(在继续读下去之前,有必要复习一下TCP/IP

HERO--To Be a Linuxer 835

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

libnids 分析笔记

一、当日工作(或学习)内容及进展情况(以条目式陈述,必要时配图说明) Libnids读书笔记: Libnids(Library Network Intusion Detection System)网络入侵检测开发包,基于libpcap和libnet开发,是仿照linux内核中的TCP/IP协议部分而实现的。   libnids主要功能包括捕获网络数据包、IP碎片重组、TCP数据流重组以及端

qinggebuyao的专栏 7107

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Libnids分析

一、当日工作(或学习)内容及进展情况(以条目式陈述,必要时配图说明) Libnids读书笔记: Libnids(Library Network Intusion Detection System)网络入侵检测开发包,基于libpcap和libnet开发,是仿照Linux内核中的TCP/IP协议部分而实现的。   libnids主要功能包括捕获网络数据包、IP碎片重组、TCP

suyouli的博客 1573

Libnids详解

一、当日工作(或学习)内容及进展情况(以条目式陈述,必要时配图说明) Libnids读书笔记: Libnids(Library Network Intusion Detection System)网络入侵检测开发包,基于libpcap和libnet开发,是仿照linux内核中的TCP/IP协议部分而实现的。   libnids主要功能包括捕获网络数据包、IP碎片重组、TCP数据流重组以及端

因热爱而执着,因执着而成功。 8075

Libnids读书笔记

一、当日工作(或学习)内容及进展情况(以条目式陈述,必要时配图说明) Libnids读书笔记: Libnids(Library Network Intusion Detection System)网络入侵检测开发包,基于libpcap和libnet开发,是仿照linux内核中的TCP/IP协议部分而实现的。 libnids主要功能包括捕获网络数据包、IP碎片重组、TCP数据流重组以及端口扫描攻击检测和异常数据包检测等。IP碎片重组是libnids的一个重要内容,是仿照linux内核中的IP重组而实现的,所以

hallå的博客 461

libnids

 一、当日工作(或学习)内容及进展情况(以条目式陈述,必要时配图说明) Libnids读书笔记: Libnids(Library Network Intusion Detection System)网络入侵检测开发包,基于libpcap和libnet开发,是仿照Linux内核中的TCP/IP协议部分而实现的。   libnids主要功能包括捕获网络数据包、IP碎片重组、TCP数据流重

程序猿成长之路 910
上一篇: libnids中TCP/IP栈实现细节分析(上)——TCP会话重组
下一篇: postgresql PREPARE 用法
jiangfeng999
博客等级 码龄23年 122粉丝 64原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值