【网络入侵检测】基于Suricata源码分析应用协议识别实现

【作者主页】只道当时是寻常

【专栏介绍】Suricata入侵检测。专注网络、主机安全,欢迎关注与评论。

1. 概要

👋 本文聚焦Suricata网络安全引擎的协议解析器实现,详细剖析HTTP、SSL/TLS、FTP、SSH、SMTP等协议的解析流程。

2. 源码分析

2.1 HTTP协议解析器

RegisterHTPParsers 函数实现注册 HTTP 协议解析器。下面是该函数代码实现:

/***  \brief  Register the HTTP protocol and state handling functions to APP layer*          of the engine.*/
void RegisterHTPParsers(void)
{SCEnter();const char *proto_name = "http";/** HTTP */if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {AppLayerProtoDetectRegisterProtocol(ALPROTO_HTTP1, proto_name);if (HTPRegisterPatternsForProtocolDetection() < 0)return;} else {SCLogInfo("Protocol detection and parser disabled for %s protocol",proto_name);return;}if (AppLayerParserConfParserEnabled("tcp", proto_name)) {AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateAlloc, HTPStateFree);AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateTransactionFree);AppLayerParserRegisterGetTxFilesFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetTxFiles);AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetAlstateProgress);AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetTxCnt);AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetTx);AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_HTTP1, HTP_REQUEST_COMPLETE, HTP_RESPONSE_COMPLETE);AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetEventInfo);AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetEventInfoById);AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetTxData);AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetStateData);AppLayerParserRegisterSetStreamDepthFlag(IPPROTO_TCP, ALPROTO_HTTP1, AppLayerHtpSetStreamDepthFlag);AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_HTTP1, STREAM_TOSERVER, HTPHandleRequestData);AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_HTTP1, STREAM_TOCLIENT, HTPHandleResponseData);SC_ATOMIC_INIT(htp_config_flags);/* This parser accepts gaps. */AppLayerParserRegisterOptionFlags(IPPROTO_TCP, ALPROTO_HTTP1, APP_LAYER_PARSER_OPT_ACCEPT_GAPS);AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_TOCLIENT);/* app-layer-frame-documentation tag start: registering relevant callbacks */AppLayerParserRegisterGetFrameFuncs(IPPROTO_TCP, ALPROTO_HTTP1, HTTPGetFrameIdByName, HTTPGetFrameNameById);/* app-layer-frame-documentation tag end: registering relevant callbacks */HTPConfigure();} else {SCLogInfo("Parsed disabled for %s protocol. Protocol detection""still on.", proto_name);}
#ifdef UNITTESTSAppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_HTTP1, HTPParserRegisterTests);
#endifSCReturn;
}

2.1.1 配置开启

AppLayerProtoDetectConfProtoDetectionEnabled 函数是一个通用的配置开启检查函数,通过第二个参数传入"http"字符串用于检测配置文件中 app-layer.protocols.http.enabled 选项是否开启,若开启则继续注册操作,如果未开启则终止 HTTP 协议解析器的注册操作。

2.1.2 协议识别

Suricata 中,HTTP 协议识别通过在应用数据中匹配特定模式串实现,协议识别器针对报文流方向(STREAM_TOSERVER STREAM_TOCLIENT)定义了不同的模式串,在 HTPRegisterPatternsForProtocolDetection 函数中实现了模式串的注册。

(1)客户端 -> 服务端

在下面这些字符串后面添加空格(|20|)或者制表符(|09|)作为模式串。

"GET", "PUT", "POST", "HEAD", "TRACE", "OPTIONS","CONNECT", "DELETE", "PATCH", "PROPFIND", "PROPPATCH", "MKCOL", "COPY", "MOVE", "LOCK", "UNLOCK", "CHECKOUT", "UNCHECKOUT", "CHECKIN", "UPDATE", "LABEL", "REPORT", "MKWORKSPACE", "MKACTIVITY", "MERGE", "INVALID", "VERSION-CONTROL", "BASELINE-CONTROL".

(2)服务端 -> 客户端

下面字符串作为模式串。

"HTTP/0.9", "HTTP/1.0", "HTTP/1.1".

2.2 SSL协议解析器

RegisterSSLParsers 函数实现注册 SSL 协议解析器。下面是该函数代码实现:

/*** \brief Function to register the SSL protocol parser and other functions*/
void RegisterSSLParsers(void)
{const char *proto_name = "tls";SC_ATOMIC_INIT(ssl_config.enable_ja3);/** SSLv2  and SSLv23*/if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {AppLayerProtoDetectRegisterProtocol(ALPROTO_TLS, proto_name);if (SSLRegisterPatternsForProtocolDetection() < 0)return;if (RunmodeIsUnittests()) {AppLayerProtoDetectPPRegister(IPPROTO_TCP,"443",ALPROTO_TLS,0, 3,STREAM_TOSERVER,SSLProbingParser, NULL);} else {if (AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP,proto_name, ALPROTO_TLS,0, 3,SSLProbingParser, NULL) == 0) {SCLogConfig("no TLS config found, ""enabling TLS detection on port 443.");AppLayerProtoDetectPPRegister(IPPROTO_TCP,"443",ALPROTO_TLS,0, 3,STREAM_TOSERVER,SSLProbingParser, NULL);}}} else {SCLogConfig("Protocol detection and parser disabled for %s protocol",proto_name);return;}if (AppLayerParserConfParserEnabled("tcp", proto_name)) {AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TLS, STREAM_TOSERVER,SSLParseClientRecord);AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TLS, STREAM_TOCLIENT,SSLParseServerRecord);AppLayerParserRegisterGetFrameFuncs(IPPROTO_TCP, ALPROTO_TLS, SSLStateGetFrameIdByName, SSLStateGetFrameNameById);AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_TLS, SSLStateGetEventInfo);AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_TLS, SSLStateGetEventInfoById);AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_TLS, SSLStateAlloc, SSLStateFree);AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_TLS, STREAM_TOSERVER);AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_TLS, SSLStateTransactionFree);AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_TLS, SSLGetTx);AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_TLS, SSLGetTxData);AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_TLS, SSLGetStateData);AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_TLS, SSLGetTxCnt);AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_TLS, SSLGetAlstateProgress);AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_TLS, TLS_STATE_FINISHED, TLS_STATE_FINISHED);ConfNode *enc_handle = ConfGetNode("app-layer.protocols.tls.encryption-handling");if (enc_handle != NULL && enc_handle->val != NULL) {SCLogDebug("have app-layer.protocols.tls.encryption-handling = %s", enc_handle->val);if (strcmp(enc_handle->val, "full") == 0) {ssl_config.encrypt_mode = SSL_CNF_ENC_HANDLE_FULL;} else if (strcmp(enc_handle->val, "bypass") == 0) {ssl_config.encrypt_mode = SSL_CNF_ENC_HANDLE_BYPASS;} else if (strcmp(enc_handle->val, "default") == 0) {ssl_config.encrypt_mode = SSL_CNF_ENC_HANDLE_DEFAULT;} else {ssl_config.encrypt_mode = SSL_CNF_ENC_HANDLE_DEFAULT;}} else {/* Get the value of no reassembly option from the config file */if (ConfGetNode("app-layer.protocols.tls.no-reassemble") == NULL) {int value = 0;if (ConfGetBool("tls.no-reassemble", &value) == 1 && value == 1)ssl_config.encrypt_mode = SSL_CNF_ENC_HANDLE_BYPASS;} else {int value = 0;if (ConfGetBool("app-layer.protocols.tls.no-reassemble", &value) == 1 && value == 1)ssl_config.encrypt_mode = SSL_CNF_ENC_HANDLE_BYPASS;}}SCLogDebug("ssl_config.encrypt_mode %u", ssl_config.encrypt_mode);#ifdef HAVE_JA3CheckJA3Enabled();
#endif /* HAVE_JA3 */
#ifdef HAVE_JA4CheckJA4Enabled();
#endif /* HAVE_JA4 */if (g_disable_hashing) {if (SC_ATOMIC_GET(ssl_config.enable_ja3)) {SCLogWarning("MD5 calculation has been disabled, disabling JA3");SC_ATOMIC_SET(ssl_config.enable_ja3, 0);}if (SC_ATOMIC_GET(ssl_config.enable_ja4)) {SCLogWarning("Hashing has been disabled, disabling JA4");SC_ATOMIC_SET(ssl_config.enable_ja4, 0);}} else {if (RunmodeIsUnittests()) {
#ifdef HAVE_JA3SC_ATOMIC_SET(ssl_config.enable_ja3, 1);
#endif /* HAVE_JA3 */
#ifdef HAVE_JA4SC_ATOMIC_SET(ssl_config.enable_ja4, 1);
#endif /* HAVE_JA4 */}}} else {SCLogConfig("Parsed disabled for %s protocol. Protocol detection""still on.", proto_name);}return;
}

2.2.1 配置开启

AppLayerProtoDetectConfProtoDetectionEnabled 函数是一个通用的配置开启检查函数,通过第二个参数传入"tls"字符串用于检测配置文件中 app-layer.protocols.tls.enabled 选项是否开启,若开启则继续注册操作,如果未开启则终止 SSL 协议解析器的注册操作。

2.2.2 协议识别

Suricata 中,SSL 协议识别通过在应用数据中匹配特定模式串实现,协议识别器针对报文流方向(STREAM_TOSERVER STREAM_TOCLIENT)定义了不同的模式串,在 SSLRegisterPatternsForProtocolDetection 函数中实现了模式串的注册。

Suricata 根据报文方向以及应用报文中携带的特定模式串判断报文所在流的协议类型。下面是匹配规则(其中偏移为从应用数据 0 字节开始偏移,深度为从偏移开始指定字节内包含特定模式串):

  1. 客户端->服务端,偏移为 2,深度为 5,命中"|01 00 02|"字节序列。

  2. 客户端->服务端,偏移为 0,深度为 3,命中"|01 03 00|"字节序列。

  3. 客户端->服务端,偏移为 0,深度为 3,命中"|16 03 00|"字节序列。

  4. 客户端->服务端,偏移为 0,深度为 3,命中"|01 03 01|"字节序列。

  5. 客户端->服务端,偏移为 0,深度为 3,命中"|16 03 01|"字节序列。

  6. 客户端->服务端,偏移为 0,深度为 3,命中"|01 03 02|"字节序列。

  7. 客户端->服务端,偏移为 0,深度为 3,命中"|16 03 02|"字节序列。

  8. 客户端->服务端,偏移为 0,深度为 3,命中"|01 03 03|"字节序列。

  9. 客户端->服务端,偏移为 0,深度为 3,命中"|16 03 03|"字节序列。

  10. 服务端->客户端,偏移为 0,深度为 3,命中"|15 03 00|"字节序列。

  11. 服务端->客户端,偏移为 0,深度为 3,命中"|16 03 00|"字节序列。

  12. 服务端->客户端,偏移为 0,深度为 3,命中"|17 03 00|"字节序列。

  13. 服务端->客户端,偏移为 0,深度为 3,命中"|15 03 01|"字节序列。

  14. 服务端->客户端,偏移为 0,深度为 3,命中"|16 03 01|"字节序列。

  15. 服务端->客户端,偏移为 0,深度为 3,命中"|17 03 01|"字节序列。

  16. 服务端->客户端,偏移为 0,深度为 3,命中"|15 03 02|"字节序列。

  17. 服务端->客户端,偏移为 0,深度为 3,命中"|16 03 02|"字节序列。

  18. 服务端->客户端,偏移为 0,深度为 3,命中"|17 03 02|"字节序列。

  19. 服务端->客户端,偏移为 0,深度为 3,命中"|15 03 03|"字节序列。

  20. 服务端->客户端,偏移为 0,深度为 3,命中"|16 03 03|"字节序列。

  21. 服务端->客户端,偏移为 0,深度为 3,命中"|17 03 03|"字节序列。

2.3 FTP协议解析器

RegisterFTPParsers 函数实现注册 FTP 协议解析器。下面是该函数代码实现:

void RegisterFTPParsers(void)
{const char *proto_name = "ftp";const char *proto_data_name = "ftp-data";/** FTP */if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {AppLayerProtoDetectRegisterProtocol(ALPROTO_FTP, proto_name);if (FTPRegisterPatternsForProtocolDetection() < 0 )return;AppLayerProtoDetectRegisterProtocol(ALPROTO_FTPDATA, proto_data_name);}if (AppLayerParserConfParserEnabled("tcp", proto_name)) {AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_FTP, STREAM_TOSERVER,FTPParseRequest);AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_FTP, STREAM_TOCLIENT,FTPParseResponse);AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_FTP, FTPStateAlloc, FTPStateFree);AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_FTP, STREAM_TOSERVER | STREAM_TOCLIENT);AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_FTP, FTPStateTransactionFree);AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_FTP, FTPGetTx);AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_FTP, FTPGetTxData);AppLayerParserRegisterGetTxIterator(IPPROTO_TCP, ALPROTO_FTP, FTPGetTxIterator);AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_FTP, FTPGetStateData);AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_FTP, FTPLocalStorageAlloc,FTPLocalStorageFree);AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_FTP, FTPGetTxCnt);AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_FTP, FTPGetAlstateProgress);AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_FTP, FTP_STATE_FINISHED, FTP_STATE_FINISHED);AppLayerRegisterExpectationProto(IPPROTO_TCP, ALPROTO_FTPDATA);AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_FTPDATA, STREAM_TOSERVER,FTPDataParseRequest);AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_FTPDATA, STREAM_TOCLIENT,FTPDataParseResponse);AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateAlloc, FTPDataStateFree);AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_FTPDATA, STREAM_TOSERVER | STREAM_TOCLIENT);AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateTransactionFree);AppLayerParserRegisterGetTxFilesFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateGetTxFiles);AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetTx);AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetTxData);AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetStateData);AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetTxCnt);AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetAlstateProgress);AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_FTPDATA, FTPDATA_STATE_FINISHED, FTPDATA_STATE_FINISHED);AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_FTP, ftp_get_event_info);AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_FTP, ftp_get_event_info_by_id);sbcfg.buf_size = 4096;sbcfg.Calloc = FTPCalloc;sbcfg.Realloc = FTPRealloc;sbcfg.Free = FTPFree;FTPParseMemcap();} else {SCLogInfo("Parsed disabled for %s protocol. Protocol detection""still on.", proto_name);}FTPSetMpmState();#ifdef UNITTESTSAppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_FTP, FTPParserRegisterTests);
#endif
}

2.3.1 配置开启

AppLayerProtoDetectConfProtoDetectionEnabled 函数是一个通用的配置开启检查函数,通过第二个参数传入"ftp"字符串用于检测配置文件中 app-layer.protocols.ftp.enabled 选项是否开启,若开启则继续注册操作,如果未开启则终止 FTP 协议解析器的注册操作。

2.3.2 协议识别

Suricata 中,FTP 协议识别通过在应用数据中匹配特定模式串实现,协议识别器针对报文流方向(STREAM_TOSERVER STREAM_TOCLIENT)定义了不同的模式串,在 FTPRegisterPatternsForProtocolDetection 函数中实现了模式串的注册。

Suricata 根据报文方向以及应用报文中携带的特定模式串判断报文所在流的协议类型。下面是匹配规则(其中偏移为从应用数据 0 字节开始偏移,深度为从偏移开始指定字节内包含特定模式串):

  1. 服务端->客户端,偏移为 0,深度为 5,命中"220 ("字符串。

  2. 客户端->服务端,偏移为 0,深度为 4,命中"FEAT"字符串。

  3. 客户端->服务端,偏移为 0,深度为 5,命中"USER "字符串。

  4. 客户端->服务端,偏移为 0,深度为 5,命中"PASS "字符串。

  5. 客户端->服务端,偏移为 0,深度为 5,命中"PORT "字符串。

2.4 SSH协议解析器

RegisterSSHParsers 函数实现注册 SSH 协议解析器。下面是该函数代码实现:

void RegisterSSHParsers(void)
{const char *proto_name = "ssh";if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {AppLayerProtoDetectRegisterProtocol(ALPROTO_SSH, proto_name);if (SSHRegisterPatternsForProtocolDetection() < 0)return;/* Check if we should generate Hassh fingerprints */int enable_hassh = SSH_CONFIG_DEFAULT_HASSH;const char *strval = NULL;if (ConfGet("app-layer.protocols.ssh.hassh", &strval) != 1) {enable_hassh = SSH_CONFIG_DEFAULT_HASSH;} else if (strcmp(strval, "auto") == 0) {enable_hassh = SSH_CONFIG_DEFAULT_HASSH;} else if (ConfValIsFalse(strval)) {enable_hassh = SSH_CONFIG_DEFAULT_HASSH;} else if (ConfValIsTrue(strval)) {enable_hassh = true;}if (RunmodeIsUnittests() || enable_hassh) {rs_ssh_enable_hassh();}}SCLogDebug("Registering Rust SSH parser.");rs_ssh_register_parser();#ifdef UNITTESTSAppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_SSH, SSHParserRegisterTests);
#endif
}

2.4.1 配置开启

AppLayerProtoDetectConfProtoDetectionEnabled 函数是一个通用的配置开启检查函数,通过第二个参数传入"ssh"字符串用于检测配置文件中 app-layer.protocols.ssh.enabled 选项是否开启,若开启则继续注册操作,如果未开启则终止 SSH 协议解析器的注册操作。

2.4.2 协议识别

Suricata 在 SSHRegisterPatternsForProtocolDetection 函数中实现模式串的注册。

Suricata 根据报文方向以及应用报文中携带的特定模式串判断报文所在流的协议类型。下面是匹配规则(其中偏移为从应用数据 0 字节开始偏移,深度为从偏移开始指定字节内包含特定模式串):

  1. 服务端->客户端,偏移为 0,深度为 4,命中"SSH-"字符串。

  2. 客户端->服务端,偏移为 0,深度为 4,命中"SSH-"字符串。

2.5 SMTP协议解析器

RegisterSMTPParsers 函数实现注册 SMTP 协议解析器。下面是该函数代码实现:

void RegisterSMTPParsers(void)
{const char *proto_name = "smtp";if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {AppLayerProtoDetectRegisterProtocol(ALPROTO_SMTP, proto_name);if (SMTPRegisterPatternsForProtocolDetection() < 0 )return;} else {SCLogInfo("Protocol detection and parser disabled for %s protocol.",proto_name);return;}if (AppLayerParserConfParserEnabled("tcp", proto_name)) {AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateAlloc, SMTPStateFree);AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOSERVER,SMTPParseClientRecord);AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOCLIENT,SMTPParseServerRecord);AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfo);AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfoById);AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc,SMTPLocalStorageFree);AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTransactionFree);AppLayerParserRegisterGetTxFilesFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxFiles);AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetAlstateProgress);AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxCnt);AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTx);AppLayerParserRegisterGetTxIterator(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxIterator);AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxData);AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetStateData);AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_SMTP, 1, 1);} else {SCLogInfo("Parsed disabled for %s protocol. Protocol detection""still on.", proto_name);}SMTPSetMpmState();SMTPConfigure();#ifdef UNITTESTSAppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_SMTP, SMTPParserRegisterTests);
#endifreturn;
}

2.5.1 配置开启

AppLayerProtoDetectConfProtoDetectionEnabled 函数是一个通用的配置开启检查函数,通过第二个参数传入"smtp"字符串用于检测配置文件中 app-layer.protocols.smtp.enabled 选项是否开启,若开启则继续注册操作,如果未开启则终止 smtp 协议解析器的注册操作。

2.5.2 协议识别

Suricata 在 SMTPRegisterPatternsForProtocolDetection 函数中实现模式串的注册。

Suricata 根据报文方向以及应用报文中携带的特定模式串判断报文所在流的协议类型。下面是匹配规则(其中偏移为从应用数据 0 字节开始偏移,深度为从偏移开始指定字节内包含特定模式串):

  1. 客户端->服务端,偏移为 0,深度为 4,命中"EHLO"字符串。

  2. 客户端->服务端,偏移为 0,深度为 4,命中"QUIT"字符串。

2.6 总结

上述协议类型仅为 Suricata 支持的部分协议。除模式串匹配外,其还支持其他识别方式:如 MQTT 协议解析器会监控 1883 端口流量,通过探测函数解析应用数据,若格式符合 MQTT 协议规范则判定为 MQTT 流。此外,部分协议识别器采用 Rust 语言编写并嵌入 C 语言工程。如需了解更多协议解析器实现,可关注`AppLayerParserRegisterProtocolParsers`函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/86240.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/86240.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Nginx SSL/TLS协议栈中配置深度解析与实践指南-优雅草卓伊凡

Nginx SSL/TLS协议栈中配置深度解析与实践指南-优雅草卓伊凡 引言&#xff1a;SSL/TLS的重要性与Nginx配置挑战 在当今互联网环境中&#xff0c;SSL/TLS加密已成为网站安全的基本要求。根据Google透明度报告显示&#xff0c;截至2023年&#xff0c;全球Chrome浏览器加载的网页…

C++字符串的行输入

1、字符串的输入 下面用一个真实的示例来进行演示&#xff1a; #include<iostream> #include<string>int main() {using namespace std;const int ArSize 20;char name[ArSize];char dessert[ArSize];cout << "Enter your name:\n";cin >>…

征服分布式系统:阿里云 Linux 多机互联与资源共享实战指南

征服分布式系统&#xff1a;阿里云 Linux 多机互联与资源共享实战指南 文章目录 征服分布式系统&#xff1a;阿里云 Linux 多机互联与资源共享实战指南一、分布式系统架构概述二、阿里云网络基础架构解析三、多机互联基础配置1. 环境准备2. 网络连通性测试3. SSH 密钥认证配置 …

AI三步诊断心理:比ChatGPT更懂人心

用人工智能(大语言模型)辅助心理治疗的研究 解决心理治疗中专业人员不足的问题,提出了一种叫“思维诊断”(DoT)的方法,让AI通过三个步骤来识别患者的“认知扭曲”(也就是负面、不合理的思维模式)。 背景:心理治疗的困境 全世界约八分之一的人有心理问题,但心理咨询师…

C++【生存游戏】开发:荒岛往事 第一期

字幕君已上线...... 副字幕君已上线...... 计数君已上线...... 彩色字幕君 ( 花了重金请来的 ) 已上线...... Doge智能系统已上线...... Doge:嗨嗨我又来了&#xff01; 观众们......已上线&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; OK LETS GO&am…

k8s强制删除podpvpvc和nsnamespace

k8s如何强制删除pod&pv&pvc和ns&namespace方法 namespace、pod、pv、pvc全部处于“Terminating”状态时&#xff0c;此时的该名称空间下的所有控制器都已经被删除了&#xff0c;之所以出现pod、pvc、pv、ns无法删除&#xff0c;那是因为kubelet 阻塞&#xff0c;有…

Python基础--4--Python常用代码示例

1、文件读写操作&#xff08;常用于日志处理、数据导入导出&#xff09; 1、代码示例 &#xff08;1&#xff09;读取文本文件内容 with open("data.txt", "r", encoding"utf-8") as f:content f.read()print(content)&#xff08;2&#xf…

单项循环链表及带头指针的链表

单项循环链表及其带头指针的链表 对于链表我们要仔细深入的学习它&#xff0c;为何呢&#xff0c;因为他是我们在后面学习非线性数据结构的基础&#xff0c;像后面的树&#xff0c;图等结构都是由链表演变出来的&#xff0c;所以我们这篇博客继续探究链表 带头指针的链表 我…

八股文——JAVA基础:解释下什么是面向对象?面向对象和面向过程的区别

面向对象和面向过程是编程的不同思想&#xff1a; 面向过程如c语言的编程形式&#xff0c;在编程时定义的是一个方法&#xff0c;然后后续执行只需要关注这个方法的作用&#xff0c;而不会将方法进行抽象&#xff0c;也就是只关注程序执行的过程细节。 面向对象如java&#x…

SuperMap iServer 关闭数据目录(datacatalog)、地图打印(webprinting)等服务

背景 漏洞扫描发现有部分低危 web 漏洞&#xff0c;项目又暂未使用数据目录服务&#xff0c;所以最简单的方案是直接关闭服务。 查阅文档发现处理自动化服务可以修改webapps\iserver\WEB-INF\iserver-geoprocessing.xml 的 enable 属性为 false 关闭&#xff0c;机器学习服务…

PyTorch 张量(Tensors)全面指南:从基础到实战

文章目录 什么是张量&#xff1f;张量初始化方法1. 直接从数据创建2. 从 NumPy 数组转换3. 基于现有张量创建4. 使用随机值或常量 张量属性张量操作设备转移索引和切片连接张量算术运算单元素张量转换 原地操作&#xff08;In-place Operations&#xff09;PyTorch 与 NumPy 互…

Maven是什么?

Maven是一个流行的Java项目管理和构建工具&#xff0c;主要用于自动化项目构建、依赖管理和项目文档生成等工作。以下是对它的简单介绍&#xff1a; 核心功能 依赖管理&#xff1a;自动管理项目所需的第三方库&#xff08;如JAR包&#xff09;&#xff0c;通过在配置文件中声…

etcd教程-快速入门使用(截图实操)集群搭建 + 原理解释

大家好&#xff0c;我是此林。 etcd 是一个高可用的键值对存储系统&#xff0c;常用于分布式系统中保存配置、服务发现和协调信息。它是 CNCF 旗下的项目之一&#xff0c;也是 Kubernetes 的核心组件之一&#xff0c;用来存储集群状态。 可以说&#xff0c;云原生场景下经常使…

OpenSSL 混合加密

openssl 中文网&#xff1a; https://www.openssl.net.cn/ 目录 对称加密特点常见算法案例&#xff08;使用 AES&#xff09; 非对称加密特点常见算法案例&#xff08;使用 RSA&#xff09; 混合加密场景加密&#xff08;使用 AES&#xff09;解密 总结 对称加密 特点 加密和解…

AI驱动的DevOps运维与云服务部署自动化

引言 当前&#xff0c;云计算和DevOps实践让开发者能够管理成百上千台服务器和容器&#xff0c;但随之而来的运维复杂度也急剧提升。运维工程师经常需要部署多环境应用、维护大规模云主机、排查集群故障等任务。这些任务不仅涉及繁琐的脚本编写和命令行操作&#xff0c;还需要对…

Spring Boot动态数据源切换:优雅实现多数据源管理

在复杂的企业应用中&#xff0c;多数据源管理是常见需求。本文将介绍如何基于Spring Boot实现优雅的动态数据源切换方案&#xff0c;通过自定义注解和AOP实现透明化切换。 核心设计思路 通过三层结构实现数据源动态路由&#xff1a; 1. 注解层&#xff1a;声明式标记数据源 2…

如何挑选一款1588PTP时钟同步服务器​

在当今数字化程度极高的时代&#xff0c;高精度时间同步对于众多关键领域的高效、稳定运行起着决定性作用。PTP&#xff08;精确时间协议&#xff09;时钟作为实现高精度时间同步的核心设备&#xff0c;其性能优劣直接关乎系统整体表现。挑选一款合适的 ptp网络同步时钟&#x…

Harmony状态管理 @Local和@Param

深入理解ArkUI中的Param与Local装饰器 引言 在ArkUI的状态管理系统中&#xff0c;Param和Local是两个核心装饰器&#xff0c;它们分别用于处理组件间的数据传递和组件内部状态管理。本文将详细介绍这两个装饰器的使用场景、特性差异以及最佳实践。 Param装饰器&#xff1a;组…

物联网摄像头模块的应用场景

一、智慧城市治理 ‌智能交通优化‌ ‌动态信号控制‌&#xff1a;杭州部署20万物联网摄像头&#xff0c;实时分析车流密度并联动1200个红绿灯&#xff0c;早高峰通行效率提升40%。 ‌违规行为识别‌&#xff1a;搭载GB/T28181协议的摄像头AI抓拍交通违章&#xff0c;车牌识…

k8s Ingress、Service配置各样例大全

目录 壹、k8s Ingress 样例大全&#x1f527; 一、基础路由与 TLS 终止&#x1f504; 二、高级路由控制1. **URL 重写**&#xff08;适用后端服务路径与入口路径不一致&#xff09;2. **多路径路由到不同服务** &#x1f6a6; 三、流量治理策略1. **金丝雀发布&#xff08;灰度…