snort会话控制块scb

55 篇文章 3 订阅
22 篇文章 1 订阅

一 会话控制块session control block含义

    scb是snort用来保存一次完整会话信息,包括会话Key,会话首次时间,会话最终时间,会话过期时间,ttl信息,snort策略ID,服务器端IP,客户端IP,服务端通信端口,客户端通信端口,协议,MAC地址,客户端请求字节数,服务端响应字节数,会话ID,客户端请求包数,服务端响应包数等,其定义在snort源码preprocessors/Session/session_common.h:

typedef struct _SessionControlBlock
{
    SessionKey *key;            // snort将session存储到hash表,key就是其相应的键值
    StreamAppData *appDataList; // 将应用协议(egd, modbus, s7等)和应用协议解析数据及释放解析数据函数组织成双向链表
    ...
    sfaddr_t client_ip;         // 客户端IP
    sfaddr_t server_ip;         // 服务端IP
    ...
    uint64_t initiaorBytes;     // 客户端请求字节数
    uint64_t responderBytes;    // 服务端请求字节数
    ...
    long session_lastest_time;      // 会话最近时间
    uint64_t requestpacketCount;    // 客户端请求包数
    uint64_t responsepacketCount;   // 服务端请求包数
}SessionControlBlock;

1.SessionKey:snort将所有会话存入hash表,key就是hash表的key,SessionKey定义在session_api.h中:

typedef struct _StreamSessionKey
{
    uint32_t ip_l[4];
    uint32_t ip_h[4];
    uint16_t port_l;
    uint16_t port_h;
    ...
}StreamSessionKey;

snort在会话处理时,会根据key进行判断,如果两个session的key相同,则snort认为是同一个会话,即:两个会话ip,端口等信息一致,比如会话A:192.168.1.10:9000=>192.168.1.12:9000,会话B:192.168.1.12:9000=>192.168.1.10:9000,则A,B是同一个会话。

2.initiaorBytes和responderBytes是当前会话的请求和响应字节数,如果业务层会定期取会话的请求和响应字节数,那么对于同一个会话,这两个值是累加值,当会话关闭,这两个值会被snort清零。

3.每个snort包都包含一个session指针

snort包结构是SFSnortPacket,定义在dynamic-plugins/sf_engine/sf_snort,packet.h:

typedef struct _SFSnortPacket
{
    const SFDAQ_PktHdr_t *pkt_header;       // 包头信息
    const uint8_t *pkt_data;                // 指向包数据
    ...
    void *stream_session;                   // 指向scb
}SFSnortPacket;

这样snort在处理包是可以和会话相关联。

二 会话处理函数集SessionAPI

1.SessionAPI是一个结构体,它包含了会话处理的所有函数指针,其定义在snort源码precessorors/session_api.h:

typedef struct _session_api
{
    int version;
    ...
    void *(*get_session)(void *, Packet *, SessionKey *);                                       // 根据snort包和会话key查询会话
    ...
    void (*get_session_bytes)(void *, uint64_t *initiaorBytes, uint64_t *responderBytes);       // 从scb拿出请求和响应字节数
    ...
}SessionAPI;

2.SessionAPI被嵌入到全局对象_dpd中,方便在插件使用:

typedef struct _DynamicPreprocessorData
{
    ...
    SessionAPI *sessionAPI
    ...
}DynamicPreprocessorData;

3.在插件中使用SessionAPI

static inline void Egd_Save_action(SFSnortPacket *p, EgdSessionData *egdSessionData)
{
    ...
    if (p && p->stream_session)          // 使用包里stream_session
    {
        _dpd.sessionAPI->get_session_id(p->stream_session, &savemdb.sessionID);       // 从scb拿出sessionID
    }拿出请求和响应字节数
    ...
}
EgdSessionData *GetEgdSessionData(SFSnortPacket *p, EdgConfig *config)
{
    ...
    _dpd.sessionAPI->set_application_data(p->stream_session, PP_EGD, edgSessionData, FreeEgdSessionData);
}

set_application_data是spp_session.c的setApplicationData函数指针,将edgSessionData和FreeEgdSessionData插入scb的appDataList中并释放老的相同协议数据:

static int setApplicationData(void *scbptr,uint32_t protocol, void *data, StreamAppDataFree free_func)
{
    ...
    if (scbptr)         //scbptr指向scb
    {
        scb = (SessionControlBlock *)scpptr;
        appData = scb->appDataList;      // 找到协议双向链表
        while (appData)     // 遍历链表
        {
            if (appData->protocol == protocol)       // 找到目标协议
            {
                if ((appData->freeFunc) && (appData->datapointer != data)) // 目标结点里数据指针和传入指针不同 则利用free_func将结点里协议数据释放
                {
                    ...
                }
            }
            ...
        }
        if (!appData)       // 在链表中查不到该协议 则构造新结点插入链表头
        {
            ...
        }
    }
}

三 初始化会话预处理initializeSessionPreproc

该函数定义在preprocessor/Stream6/spp_session.c:

void initializeSessionPreproc(struct _SnortConfig *sc, char *args)
{
    if (session_configuration == NULL)  // 会话配置只能初始化一次
    {
        session_configuration = initSessionConfiguration(); // 分配session_configuration存储空间并初始化相关参数
        ...
        AddFuncToPreprocList(sc, sessionPacketProcessor, PP_SESSION_PRIORITY, PP_SESSION, PROTO_BIT_ALL);   // 将sessionPacketProcessor装入snort策略的预处理链表中
    }
    else
    {
        WarningMessage("...);
    }
}

四 会话预处理sessionPacketProcessor

该函数定义在preprocessor/Stream6/spp_session.c:

static void sessionPacketProcessor(Packet *p, void *context)
{
    // 判断p是否合法
    // 如果p的scb为空,则根据p的协议从相应SessionCache里的hash表查询scb,这里的hash表就是sfxhash,SessionCache是一个4元素数组,每个元素对应一种协议(tcp,udp,icmp,ip)会话缓存
    ...
    if (t_now - scb->session_lastest_time > scb->session_config->long_connect_time_interval)    // 达到会话保存时间 60s
    {
        scb->session_lastest_time = t_now;
        SaveSessionFlowStaticsInfo(scb, 0);     // 调用snort里保存网络会话信息接口,将相关信息保存到共享内存,以供审计进程做业务处理
    }
    ...
}

1.会话缓存proto_session_caches

会话缓存是SessionCache结构的数组,维度是4,分别对应tcp,udp,icmp,ip四种协议:

typedef struct _SessionCache
{
    SFXHASH *hashTable;     // scb存储到sfxhash表
    SFXHASH_NODE *nextTimeoutEvalNode;
    ...
}SessionCache;

2.会话保存时间

会话保存时间是long_connect_time_interval,由snort配置解析函数parseSessionConfiguration从snort,conf解析而得,如下:

3.会话预处理逻辑:

(1)如果packet里的ssnptr为空,则从会话缓存查询scb,并且按照snort配置保存网络会话信息;

(2)否则,获取scb,即scb = p→ssnptr;

(3)调用initializePacketPolicy等函数进行相关处理。

五 会话删除deleteSession

该函数定义在preprocessor/Stream6/spp_session.c:

static int deleteSession(void *sessionCache, void *session, char *delete_reason)
{
    ...
    freeSessionApplicationData(scb);        // 是否scb的appDataList 即协议链表
    SaveSessionFlowStatisticsInfo(scb,1);   // 网络会话断开业务处理
    clearSessionApplicationData(scb);       // 清除scb的请求字节等数据
}

需要注意是:当会话断开时,scb保存到共享内存后,请求字节数不为0,但其状态已经是close,其值表示相应会话的累加最值。

函数deleteSessionIfClosed会调用deleteSession:

static int deleteSessionIfClosed(Packet *p)
{
    ...
    if (scb->is_session_state & STREAM_STATE_CLOSED)     // 会话关闭状态
    {
        if (scb->is_session_deletion_delayed)    // 延迟删除
        ...
        switch (scb->protocol)
        {
            case IPPROTO_TCP:       // 根据不同协议 删除scb
                deleteSession(proto_session_caches[SESSION_PROTO_TCP], scb, "closed normally");    
            ...
        }
    }
    ...
}

函数Preprocess调用check_session_closed(deleteSessionIfClosed的函数指针),其代码位于detect.c:

int Preprocess(Packet *p)
{
    ...
    if (do_detect)
        Detect(p);      // snort检测
    ...
    if (session_api)
        session_api->check_session_closed(p);    // 检测之后就删除会话
}

除了Preprocessor之外,还有pruneOneWaySession=》deleteSession,pruneSessionCache=》deleteSession。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值