* \param input Pointer the received input data
* \param input_len Length in bytes of the received data
*/
-static int SSHParseVersion(SshState *state, SshHeader *header, const uint8_t *input, uint32_t input_len)
+static int SSHParseBanner(SshState *state, SshHeader *header, const uint8_t *input, uint32_t input_len)
{
const uint8_t *line_ptr = input;
uint32_t line_len = input_len;
SCReturnInt(-1);
}
if (line_len > 255) {
- SCLogInfo("Invalid version string, it should be less than 255 characters including <CR><NL>");
+ SCLogDebug("Invalid version string, it should be less than 255 characters including <CR><NL>");
SCReturnInt(-1);
}
line_ptr += proto_ver_len + 1;
line_len -= proto_ver_len + 1;
if (line_len < 1) {
- SCLogInfo("No software version specified (weird)");
+ SCLogDebug("No software version specified (weird)");
header->flags |= SSH_FLAG_VERSION_PARSED;
/* Return the remaining length */
SCReturnInt(0);
SCReturnInt(len);
}
-static int SSHParseClientRecordHeader(SshState *state, SshHeader *header, uint8_t *input, uint32_t input_len)
+static int SSHParseRecordHeader(SshState *state, SshHeader *header, uint8_t *input, uint32_t input_len)
{
+#ifdef DEBUG
BUG_ON(input_len != 6);
-
+#endif
/* input and input_len now point past initial line */
uint32_t pkt_len = 0;
int r = ByteExtractUint32(&pkt_len, BYTE_BIG_ENDIAN,
4, input);
if (r != 4) {
- SCLogInfo("xtract 4 bytes failed %d", r);
+ SCLogDebug("xtract 4 bytes failed %d", r);
SCReturnInt(-1);
}
if (pkt_len < 2) {
}
header->pkt_len = pkt_len;
- SCLogInfo("pkt len: %"PRIu32, pkt_len);
+ SCLogDebug("pkt len: %"PRIu32, pkt_len);
input += 4;
input_len -= 4;
input += 1;
input_len -= 1;
- SCLogInfo("padding: %u", header->padding_len);
+ SCLogDebug("padding: %u", header->padding_len);
header->msg_code = *input;
input += 1;
input_len -= 1;
- SCLogInfo("msg code: %u", header->msg_code);
+ SCLogDebug("msg code: %u", header->msg_code);
if (header->msg_code == SSH_MSG_NEWKEYS) {
/* done */
- SCLogInfo("done");
+ SCLogDebug("done");
state->flags |= SSH_FLAG_PARSER_DONE;
} else {
/* not yet done */
- SCLogInfo("not done");
+ SCLogDebug("not done");
}
SCReturnInt(0);
}
SCLogDebug("state %p, input %p,input_len %" PRIu32,
state, input, input_len);
- PrintRawDataFp(stdout, input, input_len);
+ //PrintRawDataFp(stdout, input, input_len);
if (!(header->flags & SSH_FLAG_VERSION_PARSED)) {
- ret = SSHParseVersion(state, header, input, input_len);
+ ret = SSHParseBanner(state, header, input, input_len);
if (ret < 0) {
SCLogDebug("Invalid version string");
SCReturnInt(-1);
} else if (header->flags & SSH_FLAG_VERSION_PARSED) {
- SCLogInfo("Version string parsed, remaining length %d", ret);
+ SCLogDebug("Version string parsed, remaining length %d", ret);
input += input_len - ret;
input_len -= (input_len - ret);
ret = 0;
while (u < input_len && (input[u] == '\r' || input[u] == '\n')) {
u++;
}
- SCLogInfo("skipping %u EOL bytes", u);
+ SCLogDebug("skipping %u EOL bytes", u);
input += u;
input_len -= u;
}
/* skip bytes from the current record if we have to */
- if (state->cli_hdr.record_left > 0) {
- SCLogInfo("skipping bytes part of the current record");
- if (state->cli_hdr.record_left > input_len) {
- state->cli_hdr.record_left -= input_len;
- SCLogInfo("all input skipped, %u left in record", state->cli_hdr.record_left);
+ if (header->record_left > 0) {
+ SCLogDebug("skipping bytes part of the current record");
+ if (header->record_left > input_len) {
+ header->record_left -= input_len;
+ SCLogDebug("all input skipped, %u left in record", header->record_left);
SCReturnInt(0);
} else {
- input_len -= state->cli_hdr.record_left;
- input += state->cli_hdr.record_left;
- state->cli_hdr.record_left = 0;
+ input_len -= header->record_left;
+ input += header->record_left;
+ header->record_left = 0;
if (input_len == 0) {
- SCLogInfo("all input skipped");
+ SCLogDebug("all input skipped");
SCReturnInt(0);
}
}
again:
/* input is too small, even when combined with stored bytes */
- if (state->cli_hdr.buf_offset + input_len < 6) {
- memcpy(state->cli_hdr.buf + state->cli_hdr.buf_offset, input, input_len);
- state->cli_hdr.buf_offset += input_len;
-
- //PrintRawDataFp(stdout, state->cli_hdr.buf, state->cli_hdr.buf_offset);
+ if (header->buf_offset + input_len < 6) {
+ memcpy(header->buf + header->buf_offset, input, input_len);
+ header->buf_offset += input_len;
SCReturnInt(0);
/* we have enough bytes to parse 6 bytes, lets see if we have
* previously stored some */
- } else if (state->cli_hdr.buf_offset > 0) {
- uint8_t needed = 6 - state->cli_hdr.buf_offset;
+ } else if (header->buf_offset > 0) {
+ uint8_t needed = 6 - header->buf_offset;
- SCLogInfo("parse stored");
- memcpy(state->cli_hdr.buf + state->cli_hdr.buf_offset, input, needed);
- state->cli_hdr.buf_offset = 6;
+ SCLogDebug("parse stored");
+ memcpy(header->buf + header->buf_offset, input, needed);
+ header->buf_offset = 6;
// parse the 6
- if (SSHParseClientRecordHeader(state, header, state->cli_hdr.buf, 6) < 0)
+ if (SSHParseRecordHeader(state, header, header->buf, 6) < 0)
SCReturnInt(-1);
- state->cli_hdr.buf_offset = 0;
+ header->buf_offset = 0;
- uint32_t record_left = state->cli_hdr.pkt_len - 2;
+ uint32_t record_left = header->pkt_len - 2;
input_len -= needed;
input += needed;
if (record_left > input_len) {
- state->cli_hdr.record_left = record_left - input_len;
+ header->record_left = record_left - input_len;
} else {
input_len -= record_left;
if (input_len == 0)
/* nothing stored, lets parse this directly */
} else {
- // parse the 6
- SCLogInfo("parse direct");
- PrintRawDataFp(stdout, input, input_len);
- if (SSHParseClientRecordHeader(state, header, input, 6) < 0)
+ SCLogDebug("parse direct");
+ //PrintRawDataFp(stdout, input, input_len);
+ if (SSHParseRecordHeader(state, header, input, 6) < 0)
SCReturnInt(-1);
- uint32_t record_left = state->cli_hdr.pkt_len - 2;
- SCLogInfo("record left %u", record_left);
+ uint32_t record_left = header->pkt_len - 2;
+ SCLogDebug("record left %u", record_left);
input_len -= 6;
input += 6;
if (record_left > input_len) {
- state->cli_hdr.record_left = record_left - input_len;
+ header->record_left = record_left - input_len;
} else {
input_len -= record_left;
if (input_len == 0)
return FALSE;
}
-static int SSHParseRequest(Flow *f, void *state, AppLayerParserState *pstate,
- uint8_t *input, uint32_t input_len,
- void *local_data)
+static int SSHParseData(SshState *state, SshHeader *header,
+ uint8_t *input, uint32_t input_len)
{
- SshState *ssh_state = (SshState *)state;
+ /* we're looking for the banner */
+ if (!(header->flags & SSH_FLAG_VERSION_PARSED))
+ {
+ int banner_eol = EnoughData(input, input_len);
+
+ /* fast track normal case: no buffering */
+ if (header->banner_buffer == NULL && banner_eol)
+ {
+ SCLogDebug("enough data, parse now");
+ // parse now
+ int r = SSHParseRecord(state, header, input, input_len);
+ SCReturnInt(r);
+
+ /* banner EOL with existing buffer present. Time for magic. */
+ } else if (banner_eol) {
+ SCLogDebug("banner EOL with existing buffer");
+
+ uint32_t tocopy = 256 - header->banner_len;
+ if (tocopy > input_len)
+ tocopy = input_len;
+
+ memcpy(header->banner_buffer + header->banner_len, input, tocopy);
+ header->banner_len += tocopy;
+
+ int r = SSHParseRecord(state, header,
+ header->banner_buffer, header->banner_len);
+ SCReturnInt(r);
+
+ /* no banner EOL, so we need to buffer */
+ } else if (!banner_eol) {
+ if (header->banner_buffer == NULL) {
+ header->banner_buffer = SCMalloc(256);
+ if (header->banner_buffer == NULL)
+ SCReturnInt(-1);
+ }
- if (ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED || EnoughData(input, input_len) == TRUE) {
- SCLogInfo("enough data, parse now");
- // parse now
- int r = SSHParseRecord(ssh_state, &ssh_state->cli_hdr, input, input_len);
- SCReturnInt(r);
+ uint32_t tocopy = 256 - header->banner_len;
+ if (tocopy > input_len)
+ tocopy = input_len;
+
+ memcpy(header->banner_buffer + header->banner_len, input, tocopy);
+ header->banner_len += tocopy;
+ }
+
+ /* we have a banner, the rest is just records */
} else {
- // buffer
+ int r = SSHParseRecord(state, header, input, input_len);
+ SCReturnInt(r);
}
- PrintRawDataFp(stdout, input, input_len);
+ //PrintRawDataFp(stdout, input, input_len);
return 0;
}
+static int SSHParseRequest(Flow *f, void *state, AppLayerParserState *pstate,
+ uint8_t *input, uint32_t input_len,
+ void *local_data)
+{
+ SshState *ssh_state = (SshState *)state;
+ SshHeader *ssh_header = &ssh_state->cli_hdr;
+
+ int r = SSHParseData(ssh_state, ssh_header, input, input_len);
+ SCReturnInt(r);
+}
+
static int SSHParseResponse(Flow *f, void *state, AppLayerParserState *pstate,
uint8_t *input, uint32_t input_len,
void *local_data)
{
SshState *ssh_state = (SshState *)state;
+ SshHeader *ssh_header = &ssh_state->srv_hdr;
- if (ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED || EnoughData(input, input_len) == TRUE) {
- SCLogInfo("enough data, parse now");
- // parse now
- int r = SSHParseRecord(ssh_state, &ssh_state->srv_hdr, input, input_len);
- SCReturnInt(r);
- } else {
- // buffer
- }
-
- PrintRawDataFp(stdout, input, input_len);
- return 0;
+ int r = SSHParseData(ssh_state, ssh_header, input, input_len);
+ SCReturnInt(r);
}
/** \brief Function to allocates the SSH state memory
SCFree(s->cli_hdr.proto_version);
if (s->cli_hdr.software_version != NULL)
SCFree(s->cli_hdr.software_version);
+ if (s->cli_hdr.banner_buffer != NULL)
+ SCFree(s->cli_hdr.banner_buffer);
+
if (s->srv_hdr.proto_version != NULL)
SCFree(s->srv_hdr.proto_version);
if (s->srv_hdr.software_version != NULL)
SCFree(s->srv_hdr.software_version);
+ if (s->srv_hdr.banner_buffer != NULL)
+ SCFree(s->srv_hdr.banner_buffer);
SCFree(s);
}
uint32_t sshlen1 = sizeof(sshbuf1) - 1;
uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n";
uint32_t sshlen2 = sizeof(sshbuf2) - 1;
- uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03,0x01, 17, 0x00};
+ uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 17, 0x00};
uint32_t sshlen3 = sizeof(sshbuf3);
- uint8_t sshbuf4[] = { 0x00, 0x00, 0x00, 0x03,0x01, 21, 0x00};
+ uint8_t sshbuf4[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00};
uint32_t sshlen4 = sizeof(sshbuf4);
TcpSession ssn;
AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();