A-A+

suricata 3.1 源码分析28 (数据包TCP解码)

2018年12月06日 suricata 暂无评论

int DecodeTCP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq)
{
    StatsIncr(tv, dtv->counter_tcp);

    if (unlikely(DecodeTCPPacket(tv, p,pkt,len) < 0)) {
//调用DecodeTCPPacket完成实际的解码
        SCLogDebug("invalid TCP packet");
        p->tcph = NULL;
        return TM_ECODE_FAILED;
    }

#ifdef DEBUG
    SCLogDebug("TCP sp: %" PRIu32 " -> dp: %" PRIu32 " - HLEN: %" PRIu32 " LEN: %" PRIu32 " %s%s%s%s%s",
        GET_TCP_SRC_PORT(p), GET_TCP_DST_PORT(p), TCP_GET_HLEN(p), len,
        TCP_HAS_SACKOK(p) ? "SACKOK " : "", TCP_HAS_SACK(p) ? "SACK " : "",
        TCP_HAS_WSCALE(p) ? "WS " : "", TCP_HAS_TS(p) ? "TS " : "",
        TCP_HAS_MSS(p) ? "MSS " : "");
#endif

    FlowSetupPacket(p);
/*设置包的flag为PKT_WANTS_FLOW,并调用FlowGetHash获得包的flow_hash*/

    return TM_ECODE_OK;
}
static int DecodeTCPPacket(ThreadVars *tv, Packet *p, uint8_t *pkt, uint16_t len)
{
    if (unlikely(len < TCP_HEADER_LEN)) {
        ENGINE_SET_INVALID_EVENT(p, TCP_PKT_TOO_SMALL);
        return -1;
//若len小于TCP_HEADER_LEN(20),添加TCP_PKT_TOO_SMALL事件并返回
    }

    p->tcph = (TCPHdr *)pkt;
//设置tcph指针(TCPHdr *类型)

    uint8_t hlen = TCP_GET_HLEN(p);
    if (unlikely(len < hlen)) {
        ENGINE_SET_INVALID_EVENT(p, TCP_HLEN_TOO_SMALL);
        return -1;
//获取TCP头部长度hlen,若len小于hlen,则添加TCP_HLEN_TOO_SMALL事件并返回
    }

    uint8_t tcp_opt_len = hlen - TCP_HEADER_LEN;
    if (unlikely(tcp_opt_len > TCP_OPTLENMAX)) {
        ENGINE_SET_INVALID_EVENT(p, TCP_INVALID_OPTLEN);
        return -1;
/*计算TCP选项长度(hlen – 20)tcp_opt_len,若大于TCP_OPTLENMAX(40),
则添加TCP_INVALID_OPTLEN事件并返回。*/
    }

    if (likely(tcp_opt_len > 0)) {
        DecodeTCPOptions(p, pkt + TCP_HEADER_LEN, tcp_opt_len);
//若tcp_opt_len大于0,则调用DecodeTCPOptions对选项进行解码。
    }

    SET_TCP_SRC_PORT(p,&p->sp);
    SET_TCP_DST_PORT(p,&p->dp);

    p->proto = IPPROTO_TCP;

    p->payload = pkt + hlen;
    p->payload_len = len - hlen;
//设置Packet的sp、dp、proto、payload、payload_len。

    return 0;
}

Suricata中用于表示TCP选项的数据结构为TCPVars:

字段 含义
tcp_opts[TCP_OPTMAX] TCP选项数组,类型为TCPOpt,TCP_OPTMAX定义为20。
tcp_opt_cnt TCP选项个数
ts、sack、sackok、ws、mss 特定选项指针

选项由TCPOpt结构体表示:(可参考TCP头部选项 )
typedef struct TCPOpt_ {
uint8_t type; /* 选项类型 */0
uint8_t len; /* 选项长度 */
uint8_t data; / 内容指针 */
} TCPOpt;

其中type有以下几种(参考TCP头部选项功能详解):

类型 含义
TCP_OPT_EOL 选项表结束。
TCP_OPT_NOP 空操作,一般用于将TCP选项的总长度填充为4字节的整数倍。
TCP_OPT_MSS 最大报文段长度选项,一般设置为MTU-40,关于MTU可参考:以太网最大帧和最小帧、MTU。
TCP_OPT_WS 窗口扩大选项,用于增加TCP窗口值(16位,最大64KB),提高吞吐量。
TCP_OPT_SACKOK 选择性确认(Selective Acknowledgements )选项,用在连接初始化时,表示是否支持SACK技术。
TCP_OPT_SACKSACK 实际工作的选项,可让发送端只重新发送丢失的TCP报文段。
TCP_OPT_TS 时间戳选项,用于计算RTT,从而为TCP流量控制提供重要信息。

DecodeTCPOptions流程为:
1. 与处理IPv4选项类似,循环处理每一个选项。
2. 先看是否为单字节选项:对于EOL,直接退出;对于NOP,前进。
3. 再看是否为多字节选项:填充tcp_opts[tcp_opt_cnt],并设置特定选项指针。

标签:

给我留言

Copyright © 九毛的官方博客 保留所有权利.   Theme  Ality

用户登录