]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
ssh: convert app-layer parser to be tx aware
authorVictor Julien <victor@inliniac.net>
Thu, 22 Dec 2016 11:45:17 +0000 (12:45 +0100)
committerVictor Julien <victor@inliniac.net>
Thu, 16 Feb 2017 09:35:42 +0000 (10:35 +0100)
Like with SSL, there is only a single 'tx'.

src/app-layer-ssh.c
src/app-layer-ssh.h
src/detect-ssh-proto-version.c
src/detect-ssh-software-version.c
src/output-json-ssh.c

index 7eb529407d7f84737131e15db961ca5b4baf0961..0b965eb748109802837a1576881c7380a5212be5 100644 (file)
@@ -494,9 +494,96 @@ static void SSHStateFree(void *state)
     if (s->srv_hdr.banner_buffer != NULL)
         SCFree(s->srv_hdr.banner_buffer);
 
+    //AppLayerDecoderEventsFreeEvents(&s->decoder_events);
+
+    if (s->de_state != NULL) {
+        DetectEngineStateFree(s->de_state);
+    }
+
     SCFree(s);
 }
 
+static int SSHStateHasTxDetectState(void *state)
+{
+    SshState *ssh_state = (SshState *)state;
+    if (ssh_state->de_state)
+        return 1;
+    return 0;
+}
+
+static int SSHSetTxDetectState(void *state, void *vtx, DetectEngineState *de_state)
+{
+    SshState *ssh_state = (SshState *)state;
+    ssh_state->de_state = de_state;
+    return 0;
+}
+
+static DetectEngineState *SSHGetTxDetectState(void *vtx)
+{
+    SshState *ssh_state = (SshState *)vtx;
+    return ssh_state->de_state;
+}
+
+static void SSHStateTransactionFree(void *state, uint64_t tx_id)
+{
+    /* do nothing */
+}
+
+static void *SSHGetTx(void *state, uint64_t tx_id)
+{
+    SshState *ssh_state = (SshState *)state;
+    return ssh_state;
+}
+
+static uint64_t SSHGetTxCnt(void *state)
+{
+    /* single tx */
+    return 1;
+}
+
+static void SSHSetTxLogged(void *state, void *tx, uint32_t logger)
+{
+    SshState *ssh_state = (SshState *)state;
+    if (ssh_state)
+        ssh_state->logged |= logger;
+}
+
+static int SSHGetTxLogged(void *state, void *tx, uint32_t logger)
+{
+    SshState *ssh_state = (SshState *)state;
+    if (ssh_state && (ssh_state->logged & logger)) {
+        return 1;
+    }
+    return 0;
+}
+
+static int SSHGetAlstateProgressCompletionStatus(uint8_t direction)
+{
+    return SSH_STATE_FINISHED;
+}
+
+static int SSHGetAlstateProgress(void *tx, uint8_t direction)
+{
+    SshState *ssh_state = (SshState *)tx;
+
+    if (ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE &&
+        ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE) {
+        return SSH_STATE_FINISHED;
+    }
+
+    if (direction == STREAM_TOSERVER) {
+        if (ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE) {
+            return SSH_STATE_BANNER_DONE;
+        }
+    } else {
+        if (ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE) {
+            return SSH_STATE_BANNER_DONE;
+        }
+    }
+
+    return SSH_STATE_IN_PROGRESS;
+}
+
 static int SSHRegisterPatternsForProtocolDetection(void)
 {
     if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SSH,
@@ -532,6 +619,22 @@ void RegisterSSHParsers(void)
         AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SSH, SSHStateAlloc, SSHStateFree);
         AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP,
                 ALPROTO_SSH, STREAM_TOSERVER|STREAM_TOCLIENT);
+
+        AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SSH, SSHStateTransactionFree);
+
+        AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_SSH, SSHStateHasTxDetectState,
+                                               SSHGetTxDetectState, SSHSetTxDetectState);
+
+        AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SSH, SSHGetTx);
+
+        AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SSH, SSHGetTxCnt);
+
+        AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SSH, SSHGetAlstateProgress);
+
+        AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_SSH, SSHGetTxLogged, SSHSetTxLogged);
+
+        AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_SSH,
+                                                               SSHGetAlstateProgressCompletionStatus);
     } else {
 //        SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
 //                  "still on.", proto_name);
index 4fd59aa9e1d7f0b38f3d6c099e808824f4c99a04..bf8d50b94c939bf010fce84427735c7566567624 100644 (file)
@@ -32,8 +32,6 @@
  * must be ciphered, so the parsing finish here */
 #define SSH_FLAG_PARSER_DONE                 0x02
 
-#define SSH_FLAG_STATE_LOGGED                0x04
-
 #define SSH_FLAG_STATE_LOGGED_LUA            0x08
 
 /* MSG_CODE */
@@ -56,6 +54,7 @@ typedef struct SshHeader_ {
     uint32_t pkt_len;
     uint8_t padding_len;
     uint8_t msg_code;
+    uint16_t banner_len;
     uint8_t buf[6];
     uint8_t buf_offset;
     uint8_t flags;
@@ -63,13 +62,23 @@ typedef struct SshHeader_ {
     uint8_t *proto_version;
     uint8_t *software_version;
     uint8_t *banner_buffer;
-    uint16_t banner_len;
 } SshHeader;
 
+enum {
+    SSH_STATE_IN_PROGRESS,
+    SSH_STATE_BANNER_DONE,
+    SSH_STATE_FINISHED,
+};
+
 /** structure to store the SSH state values */
 typedef struct SshState_ {
     SshHeader srv_hdr;
     SshHeader cli_hdr;
+
+    /* specifies which loggers are done logging */
+    uint32_t logged;
+
+    DetectEngineState *de_state;
 } SshState;
 
 void RegisterSSHParsers(void);
index 322a9137fbf70c2cb49f7cacc0e31f59849c1746..96b8c40ec5caf73f96a9cf762b6fa843e28cc754 100644 (file)
@@ -360,6 +360,7 @@ static int DetectSshVersionTestDetect01(void)
     p->flowflags |= FLOW_PKT_ESTABLISHED;
     p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
     f.alproto = ALPROTO_SSH;
+    f.proto = IPPROTO_TCP;
 
     StreamTcpInitConfig(TRUE);
 
@@ -477,6 +478,7 @@ static int DetectSshVersionTestDetect02(void)
     p->flowflags |= FLOW_PKT_ESTABLISHED;
     p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
     f.alproto = ALPROTO_SSH;
+    f.proto = IPPROTO_TCP;
 
     StreamTcpInitConfig(TRUE);
 
@@ -592,6 +594,7 @@ static int DetectSshVersionTestDetect03(void)
     p->flowflags |= FLOW_PKT_ESTABLISHED;
     p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
     f.alproto = ALPROTO_SSH;
+    f.proto = IPPROTO_TCP;
 
     StreamTcpInitConfig(TRUE);
 
index a9eb19267d273bfcc928f2875ca6b585e2e1311a..3032b0e6bf375c1557e534760af522b015ace33e 100644 (file)
@@ -332,6 +332,7 @@ static int DetectSshSoftwareVersionTestDetect01(void)
     p->flowflags |= FLOW_PKT_ESTABLISHED;
     p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
     f.alproto = ALPROTO_SSH;
+    f.proto = IPPROTO_TCP;
 
     StreamTcpInitConfig(TRUE);
 
@@ -449,6 +450,7 @@ static int DetectSshSoftwareVersionTestDetect02(void)
     p->flowflags |= FLOW_PKT_ESTABLISHED;
     p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
     f.alproto = ALPROTO_SSH;
+    f.proto = IPPROTO_TCP;
 
     StreamTcpInitConfig(TRUE);
 
@@ -565,6 +567,7 @@ static int DetectSshSoftwareVersionTestDetect03(void)
     p->flowflags |= FLOW_PKT_ESTABLISHED;
     p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
     f.alproto = ALPROTO_SSH;
+    f.proto = IPPROTO_TCP;
 
     StreamTcpInitConfig(TRUE);
 
index 627b2b6f598ed3a3fec4cfc46ab8f93a3a1dbc75..6d356a0024b39f6540544f5581e5948ab029c385 100644 (file)
@@ -89,36 +89,29 @@ void JsonSshLogJSON(json_t *tjs, SshState *ssh_state)
 
 }
 
-static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p)
+static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p,
+                         Flow *f, void *state, void *txptr, uint64_t tx_id)
 {
     JsonSshLogThread *aft = (JsonSshLogThread *)thread_data;
     OutputSshCtx *ssh_ctx = aft->sshlog_ctx;
 
-    if (unlikely(p->flow == NULL)) {
-        return 0;
-    }
-
-    /* check if we have SSH state or not */
-    uint16_t proto = FlowGetAppProtocol(p->flow);
-    if (proto != ALPROTO_SSH)
-        goto end;
-
-    SshState *ssh_state = (SshState *)FlowGetAppState(p->flow);
+    SshState *ssh_state = (SshState *)state;
     if (unlikely(ssh_state == NULL)) {
-        goto end;
+        return 0;
     }
 
-    if (ssh_state->cli_hdr.software_version == NULL || ssh_state->srv_hdr.software_version == NULL)
-        goto end;
+    if (ssh_state->cli_hdr.software_version == NULL ||
+            ssh_state->srv_hdr.software_version == NULL)
+        return 0;
 
     json_t *js = CreateJSONHeader((Packet *)p, 1, "ssh");//TODO
     if (unlikely(js == NULL))
-        goto end;
+        return 0;
 
     json_t *tjs = json_object();
     if (tjs == NULL) {
         free(js);
-        goto end;
+        return 0;
     }
 
     /* reset */
@@ -132,9 +125,6 @@ static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p)
     json_object_clear(js);
     json_decref(js);
 
-    /* we only log the state once */
-    ssh_state->cli_hdr.flags |= SSH_FLAG_STATE_LOGGED;
-end:
     return 0;
 }
 
@@ -230,6 +220,7 @@ OutputCtx *OutputSshLogInit(ConfNode *conf)
     output_ctx->data = ssh_ctx;
     output_ctx->DeInit = OutputSshLogDeinit;
 
+    AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SSH);
     return output_ctx;
 }
 
@@ -267,58 +258,24 @@ OutputCtx *OutputSshLogInitSub(ConfNode *conf, OutputCtx *parent_ctx)
     output_ctx->data = ssh_ctx;
     output_ctx->DeInit = OutputSshLogDeinitSub;
 
+    AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SSH);
     return output_ctx;
 }
 
-/** \internal
- *  \brief Condition function for SSH logger
- *  \retval bool true or false -- log now?
- */
-static int JsonSshCondition(ThreadVars *tv, const Packet *p)
-{
-    if (p->flow == NULL) {
-        return FALSE;
-    }
-
-    if (!(PKT_IS_TCP(p))) {
-        return FALSE;
-    }
-
-    uint16_t proto = FlowGetAppProtocol(p->flow);
-    if (proto != ALPROTO_SSH)
-        goto dontlog;
-
-    SshState *ssh_state = (SshState *)FlowGetAppState(p->flow);
-    if (ssh_state == NULL) {
-        SCLogDebug("no ssh state, so no logging");
-        goto dontlog;
-    }
-
-    /* we only log the state once */
-    if (ssh_state->cli_hdr.flags & SSH_FLAG_STATE_LOGGED)
-        goto dontlog;
-
-    if (ssh_state->cli_hdr.software_version == NULL ||
-        ssh_state->srv_hdr.software_version == NULL)
-        goto dontlog;
-
-    /* todo: logic to log once */
-
-    return TRUE;
-dontlog:
-    return FALSE;
-}
-
 void JsonSshLogRegister (void)
 {
     /* register as separate module */
-    OutputRegisterPacketModule(LOGGER_JSON_SSH, "JsonSshLog", "ssh-json-log",
-        OutputSshLogInit, JsonSshLogger, JsonSshCondition, JsonSshLogThreadInit,
-        JsonSshLogThreadDeinit, NULL);
+    OutputRegisterTxModuleWithProgress(LOGGER_JSON_SSH,
+        "JsonSshLog", "ssh-json-log",
+        OutputSshLogInit, ALPROTO_SSH, JsonSshLogger,
+        SSH_STATE_BANNER_DONE, SSH_STATE_BANNER_DONE,
+        JsonSshLogThreadInit, JsonSshLogThreadDeinit, NULL);
 
     /* also register as child of eve-log */
-    OutputRegisterPacketSubModule(LOGGER_JSON_SSH, "eve-log", "JsonSshLog",
-        "eve-log.ssh", OutputSshLogInitSub, JsonSshLogger, JsonSshCondition,
+    OutputRegisterTxSubModuleWithProgress(LOGGER_JSON_SSH,
+        "eve-log", "JsonSshLog", "eve-log.ssh",
+        OutputSshLogInitSub, ALPROTO_SSH, JsonSshLogger,
+        SSH_STATE_BANNER_DONE, SSH_STATE_BANNER_DONE,
         JsonSshLogThreadInit, JsonSshLogThreadDeinit, NULL);
 }