ssh: convert app-layer parser to be tx aware

Like with SSL, there is only a single 'tx'.
pull/2559/head
Victor Julien 9 years ago
parent 4ae4fd0802
commit 3ee4989ba7

@ -494,9 +494,96 @@ static void SSHStateFree(void *state)
if (s->srv_hdr.banner_buffer != NULL) if (s->srv_hdr.banner_buffer != NULL)
SCFree(s->srv_hdr.banner_buffer); SCFree(s->srv_hdr.banner_buffer);
//AppLayerDecoderEventsFreeEvents(&s->decoder_events);
if (s->de_state != NULL) {
DetectEngineStateFree(s->de_state);
}
SCFree(s); 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) static int SSHRegisterPatternsForProtocolDetection(void)
{ {
if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SSH, if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SSH,
@ -532,6 +619,22 @@ void RegisterSSHParsers(void)
AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SSH, SSHStateAlloc, SSHStateFree); AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SSH, SSHStateAlloc, SSHStateFree);
AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP,
ALPROTO_SSH, STREAM_TOSERVER|STREAM_TOCLIENT); 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 { } else {
// SCLogInfo("Parsed disabled for %s protocol. Protocol detection" // SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
// "still on.", proto_name); // "still on.", proto_name);

@ -32,8 +32,6 @@
* must be ciphered, so the parsing finish here */ * must be ciphered, so the parsing finish here */
#define SSH_FLAG_PARSER_DONE 0x02 #define SSH_FLAG_PARSER_DONE 0x02
#define SSH_FLAG_STATE_LOGGED 0x04
#define SSH_FLAG_STATE_LOGGED_LUA 0x08 #define SSH_FLAG_STATE_LOGGED_LUA 0x08
/* MSG_CODE */ /* MSG_CODE */
@ -56,6 +54,7 @@ typedef struct SshHeader_ {
uint32_t pkt_len; uint32_t pkt_len;
uint8_t padding_len; uint8_t padding_len;
uint8_t msg_code; uint8_t msg_code;
uint16_t banner_len;
uint8_t buf[6]; uint8_t buf[6];
uint8_t buf_offset; uint8_t buf_offset;
uint8_t flags; uint8_t flags;
@ -63,13 +62,23 @@ typedef struct SshHeader_ {
uint8_t *proto_version; uint8_t *proto_version;
uint8_t *software_version; uint8_t *software_version;
uint8_t *banner_buffer; uint8_t *banner_buffer;
uint16_t banner_len;
} SshHeader; } SshHeader;
enum {
SSH_STATE_IN_PROGRESS,
SSH_STATE_BANNER_DONE,
SSH_STATE_FINISHED,
};
/** structure to store the SSH state values */ /** structure to store the SSH state values */
typedef struct SshState_ { typedef struct SshState_ {
SshHeader srv_hdr; SshHeader srv_hdr;
SshHeader cli_hdr; SshHeader cli_hdr;
/* specifies which loggers are done logging */
uint32_t logged;
DetectEngineState *de_state;
} SshState; } SshState;
void RegisterSSHParsers(void); void RegisterSSHParsers(void);

@ -360,6 +360,7 @@ static int DetectSshVersionTestDetect01(void)
p->flowflags |= FLOW_PKT_ESTABLISHED; p->flowflags |= FLOW_PKT_ESTABLISHED;
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
f.alproto = ALPROTO_SSH; f.alproto = ALPROTO_SSH;
f.proto = IPPROTO_TCP;
StreamTcpInitConfig(TRUE); StreamTcpInitConfig(TRUE);
@ -477,6 +478,7 @@ static int DetectSshVersionTestDetect02(void)
p->flowflags |= FLOW_PKT_ESTABLISHED; p->flowflags |= FLOW_PKT_ESTABLISHED;
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
f.alproto = ALPROTO_SSH; f.alproto = ALPROTO_SSH;
f.proto = IPPROTO_TCP;
StreamTcpInitConfig(TRUE); StreamTcpInitConfig(TRUE);
@ -592,6 +594,7 @@ static int DetectSshVersionTestDetect03(void)
p->flowflags |= FLOW_PKT_ESTABLISHED; p->flowflags |= FLOW_PKT_ESTABLISHED;
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
f.alproto = ALPROTO_SSH; f.alproto = ALPROTO_SSH;
f.proto = IPPROTO_TCP;
StreamTcpInitConfig(TRUE); StreamTcpInitConfig(TRUE);

@ -332,6 +332,7 @@ static int DetectSshSoftwareVersionTestDetect01(void)
p->flowflags |= FLOW_PKT_ESTABLISHED; p->flowflags |= FLOW_PKT_ESTABLISHED;
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
f.alproto = ALPROTO_SSH; f.alproto = ALPROTO_SSH;
f.proto = IPPROTO_TCP;
StreamTcpInitConfig(TRUE); StreamTcpInitConfig(TRUE);
@ -449,6 +450,7 @@ static int DetectSshSoftwareVersionTestDetect02(void)
p->flowflags |= FLOW_PKT_ESTABLISHED; p->flowflags |= FLOW_PKT_ESTABLISHED;
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
f.alproto = ALPROTO_SSH; f.alproto = ALPROTO_SSH;
f.proto = IPPROTO_TCP;
StreamTcpInitConfig(TRUE); StreamTcpInitConfig(TRUE);
@ -565,6 +567,7 @@ static int DetectSshSoftwareVersionTestDetect03(void)
p->flowflags |= FLOW_PKT_ESTABLISHED; p->flowflags |= FLOW_PKT_ESTABLISHED;
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
f.alproto = ALPROTO_SSH; f.alproto = ALPROTO_SSH;
f.proto = IPPROTO_TCP;
StreamTcpInitConfig(TRUE); StreamTcpInitConfig(TRUE);

@ -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; JsonSshLogThread *aft = (JsonSshLogThread *)thread_data;
OutputSshCtx *ssh_ctx = aft->sshlog_ctx; OutputSshCtx *ssh_ctx = aft->sshlog_ctx;
if (unlikely(p->flow == NULL)) { SshState *ssh_state = (SshState *)state;
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);
if (unlikely(ssh_state == NULL)) { if (unlikely(ssh_state == NULL)) {
goto end; return 0;
} }
if (ssh_state->cli_hdr.software_version == NULL || ssh_state->srv_hdr.software_version == NULL) if (ssh_state->cli_hdr.software_version == NULL ||
goto end; ssh_state->srv_hdr.software_version == NULL)
return 0;
json_t *js = CreateJSONHeader((Packet *)p, 1, "ssh");//TODO json_t *js = CreateJSONHeader((Packet *)p, 1, "ssh");//TODO
if (unlikely(js == NULL)) if (unlikely(js == NULL))
goto end; return 0;
json_t *tjs = json_object(); json_t *tjs = json_object();
if (tjs == NULL) { if (tjs == NULL) {
free(js); free(js);
goto end; return 0;
} }
/* reset */ /* reset */
@ -132,9 +125,6 @@ static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p)
json_object_clear(js); json_object_clear(js);
json_decref(js); json_decref(js);
/* we only log the state once */
ssh_state->cli_hdr.flags |= SSH_FLAG_STATE_LOGGED;
end:
return 0; return 0;
} }
@ -230,6 +220,7 @@ OutputCtx *OutputSshLogInit(ConfNode *conf)
output_ctx->data = ssh_ctx; output_ctx->data = ssh_ctx;
output_ctx->DeInit = OutputSshLogDeinit; output_ctx->DeInit = OutputSshLogDeinit;
AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SSH);
return output_ctx; return output_ctx;
} }
@ -267,58 +258,24 @@ OutputCtx *OutputSshLogInitSub(ConfNode *conf, OutputCtx *parent_ctx)
output_ctx->data = ssh_ctx; output_ctx->data = ssh_ctx;
output_ctx->DeInit = OutputSshLogDeinitSub; output_ctx->DeInit = OutputSshLogDeinitSub;
AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SSH);
return output_ctx; 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) void JsonSshLogRegister (void)
{ {
/* register as separate module */ /* register as separate module */
OutputRegisterPacketModule(LOGGER_JSON_SSH, "JsonSshLog", "ssh-json-log", OutputRegisterTxModuleWithProgress(LOGGER_JSON_SSH,
OutputSshLogInit, JsonSshLogger, JsonSshCondition, JsonSshLogThreadInit, "JsonSshLog", "ssh-json-log",
JsonSshLogThreadDeinit, NULL); OutputSshLogInit, ALPROTO_SSH, JsonSshLogger,
SSH_STATE_BANNER_DONE, SSH_STATE_BANNER_DONE,
JsonSshLogThreadInit, JsonSshLogThreadDeinit, NULL);
/* also register as child of eve-log */ /* also register as child of eve-log */
OutputRegisterPacketSubModule(LOGGER_JSON_SSH, "eve-log", "JsonSshLog", OutputRegisterTxSubModuleWithProgress(LOGGER_JSON_SSH,
"eve-log.ssh", OutputSshLogInitSub, JsonSshLogger, JsonSshCondition, "eve-log", "JsonSshLog", "eve-log.ssh",
OutputSshLogInitSub, ALPROTO_SSH, JsonSshLogger,
SSH_STATE_BANNER_DONE, SSH_STATE_BANNER_DONE,
JsonSshLogThreadInit, JsonSshLogThreadDeinit, NULL); JsonSshLogThreadInit, JsonSshLogThreadDeinit, NULL);
} }

Loading…
Cancel
Save