前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >网络入侵检测系统之Suricata(十一)--TCP重组实现详解

网络入侵检测系统之Suricata(十一)--TCP重组实现详解

原创
作者头像
于顾而言SASE
发布2024-03-20 09:56:48
1450
发布2024-03-20 09:56:48
举报
文章被收录于专栏:入侵检测系统入侵检测系统

TCP重组一直是入侵检测系统中最为重要也是最难的一部分,它涉及到全流量的缓存,因此存储消耗十分巨大,据统计100万的会话就要产生1G~10G的内存缓存,因此设计一套TCP重组优化的算法十分必要,目前优化的办法有两种,一种是尽量不去TCP重组减少缓存包括红绿名单,配置,抽样算法,另一种就是将重组下沉到硬件例如FPGA,减少以软件方式缓存。我横向对比了三种目前流行的入侵检测系统,,看看TCP软件重组上这三种IDS/IPS系统有什么优化点:

QNSM首页、文档和下载 - 高性能网络安全监控引擎 - OSCHINA - 中文开源技术交流社区

Snort - Network Intrusion Detection & Prevention System

GitHub - OISF/suricata: Suricata git repository maintained by the OISF

QSNM实现

  • QSNM是否进行流重组,以条件编译确定__QNSM_STREAM_REASSEMBLE,默认配置中是不进行TCP流重组的
  • 同一个流的TCP都会进行流重组,上下行都在一个缓存队列中,最大支持8个报文,且不考虑重叠部分
  • 重组方法基于 hashmap + 双向链表
  • TCP流缓存删除方式:1. 老化 2. 无需进一步解析 3. 命中规则
代码语言:javascript
复制
/** tcp stream reassemble */
... ...
qnsm_list_for_each_prev_entry(tmp_tcp_data, &que->tcp_que, node) 
{
 same_dir = (dir == tmp_tcp_data->dir);
 sort1 = cur_tcp_data->seq;
 if (same_dir)
    {
  sort2 = tmp_tcp_data->seq;
    } 
 else 
    {
  sort2 = tmp_tcp_data->ack;
    }
 diff = packet_sequence_diff(sort2, sort1);
 /* 根据diff进行链表insert */
 ... ...
 QNSM_LIST_ADD_AFTER(&cur_tcp_data->node, &tmp_tcp_data->node);
 que->data_cnt++;
 cache->cur_pkt_num++;
}
... ...
  1. cur_seg->seq > tmp_seg->seq/ack
  1. cur_seg->seq = tmp_seg->seq/ack

Snort实现

  • Snort是否进行流重组,以配置决定,默认配置中是进行TCP流重组的

track tcp

Track sessions for TCP. The default is ”yes”

max tcp

Maximum simultaneous TCP sessions tracked. The default is 262144,maximum is 1048576,minimum is 2

memcap

Memcap for TCP packet storage. The default is 8388608 (8MB), maximum is 1073741824(1GB), minimum is 32768(32KB)

timeout

Session timeout. The default is 30, the minimum is 1, and the maximum is 86400 (approximately 1 day).

policy

The Operating System policy for the target OS

overlap limit

Limits the number of overlapping packets per session. The default is 0(unlimited)

max_queued_bytes

Limit the number of bytes queued for reassembly on a given TCP session to bytes. Default is 1048576(1MB).

max_queued_seg

Limit the number of segments queued for reassembly on a given TCP session. The default is 2621

ignore_ports

The default is 0(unlimited)

代码语言:javascript
复制
if ( SEQ_GT(rcv->r_win_base, tdb->seq) )
{
 //Received data segment whose seq no is less than already ACKed bytes
 if(SEQ_GT(rcv->r_nxt_ack, tdb->seq))
    {
 //We have already seen the data and this is a retransmission with  different packet size
 //Add the packet to seglist if the size is more than offset
 uint32_t offset = rcv->r_win_base - tdb->seq;
 if ( offset < p->dsize )
        {
 tdb->seq += offset;
 p->data += offset;
 p->dsize -= (uint16_t)offset;
 StreamQueue(rcv, p, tdb, tcpssn);
​
 //Restore the original seq and dsize before the packet is egressed
 p->dsize += (uint16_t)offset;
 p->data -= offset;
 tdb->seq -= offset;
        }
    }
 else
    {
 //We have NOT seen the data. Add it to stream queue
 StreamQueue(rcv, p, tdb, tcpssn);
    }
}
else
 StreamQueue(rcv, p, tdb, tcpssn);
  • Reassemble 重组方法基于 hashmap + 双向链表:
代码语言:javascript
复制
typedef struct _StreamTracker
{
 StreamTcpPolicy *tcp_policy;
 StreamSegment *seglist;       /* first queued segment */
 StreamSegment *seglist_tail;  /* last queued segment */
​
 /* Local in the context of these variables means the local part
 * of the connection.  For example, if this particular StreamTracker
 * was tracking the client side of a connection, the l_unackd value
 * would represent the client side of the connection's last unacked
 * sequence number
 */
 uint32_t l_unackd;     /* local unack'd seq number */
 uint32_t l_nxt_seq;    /* local next expected sequence */
 uint32_t l_window;     /* local receive window */
​
 uint32_t r_nxt_ack;    /* next expected ack from remote side */
 uint32_t r_win_base;   /* remote side window base sequence number
 * (i.e. the last ack we got) */
 uint32_t isn;          /* initial sequence number */
 uint32_t ts_last;      /* last timestamp (for PAWS) */
 uint32_t ts_last_pkt;  /* last packet timestamp we got */
​
 uint32_t seglist_base_seq;   /* seq of first queued segment */
 uint32_t seg_count;          /* number of current queued segments */
 uint32_t seg_bytes_total;    /* total bytes currently queued */
 uint32_t seg_bytes_logical;  /* logical bytes queued (total - overlaps) */
 uint32_t total_bytes_queued; /* total bytes queued (life of session) */
 uint32_t total_segs_queued;  /* number of segments queued (life) */
 uint32_t overlap_count;      /* overlaps encountered */
 uint32_t small_seg_count;
​
 uint16_t reassembly_policy;
​
} StreamTracker;
​
typedef struct _StreamSegment
{
 uint8_t *data;
 uint8_t *payload;
​
 struct _StreamSegment *prev;
 struct _StreamSegment *next;
​
 struct timeval tv;
 uint32_t caplen;
 uint32_t pktlen;
​
 uint32_t ts;
 uint32_t seq;
​
 uint16_t orig_dsize;
 uint16_t size;
 
} StreamSegment;
​
typedef struct _TcpSession
{
 StreamTracker client;
 StreamTracker server;
    ...
}

Windows/BSD倾向于原始报文,除了后续报文起始序列号在原始报文前这种情况。 Windows/BSD: <1><1><1><4><4><2><3><3><3><6><6><6><7><7><7><3.3><3.3><3.3><3.4><3.4><3.5><3.5><3.6><11> Linux倾向于原始报文,除了后续报文起始序列号在原始报文之前,或后续报文起始序列号相同但终止序列号在原始报文后的情况 Linux: <1><1><1><4><4><2><3><3><3><6><6><6><7><7><7><3.3><3.3><3.3><3.4><3.4><3.5><3.5><11><11>

Suricata实现

Reference

  1. snort_manual.pdf
  2. snort-2.9.16.1 code
  3. qnsm-master code
  4. 解析Snort的TCP流重组
  5. suricata5.0 code
  6. suricata 6.0.3 tcp reassemble

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • QSNM实现
  • Snort实现
  • Suricata实现
  • Reference
相关产品与服务
网络入侵防护系统
网络入侵防护系统(Network Intrusion Prevention System,NIPS),是基于腾讯安全服务内部数百条业务线的运维经验积累和大数据处理能力的结合,通过旁路部署的方式,提供了网络层 ACL (访问控制)和日志审计功能,解决云平台监管、ACL 控制、安全治理等问题,并辅助客户满足网安法,合规性要求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档