• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 22550934724

01 Mar 2026 07:34PM UTC coverage: 75.853% (+2.2%) from 73.687%
22550934724

Pull #14923

github

web-flow
github-actions: bump github/codeql-action from 4.32.3 to 4.32.4

Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.32.3 to 4.32.4.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Commits](https://github.com/github/codeql-action/compare/v4.32.3...v4.32.4)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.32.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #14923: github-actions: bump github/codeql-action from 4.32.3 to 4.32.4

240804 of 317461 relevant lines covered (75.85%)

2441195.36 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.11
/src/app-layer-ssh.c
1
/* Copyright (C) 2007-2014 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17

18
/**
19
 * \file
20
 *
21
 * \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
22
 * \author Victor Julien <victor@inliniac.net>
23
 *
24
 * App-layer parser for SSH protocol
25
 *
26
 */
27

28
#include "suricata-common.h"
29
#include "decode.h"
30
#include "threads.h"
31

32
#include "util-print.h"
33
#include "util-pool.h"
34

35
#include "stream-tcp-private.h"
36
#include "stream-tcp-reassemble.h"
37
#include "stream-tcp.h"
38
#include "stream.h"
39

40
#include "app-layer-detect-proto.h"
41
#include "app-layer-protos.h"
42
#include "app-layer-parser.h"
43
#include "app-layer-ssh.h"
44
#include "rust.h"
45

46
#include "conf.h"
47

48
#include "util-spm.h"
49
#include "util-unittest.h"
50
#include "util-debug.h"
51
#include "flow-private.h"
52

53
#include "util-byte.h"
54
#include "util-memcmp.h"
55

56
/* HASSH fingerprints are disabled by default */
57
#define SSH_CONFIG_DEFAULT_HASSH false
32✔
58
/* Bypassing the encrypted part of the connections */
59
#define SSH_CONFIG_DEFAULT_ENCRYPTION_BYPASS ENCRYPTION_HANDLING_TRACK_ONLY
17✔
60

61
static int SSHRegisterPatternsForProtocolDetection(void)
62
{
17✔
63
    if (SCAppLayerProtoDetectPMRegisterPatternCI(
17✔
64
                IPPROTO_TCP, ALPROTO_SSH, "SSH-", 4, 0, STREAM_TOSERVER) < 0) {
17✔
65
        return -1;
×
66
    }
×
67
    if (SCAppLayerProtoDetectPMRegisterPatternCI(
17✔
68
                IPPROTO_TCP, ALPROTO_SSH, "SSH-", 4, 0, STREAM_TOCLIENT) < 0) {
17✔
69
        return -1;
×
70
    }
×
71
    return 0;
17✔
72
}
17✔
73

74
bool SSHTxLogCondition(ThreadVars *tv, const Packet *p, void *state, void *tx, uint64_t tx_id)
75
{
1,720✔
76
    return SCSshTxGetLogCondition(tx);
1,720✔
77
}
1,720✔
78

79
/** \brief Function to register the SSH protocol parsers and other functions
80
 */
81
void RegisterSSHParsers(void)
82
{
17✔
83
    const char *proto_name = "ssh";
17✔
84

85
    if (SCAppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
17✔
86
        AppLayerProtoDetectRegisterProtocol(ALPROTO_SSH, proto_name);
17✔
87
        if (SSHRegisterPatternsForProtocolDetection() < 0)
17✔
88
            return;
×
89

90
        /* Check if we should generate Hassh fingerprints */
91
        int enable_hassh = SSH_CONFIG_DEFAULT_HASSH;
17✔
92
        const char *strval = NULL;
17✔
93
        if (SCConfGet("app-layer.protocols.ssh.hassh", &strval) != 1) {
17✔
94
            enable_hassh = SSH_CONFIG_DEFAULT_HASSH;
15✔
95
        } else if (strcmp(strval, "auto") == 0) {
15✔
96
            enable_hassh = SSH_CONFIG_DEFAULT_HASSH;
×
97
        } else if (SCConfValIsFalse(strval)) {
2✔
98
            enable_hassh = SSH_CONFIG_DEFAULT_HASSH;
×
99
            SCSshDisableHassh();
×
100
        } else if (SCConfValIsTrue(strval)) {
2✔
101
            enable_hassh = true;
2✔
102
        }
2✔
103

104
        if (RunmodeIsUnittests() || enable_hassh) {
17✔
105
            SCSshEnableHassh();
3✔
106
        }
3✔
107

108
        EncryptionHandling encryption_bypass = SSH_CONFIG_DEFAULT_ENCRYPTION_BYPASS;
17✔
109
        SCConfNode *encryption_node = SCConfGetNode("app-layer.protocols.ssh.encryption-handling");
17✔
110
        if (encryption_node != NULL && encryption_node->val != NULL) {
17✔
111
            if (strcmp(encryption_node->val, "full") == 0) {
×
112
                encryption_bypass = ENCRYPTION_HANDLING_FULL;
×
113
            } else if (strcmp(encryption_node->val, "track-only") == 0) {
×
114
                encryption_bypass = ENCRYPTION_HANDLING_TRACK_ONLY;
×
115
            } else if (strcmp(encryption_node->val, "bypass") == 0) {
×
116
                encryption_bypass = ENCRYPTION_HANDLING_BYPASS;
×
117
            } else {
×
118
                encryption_bypass = SSH_CONFIG_DEFAULT_ENCRYPTION_BYPASS;
×
119
            }
×
120
        }
×
121

122
        if (encryption_bypass) {
17✔
123
            SCLogConfig("ssh: bypass on the start of encryption enabled");
×
124
            SCSshEnableBypass(encryption_bypass);
×
125
        }
×
126
    }
17✔
127

128
    SCLogDebug("Registering Rust SSH parser.");
17✔
129
    SCRegisterSshParser();
17✔
130

131
#ifdef UNITTESTS
6✔
132
    AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_SSH, SSHParserRegisterTests);
6✔
133
#endif
6✔
134
}
17✔
135

136
/* UNITTESTS */
137
#ifdef UNITTESTS
138
#include "flow-util.h"
139
#include "stream-tcp-util.h"
140
#include "util-unittest-helper.h"
141

142
static int SSHParserTestUtilCheck(const char *protoexp, const char *softexp, void *tx, uint8_t flags) {
20✔
143
    const uint8_t *protocol = NULL;
20✔
144
    uint32_t p_len = 0;
20✔
145
    const uint8_t *software = NULL;
20✔
146
    uint32_t s_len = 0;
20✔
147

148
    if (SCSshTxGetProtocol(tx, flags, &protocol, &p_len) != 1) {
20✔
149
        printf("Version string not parsed correctly return: ");
150
        return 1;
151
    }
152
    if (protocol == NULL) {
20✔
153
        printf("Version string not parsed correctly NULL: ");
154
        return 1;
155
    }
156

157
    if (p_len != strlen(protoexp)) {
20✔
158
        printf("Version string not parsed correctly length: ");
159
        return 1;
160
    }
161
    if (memcmp(protocol, protoexp, strlen(protoexp)) != 0) {
20✔
162
        printf("Version string not parsed correctly: ");
163
        return 1;
164
    }
165

166
    if (softexp != NULL) {
20✔
167
        if (SCSshTxGetSoftware(tx, flags, &software, &s_len) != 1)
17✔
168
            return 1;
169
        if (software == NULL)
17✔
170
            return 1;
171
        if (s_len != strlen(softexp)) {
17✔
172
            printf("Software string not parsed correctly length: ");
173
            return 1;
174
        }
175
        if (memcmp(software, softexp, strlen(softexp)) != 0) {
17✔
176
            printf("Software string not parsed correctly: ");
177
            return 1;
178
        }
179
    }
17✔
180
    return 0;
20✔
181
}
20✔
182

183
/** \test Send a version string in one chunk (client version str). */
184
static int SSHParserTest01(void)
185
{
1✔
186
    Flow f;
1✔
187
    uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1\n";
1✔
188
    uint32_t sshlen = sizeof(sshbuf) - 1;
1✔
189
    TcpSession ssn;
1✔
190
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1✔
191

192
    memset(&f, 0, sizeof(f));
1✔
193
    memset(&ssn, 0, sizeof(ssn));
1✔
194
    FLOW_INITIALIZE(&f);
1✔
195
    f.protoctx = (void *)&ssn;
1✔
196
    f.proto = IPPROTO_TCP;
1✔
197
    f.alproto = ALPROTO_SSH;
1✔
198

199
    StreamTcpInitConfig(true);
1✔
200

201
    int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1✔
202
                                STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen);
1✔
203
    FAIL_IF_NOT(r == 0);
1✔
204

205
    void *ssh_state = f.alstate;
1✔
206
    FAIL_IF_NULL(ssh_state);
1✔
207

208
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
209
    FAIL_IF_NULL(tx);
1✔
210
    FAIL_IF(SCSshTxGetAlStateProgress(tx, STREAM_TOSERVER) != SshStateBannerDone);
1✔
211
    FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER));
1✔
212

213
    FLOW_DESTROY(&f);
1✔
214
    AppLayerParserThreadCtxFree(alp_tctx);
1✔
215
    StreamTcpFreeConfig(true);
1✔
216
    PASS;
1✔
217
}
1✔
218

219
/** \test Send a version string in one chunk but multiple lines and comments.
220
 *        (client version str)
221
 */
222
static int SSHParserTest02(void)
223
{
1✔
224
    int result = 0;
1✔
225
    Flow f;
1✔
226
    uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1 some comments...\n";
1✔
227
    uint32_t sshlen = sizeof(sshbuf) - 1;
1✔
228
    TcpSession ssn;
1✔
229
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1✔
230

231
    memset(&f, 0, sizeof(f));
1✔
232
    memset(&ssn, 0, sizeof(ssn));
1✔
233
    FLOW_INITIALIZE(&f);
1✔
234
    f.protoctx = (void *)&ssn;
1✔
235
    f.proto = IPPROTO_TCP;
1✔
236
    f.alproto = ALPROTO_SSH;
1✔
237

238
    StreamTcpInitConfig(true);
1✔
239

240
    int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1✔
241
                                STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen);
1✔
242
    if (r != 0) {
1✔
243
        printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r);
244
        goto end;
245
    }
246

247
    void *ssh_state = f.alstate;
1✔
248
    if (ssh_state == NULL) {
1✔
249
        printf("no ssh state: ");
250
        goto end;
251
    }
252
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
253

254
    if (SCSshTxGetAlStateProgress(tx, STREAM_TOSERVER) != SshStateBannerDone) {
1✔
255
        printf("Client version string not parsed: ");
256
        goto end;
257
    }
258
    if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER))
1✔
259
        goto end;
260

261
    result = 1;
1✔
262
end:
1✔
263
    FLOW_DESTROY(&f);
1✔
264
    if (alp_tctx != NULL)
1✔
265
        AppLayerParserThreadCtxFree(alp_tctx);
1✔
266
    StreamTcpFreeConfig(true);
1✔
267
    return result;
1✔
268
}
1✔
269

270
/** \test Send a invalid version string in one chunk but multiple lines and comments.
271
 *        (client version str)
272
 */
273
static int SSHParserTest03(void)
274
{
1✔
275
    int result = 0;
1✔
276
    Flow f;
1✔
277
    uint8_t sshbuf[] = "SSH-2.0 some comments...\n";
1✔
278
    uint32_t sshlen = sizeof(sshbuf) - 1;
1✔
279
    TcpSession ssn;
1✔
280
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1✔
281

282
    memset(&f, 0, sizeof(f));
1✔
283
    memset(&ssn, 0, sizeof(ssn));
1✔
284
    FLOW_INITIALIZE(&f);
1✔
285
    f.protoctx = (void *)&ssn;
1✔
286
    f.proto = IPPROTO_TCP;
1✔
287
    f.alproto = ALPROTO_SSH;
1✔
288

289
    StreamTcpInitConfig(true);
1✔
290

291
    int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1✔
292
                                STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen);
1✔
293
    if (r == 0) {
1✔
294
        printf("toclient chunk 1 returned %" PRId32 ", expected != 0: ", r);
295
        goto end;
296
    }
297

298
    void *ssh_state = f.alstate;
1✔
299
    if (ssh_state == NULL) {
1✔
300
        printf("no ssh state: ");
301
        goto end;
302
    }
303
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
304

305
    if (SCSshTxGetAlStateProgress(tx, STREAM_TOSERVER) == SshStateBannerDone) {
1✔
306
        printf("Client version string parsed? It's not a valid string: ");
307
        goto end;
308
    }
309
    const uint8_t *dummy = NULL;
1✔
310
    uint32_t dummy_len = 0;
1✔
311
    if (SCSshTxGetProtocol(tx, STREAM_TOSERVER, &dummy, &dummy_len) != 0)
1✔
312
        goto end;
313
    if (SCSshTxGetSoftware(tx, STREAM_TOSERVER, &dummy, &dummy_len) != 0)
1✔
314
        goto end;
315

316
    result = 1;
1✔
317
end:
1✔
318
    FLOW_DESTROY(&f);
1✔
319
    if (alp_tctx != NULL)
1✔
320
        AppLayerParserThreadCtxFree(alp_tctx);
1✔
321
    StreamTcpFreeConfig(true);
1✔
322
    return result;
1✔
323
}
1✔
324

325
/** \test Send a version string in one chunk (server version str). */
326
static int SSHParserTest04(void)
327
{
1✔
328
    int result = 0;
1✔
329
    Flow f;
1✔
330
    uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1\n";
1✔
331
    uint32_t sshlen = sizeof(sshbuf) - 1;
1✔
332
    TcpSession ssn;
1✔
333
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1✔
334

335
    memset(&f, 0, sizeof(f));
1✔
336
    memset(&ssn, 0, sizeof(ssn));
1✔
337
    FLOW_INITIALIZE(&f);
1✔
338
    f.protoctx = (void *)&ssn;
1✔
339
    f.proto = IPPROTO_TCP;
1✔
340
    f.alproto = ALPROTO_SSH;
1✔
341

342
    StreamTcpInitConfig(true);
1✔
343

344
    int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1✔
345
                                STREAM_TOCLIENT | STREAM_EOF, sshbuf, sshlen);
1✔
346
    if (r != 0) {
1✔
347
        printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
348
        goto end;
349
    }
350

351
    void *ssh_state = f.alstate;
1✔
352
    if (ssh_state == NULL) {
1✔
353
        printf("no ssh state: ");
354
        goto end;
355
    }
356
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
357

358
    if (SCSshTxGetAlStateProgress(tx, STREAM_TOCLIENT) != SshStateBannerDone) {
1✔
359
        printf("Client version string not parsed: ");
360
        goto end;
361
    }
362
    if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT))
1✔
363
        goto end;
364

365
    result = 1;
1✔
366

367
end:
1✔
368
    FLOW_DESTROY(&f);
1✔
369
    if (alp_tctx != NULL)
1✔
370
        AppLayerParserThreadCtxFree(alp_tctx);
1✔
371
    StreamTcpFreeConfig(true);
1✔
372
    return result;
1✔
373
}
1✔
374

375
/** \test Send a version string in one chunk (server version str)
376
 */
377
static int SSHParserTest05(void)
378
{
1✔
379
    int result = 0;
1✔
380
    Flow f;
1✔
381
    uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1 some comments...\n";
1✔
382
    uint32_t sshlen = sizeof(sshbuf) - 1;
1✔
383
    TcpSession ssn;
1✔
384
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1✔
385

386
    memset(&f, 0, sizeof(f));
1✔
387
    memset(&ssn, 0, sizeof(ssn));
1✔
388
    FLOW_INITIALIZE(&f);
1✔
389
    f.protoctx = (void *)&ssn;
1✔
390
    f.proto = IPPROTO_TCP;
1✔
391
    f.alproto = ALPROTO_SSH;
1✔
392

393
    StreamTcpInitConfig(true);
1✔
394

395
    int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1✔
396
                                STREAM_TOCLIENT | STREAM_EOF, sshbuf, sshlen);
1✔
397
    if (r != 0) {
1✔
398
        printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
399
        goto end;
400
    }
401

402
    void *ssh_state = f.alstate;
1✔
403
    if (ssh_state == NULL) {
1✔
404
        printf("no ssh state: ");
405
        goto end;
406
    }
407
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
408

409
    if (SCSshTxGetAlStateProgress(tx, STREAM_TOCLIENT) != SshStateBannerDone) {
1✔
410
        printf("Client version string not parsed: ");
411
        goto end;
412
    }
413
    if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT))
1✔
414
        goto end;
415

416
    result = 1;
1✔
417
end:
1✔
418
    FLOW_DESTROY(&f);
1✔
419
    if (alp_tctx != NULL)
1✔
420
        AppLayerParserThreadCtxFree(alp_tctx);
1✔
421
    StreamTcpFreeConfig(true);
1✔
422
    return result;
1✔
423
}
1✔
424

425
/** \test Send a invalid version string in one chunk (server version str)
426
 */
427
static int SSHParserTest06(void)
428
{
1✔
429
    int result = 0;
1✔
430
    Flow f;
1✔
431
    uint8_t sshbuf[] = "SSH-2.0 some comments...\n";
1✔
432
    uint32_t sshlen = sizeof(sshbuf) - 1;
1✔
433
    TcpSession ssn;
1✔
434
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1✔
435

436
    memset(&f, 0, sizeof(f));
1✔
437
    memset(&ssn, 0, sizeof(ssn));
1✔
438
    FLOW_INITIALIZE(&f);
1✔
439
    f.protoctx = (void *)&ssn;
1✔
440
    f.proto = IPPROTO_TCP;
1✔
441
    f.alproto = ALPROTO_SSH;
1✔
442

443
    StreamTcpInitConfig(true);
1✔
444

445
    int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1✔
446
                                STREAM_TOCLIENT | STREAM_EOF, sshbuf, sshlen);
1✔
447
    if (r == 0) {
1✔
448
        printf("toserver chunk 1 returned %" PRId32 ", expected != 0: ", r);
449
        goto end;
450
    }
451
    /* Ok, it returned an error. Let's make sure we didn't parse the string at all */
452

453
    void *ssh_state = f.alstate;
1✔
454
    if (ssh_state == NULL) {
1✔
455
        printf("no ssh state: ");
456
        goto end;
457
    }
458
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
459

460
    if (SCSshTxGetAlStateProgress(tx, STREAM_TOCLIENT) == SshStateBannerDone) {
1✔
461
        printf("Client version string parsed? It's not a valid string: ");
462
        goto end;
463
    }
464
    const uint8_t *dummy = NULL;
1✔
465
    uint32_t dummy_len = 0;
1✔
466
    if (SCSshTxGetProtocol(tx, STREAM_TOCLIENT, &dummy, &dummy_len) != 0)
1✔
467
        goto end;
468
    if (SCSshTxGetSoftware(tx, STREAM_TOCLIENT, &dummy, &dummy_len) != 0)
1✔
469
        goto end;
470

471
    result = 1;
1✔
472
end:
1✔
473
    FLOW_DESTROY(&f);
1✔
474
    if (alp_tctx != NULL)
1✔
475
        AppLayerParserThreadCtxFree(alp_tctx);
1✔
476
    StreamTcpFreeConfig(true);
1✔
477
    return result;
1✔
478
}
1✔
479

480
#define MAX_SSH_TEST_SIZE 512
481

482
static int SSHParserTest07(void)
483
{
1✔
484
    TcpReassemblyThreadCtx *ra_ctx = NULL;
1✔
485
    ThreadVars tv;
1✔
486
    TcpSession ssn;
1✔
487
    Flow *f = NULL;
1✔
488
    Packet *p = NULL;
1✔
489

490
    char sshbufs[2][MAX_SSH_TEST_SIZE] = {"SSH-2.", "0-MySSHClient-0.5.1\r\n"};
1✔
491

492
    memset(&tv, 0x00, sizeof(tv));
1✔
493

494
    StreamTcpUTInit(&ra_ctx);
1✔
495
    StreamTcpUTInitInline();
1✔
496
    StreamTcpUTSetupSession(&ssn);
1✔
497
    StreamTcpUTSetupStream(&ssn.server, 1);
1✔
498
    StreamTcpUTSetupStream(&ssn.client, 1);
1✔
499

500
    f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
1✔
501
    FAIL_IF_NULL(f);
1✔
502
    f->protoctx = &ssn;
1✔
503
    f->proto = IPPROTO_TCP;
1✔
504
    f->alproto = ALPROTO_SSH;
1✔
505

506
    p = PacketGetFromAlloc();
1✔
507
    FAIL_IF(unlikely(p == NULL));
1✔
508
    p->proto = IPPROTO_TCP;
1✔
509
    p->flow = f;
1✔
510

511
    uint32_t seq = 2;
1✔
512
    for (int i=0; i<2; i++) {
3✔
513
        FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, seq, (uint8_t *) sshbufs[i], strlen(sshbufs[i])) == -1);
2✔
514
        seq += strlen(sshbufs[i]);
2✔
515
        FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < 0);
2✔
516
    }
2✔
517

518
    void *ssh_state = f->alstate;
1✔
519
    FAIL_IF_NULL(ssh_state);
1✔
520
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
521
    FAIL_IF(SCSshTxGetAlStateProgress(tx, STREAM_TOSERVER) != SshStateBannerDone);
1✔
522

523
    FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER));
1✔
524

525
    UTHFreePacket(p);
1✔
526
    UTHFreeFlow(f);
1✔
527
    StreamTcpUTClearSession(&ssn);
1✔
528
    StreamTcpUTDeinit(ra_ctx);
1✔
529
    PASS;
1✔
530
}
1✔
531

532
/** \test Send a version banner in three chunks. */
533
static int SSHParserTest08(void)
534
{
1✔
535
    TcpReassemblyThreadCtx *ra_ctx = NULL;
1✔
536
    ThreadVars tv;
1✔
537
    TcpSession ssn;
1✔
538
    Flow *f = NULL;
1✔
539
    Packet *p = NULL;
1✔
540

541
    char sshbufs[3][MAX_SSH_TEST_SIZE] = {"SSH-", "2.", "0-MySSHClient-0.5.1\r\n"};
1✔
542

543
    memset(&tv, 0x00, sizeof(tv));
1✔
544

545
    StreamTcpUTInit(&ra_ctx);
1✔
546
    StreamTcpUTInitInline();
1✔
547
    StreamTcpUTSetupSession(&ssn);
1✔
548
    StreamTcpUTSetupStream(&ssn.server, 1);
1✔
549
    StreamTcpUTSetupStream(&ssn.client, 1);
1✔
550

551
    f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
1✔
552
    FAIL_IF_NULL(f);
1✔
553
    f->protoctx = &ssn;
1✔
554
    f->proto = IPPROTO_TCP;
1✔
555
    f->alproto = ALPROTO_SSH;
1✔
556

557
    p = PacketGetFromAlloc();
1✔
558
    FAIL_IF(unlikely(p == NULL));
1✔
559
    p->proto = IPPROTO_TCP;
1✔
560
    p->flow = f;
1✔
561

562
    uint32_t seq = 2;
1✔
563
    for (int i=0; i<3; i++) {
4✔
564
        FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, seq, (uint8_t *) sshbufs[i], strlen(sshbufs[i])) == -1);
3✔
565
        seq += strlen(sshbufs[i]);
3✔
566
        FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < 0);
3✔
567
    }
3✔
568

569
    void *ssh_state = f->alstate;
1✔
570
    FAIL_IF_NULL(ssh_state);
1✔
571
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
572
    FAIL_IF(SCSshTxGetAlStateProgress(tx, STREAM_TOSERVER) != SshStateBannerDone);
1✔
573

574
    FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER));
1✔
575

576
    UTHFreePacket(p);
1✔
577
    UTHFreeFlow(f);
1✔
578
    StreamTcpUTClearSession(&ssn);
1✔
579
    StreamTcpUTDeinit(ra_ctx);
1✔
580
    PASS;
1✔
581
}
1✔
582

583
static int SSHParserTest09(void)
584
{
1✔
585
    TcpReassemblyThreadCtx *ra_ctx = NULL;
1✔
586
    ThreadVars tv;
1✔
587
    TcpSession ssn;
1✔
588
    Flow *f = NULL;
1✔
589
    Packet *p = NULL;
1✔
590

591
    char sshbufs[2][MAX_SSH_TEST_SIZE] = {"SSH-2.", "0-MySSHClient-0.5.1\r\n"};
1✔
592

593
    memset(&tv, 0x00, sizeof(tv));
1✔
594

595
    StreamTcpUTInit(&ra_ctx);
1✔
596
    StreamTcpUTInitInline();
1✔
597
    StreamTcpUTSetupSession(&ssn);
1✔
598
    StreamTcpUTSetupStream(&ssn.server, 1);
1✔
599
    StreamTcpUTSetupStream(&ssn.client, 1);
1✔
600

601
    f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
1✔
602
    FAIL_IF_NULL(f);
1✔
603
    f->protoctx = &ssn;
1✔
604
    f->proto = IPPROTO_TCP;
1✔
605
    f->alproto = ALPROTO_SSH;
1✔
606

607
    p = PacketGetFromAlloc();
1✔
608
    FAIL_IF(unlikely(p == NULL));
1✔
609
    p->proto = IPPROTO_TCP;
1✔
610
    p->flow = f;
1✔
611

612
    uint32_t seq = 2;
1✔
613
    for (int i=0; i<2; i++) {
3✔
614
        FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, (uint8_t *) sshbufs[i], strlen(sshbufs[i])) == -1);
2✔
615
        seq += strlen(sshbufs[i]);
2✔
616
        FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0);
2✔
617
    }
2✔
618

619
    void *ssh_state = f->alstate;
1✔
620
    FAIL_IF_NULL(ssh_state);
1✔
621
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
622
    FAIL_IF(SCSshTxGetAlStateProgress(tx, STREAM_TOCLIENT) != SshStateBannerDone);
1✔
623

624
    FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT));
1✔
625

626
    UTHFreePacket(p);
1✔
627
    UTHFreeFlow(f);
1✔
628
    StreamTcpUTClearSession(&ssn);
1✔
629
    StreamTcpUTDeinit(ra_ctx);
1✔
630
    PASS;
1✔
631
}
1✔
632

633
/** \test Send a version banner in three chunks. */
634
static int SSHParserTest10(void)
635
{
1✔
636
    TcpReassemblyThreadCtx *ra_ctx = NULL;
1✔
637
    ThreadVars tv;
1✔
638
    TcpSession ssn;
1✔
639
    Flow *f = NULL;
1✔
640
    Packet *p = NULL;
1✔
641

642
    char sshbufs[3][MAX_SSH_TEST_SIZE] = {"SSH-", "2.", "0-MySSHClient-0.5.1\r\n"};
1✔
643

644
    memset(&tv, 0x00, sizeof(tv));
1✔
645

646
    StreamTcpUTInit(&ra_ctx);
1✔
647
    StreamTcpUTInitInline();
1✔
648
    StreamTcpUTSetupSession(&ssn);
1✔
649
    StreamTcpUTSetupStream(&ssn.server, 1);
1✔
650
    StreamTcpUTSetupStream(&ssn.client, 1);
1✔
651

652
    f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
1✔
653
    FAIL_IF_NULL(f);
1✔
654
    f->protoctx = &ssn;
1✔
655
    f->proto = IPPROTO_TCP;
1✔
656
    f->alproto = ALPROTO_SSH;
1✔
657

658
    p = PacketGetFromAlloc();
1✔
659
    FAIL_IF(unlikely(p == NULL));
1✔
660
    p->proto = IPPROTO_TCP;
1✔
661
    p->flow = f;
1✔
662

663
    uint32_t seq = 2;
1✔
664
    for (int i=0; i<3; i++) {
4✔
665
        FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, (uint8_t *) sshbufs[i], strlen(sshbufs[i])) == -1);
3✔
666
        seq += strlen(sshbufs[i]);
3✔
667
        FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0);
3✔
668
    }
3✔
669

670
    void *ssh_state = f->alstate;
1✔
671
    FAIL_IF_NULL(ssh_state);
1✔
672
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
673
    FAIL_IF(SCSshTxGetAlStateProgress(tx, STREAM_TOCLIENT) != SshStateBannerDone);
1✔
674

675
    FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT));
1✔
676

677
    UTHFreePacket(p);
1✔
678
    UTHFreeFlow(f);
1✔
679
    StreamTcpUTClearSession(&ssn);
1✔
680
    StreamTcpUTDeinit(ra_ctx);
1✔
681
    PASS;
1✔
682
}
1✔
683

684
/** \test Send a banner and record in three chunks. */
685
static int SSHParserTest11(void)
686
{
1✔
687
    int result = 0;
1✔
688
    Flow f;
1✔
689
    uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n";
1✔
690
    uint32_t sshlen1 = sizeof(sshbuf1) - 1;
1✔
691
    uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00};
1✔
692
    uint32_t sshlen2 = sizeof(sshbuf2);
1✔
693
    TcpSession ssn;
1✔
694
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1✔
695

696
    memset(&f, 0, sizeof(f));
1✔
697
    memset(&ssn, 0, sizeof(ssn));
1✔
698
    FLOW_INITIALIZE(&f);
1✔
699
    f.protoctx = (void *)&ssn;
1✔
700
    f.proto = IPPROTO_TCP;
1✔
701
    f.alproto = ALPROTO_SSH;
1✔
702

703
    StreamTcpInitConfig(true);
1✔
704

705
    int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1✔
706
                                STREAM_TOSERVER, sshbuf1, sshlen1);
1✔
707
    if (r != 0) {
1✔
708
        printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
709
        goto end;
710
    }
711
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
1✔
712
                            sshbuf2, sshlen2);
1✔
713
    if (r != 0) {
1✔
714
        printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
715
        goto end;
716
    }
717

718
    void *ssh_state = f.alstate;
1✔
719
    if (ssh_state == NULL) {
1✔
720
        printf("no ssh state: ");
721
        goto end;
722
    }
723
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
724
    if (SCSshTxGetFlags(tx, STREAM_TOSERVER) != SshStateFinished) {
1✔
725
        printf("Didn't detect the msg code of new keys (ciphered data starts): ");
726
        goto end;
727
    }
728
    if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER))
1✔
729
        goto end;
730

731
    result = 1;
1✔
732
end:
1✔
733
    FLOW_DESTROY(&f);
1✔
734
    if (alp_tctx != NULL)
1✔
735
        AppLayerParserThreadCtxFree(alp_tctx);
1✔
736
    StreamTcpFreeConfig(true);
1✔
737
    return result;
1✔
738
}
1✔
739

740
/** \test Send a banner and 2 records record in four chunks. */
741
static int SSHParserTest12(void)
742
{
1✔
743
    int result = 0;
1✔
744
    Flow f;
1✔
745
    uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n";
1✔
746
    uint32_t sshlen1 = sizeof(sshbuf1) - 1;
1✔
747
    uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x03,0x01, 17, 0x00};
1✔
748
    uint32_t sshlen2 = sizeof(sshbuf2);
1✔
749
    uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03,0x01, 21, 0x00};
1✔
750
    uint32_t sshlen3 = sizeof(sshbuf3);
1✔
751
    TcpSession ssn;
1✔
752
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1✔
753

754
    memset(&f, 0, sizeof(f));
1✔
755
    memset(&ssn, 0, sizeof(ssn));
1✔
756
    FLOW_INITIALIZE(&f);
1✔
757
    f.protoctx = (void *)&ssn;
1✔
758
    f.proto = IPPROTO_TCP;
1✔
759
    f.alproto = ALPROTO_SSH;
1✔
760

761
    StreamTcpInitConfig(true);
1✔
762

763
    int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1✔
764
                                STREAM_TOSERVER, sshbuf1, sshlen1);
1✔
765
    if (r != 0) {
1✔
766
        printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
767
        goto end;
768
    }
769
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
1✔
770
                            sshbuf2, sshlen2);
1✔
771
    if (r != 0) {
1✔
772
        printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
773
        goto end;
774
    }
775
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
1✔
776
                            sshbuf3, sshlen3);
1✔
777
    if (r != 0) {
1✔
778
        printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
779
        goto end;
780
    }
781

782
    void *ssh_state = f.alstate;
1✔
783
    if (ssh_state == NULL) {
1✔
784
        printf("no ssh state: ");
785
        goto end;
786
    }
787
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
788
    if (SCSshTxGetFlags(tx, STREAM_TOSERVER) != SshStateFinished) {
1✔
789
        printf("Didn't detect the msg code of new keys (ciphered data starts): ");
790
        goto end;
791
    }
792
    if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER))
1✔
793
        goto end;
794

795
    result = 1;
1✔
796
end:
1✔
797
    FLOW_DESTROY(&f);
1✔
798
    if (alp_tctx != NULL)
1✔
799
        AppLayerParserThreadCtxFree(alp_tctx);
1✔
800
    StreamTcpFreeConfig(true);
1✔
801
    return result;
1✔
802
}
1✔
803

804
/** \test Send a banner and 2 records record in four chunks. */
805
static int SSHParserTest13(void)
806
{
1✔
807
    TcpReassemblyThreadCtx *ra_ctx = NULL;
1✔
808
    ThreadVars tv;
1✔
809
    TcpSession ssn;
1✔
810
    Flow *f = NULL;
1✔
811
    Packet *p = NULL;
1✔
812

813
    uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n";
1✔
814
    uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x02, 0x01, 17};
1✔
815
    uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x02, 0x01, 21};
1✔
816

817
    uint8_t* sshbufs[3] = {sshbuf1, sshbuf2, sshbuf3};
1✔
818
    uint32_t sshlens[3] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2), sizeof(sshbuf3)};
1✔
819

820
    memset(&tv, 0x00, sizeof(tv));
1✔
821

822
    StreamTcpUTInit(&ra_ctx);
1✔
823
    StreamTcpUTInitInline();
1✔
824
    StreamTcpUTSetupSession(&ssn);
1✔
825
    StreamTcpUTSetupStream(&ssn.server, 1);
1✔
826
    StreamTcpUTSetupStream(&ssn.client, 1);
1✔
827

828
    f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
1✔
829
    FAIL_IF_NULL(f);
1✔
830
    f->protoctx = &ssn;
1✔
831
    f->proto = IPPROTO_TCP;
1✔
832
    f->alproto = ALPROTO_SSH;
1✔
833

834
    p = PacketGetFromAlloc();
1✔
835
    FAIL_IF(unlikely(p == NULL));
1✔
836
    p->proto = IPPROTO_TCP;
1✔
837
    p->flow = f;
1✔
838

839
    uint32_t seq = 2;
1✔
840
    for (int i=0; i<3; i++) {
4✔
841
        FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, seq, sshbufs[i], sshlens[i]) == -1);
3✔
842
        seq += sshlens[i];
3✔
843
        FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < 0);
3✔
844
    }
3✔
845

846
    void *ssh_state = f->alstate;
1✔
847
    FAIL_IF_NULL(ssh_state);
1✔
848
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
849
    FAIL_IF(SCSshTxGetFlags(tx, STREAM_TOSERVER) != SshStateFinished);
1✔
850

851
    FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER));
1✔
852

853
    UTHFreePacket(p);
1✔
854
    UTHFreeFlow(f);
1✔
855
    StreamTcpUTClearSession(&ssn);
1✔
856
    StreamTcpUTDeinit(ra_ctx);
1✔
857
    PASS;
1✔
858
}
1✔
859

860
/** \test Send a banner and 2 records record in four chunks. */
861
static int SSHParserTest14(void)
862
{
1✔
863
    TcpReassemblyThreadCtx *ra_ctx = NULL;
1✔
864
    ThreadVars tv;
1✔
865
    TcpSession ssn;
1✔
866
    Flow *f = NULL;
1✔
867
    Packet *p = NULL;
1✔
868

869
    uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n";
1✔
870
    uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x10, 0x01, 17, 0x00};
1✔
871
    uint8_t sshbuf3[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
1✔
872
    uint8_t sshbuf4[] = { 0x09, 0x10, 0x11, 0x12, 0x13, 0x00};
1✔
873
    /* first byte of this record in sshbuf4 */
874
    uint8_t sshbuf5[] = { 0x00, 0x00, 0x02, 0x01, 21};
1✔
875

876
    uint8_t* sshbufs[5] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4, sshbuf5};
1✔
877
    uint32_t sshlens[5] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2), sizeof(sshbuf3), sizeof(sshbuf4), sizeof(sshbuf5)};
1✔
878

879
    memset(&tv, 0x00, sizeof(tv));
1✔
880

881
    StreamTcpUTInit(&ra_ctx);
1✔
882
    StreamTcpUTInitInline();
1✔
883
    StreamTcpUTSetupSession(&ssn);
1✔
884
    StreamTcpUTSetupStream(&ssn.server, 1);
1✔
885
    StreamTcpUTSetupStream(&ssn.client, 1);
1✔
886

887
    f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
1✔
888
    FAIL_IF_NULL(f);
1✔
889
    f->protoctx = &ssn;
1✔
890
    f->proto = IPPROTO_TCP;
1✔
891
    f->alproto = ALPROTO_SSH;
1✔
892

893
    p = PacketGetFromAlloc();
1✔
894
    FAIL_IF(unlikely(p == NULL));
1✔
895
    p->proto = IPPROTO_TCP;
1✔
896
    p->flow = f;
1✔
897

898
    uint32_t seq = 2;
1✔
899
    for (int i=0; i<5; i++) {
6✔
900
        FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, seq, sshbufs[i], sshlens[i]) == -1);
5✔
901
        seq += sshlens[i];
5✔
902
        FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < 0);
5✔
903
    }
5✔
904

905
    void *ssh_state = f->alstate;
1✔
906
    FAIL_IF_NULL(ssh_state);
1✔
907
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
908
    FAIL_IF(SCSshTxGetFlags(tx, STREAM_TOSERVER) != SshStateFinished);
1✔
909

910
    FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER));
1✔
911

912
    UTHFreePacket(p);
1✔
913
    UTHFreeFlow(f);
1✔
914
    StreamTcpUTClearSession(&ssn);
1✔
915
    StreamTcpUTDeinit(ra_ctx);
1✔
916
    PASS;
1✔
917
}
1✔
918

919
/** \test Send a banner and 2 records record in four chunks. */
920
static int SSHParserTest15(void)
921
{
1✔
922
    TcpReassemblyThreadCtx *ra_ctx = NULL;
1✔
923
    ThreadVars tv;
1✔
924
    TcpSession ssn;
1✔
925
    Flow *f = NULL;
1✔
926
    Packet *p = NULL;
1✔
927

928
    uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n";
1✔
929
    uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x10, 0x01, 17, 0x00};
1✔
930
    uint8_t sshbuf3[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
1✔
931
    uint8_t sshbuf4[] = { 0x09, 0x10, 0x11, 0x12, 0x13, 0x00};
1✔
932
    uint8_t sshbuf5[] = { 0x00, 0x00, 0x02, 0x01, 20, 0x00, 0x00, 0x00, 0x02, 0x01, 21};
1✔
933

934
    uint8_t* sshbufs[5] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4, sshbuf5};
1✔
935
    uint32_t sshlens[5] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2), sizeof(sshbuf3), sizeof(sshbuf4), sizeof(sshbuf5)};
1✔
936

937
    memset(&tv, 0x00, sizeof(tv));
1✔
938

939
    StreamTcpUTInit(&ra_ctx);
1✔
940
    StreamTcpUTInitInline();
1✔
941
    StreamTcpUTSetupSession(&ssn);
1✔
942
    StreamTcpUTSetupStream(&ssn.server, 1);
1✔
943
    StreamTcpUTSetupStream(&ssn.client, 1);
1✔
944

945
    f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
1✔
946
    FAIL_IF_NULL(f);
1✔
947
    f->protoctx = &ssn;
1✔
948
    f->proto = IPPROTO_TCP;
1✔
949
    f->alproto = ALPROTO_SSH;
1✔
950

951
    p = PacketGetFromAlloc();
1✔
952
    FAIL_IF(unlikely(p == NULL));
1✔
953
    p->proto = IPPROTO_TCP;
1✔
954
    p->flow = f;
1✔
955

956
    uint32_t seq = 2;
1✔
957
    for (int i=0; i<5; i++) {
6✔
958
        FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, seq, sshbufs[i], sshlens[i]) == -1);
5✔
959
        seq += sshlens[i];
5✔
960
        FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < 0);
5✔
961
    }
5✔
962

963
    void *ssh_state = f->alstate;
1✔
964
    FAIL_IF_NULL(ssh_state);
1✔
965
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
966
    FAIL_IF(SCSshTxGetFlags(tx, STREAM_TOSERVER) != SshStateFinished);
1✔
967

968
    FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER));
1✔
969

970
    UTHFreePacket(p);
1✔
971
    UTHFreeFlow(f);
1✔
972
    StreamTcpUTClearSession(&ssn);
1✔
973
    StreamTcpUTDeinit(ra_ctx);
1✔
974
    PASS;
1✔
975
}
1✔
976

977
/** \test Send toserver a banner and record in three chunks. */
978
static int SSHParserTest16(void)
979
{
1✔
980
    TcpReassemblyThreadCtx *ra_ctx = NULL;
1✔
981
    ThreadVars tv;
1✔
982
    TcpSession ssn;
1✔
983
    Flow *f = NULL;
1✔
984
    Packet *p = NULL;
1✔
985

986
    uint8_t sshbuf1[] = "SSH-";
1✔
987
    uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n";
1✔
988
    uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03,0x01, 21, 0x00};
1✔
989

990
    uint8_t* sshbufs[3] = {sshbuf1, sshbuf2, sshbuf3};
1✔
991
    uint32_t sshlens[3] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3)};
1✔
992

993
    memset(&tv, 0x00, sizeof(tv));
1✔
994

995
    StreamTcpUTInit(&ra_ctx);
1✔
996
    StreamTcpUTInitInline();
1✔
997
    StreamTcpUTSetupSession(&ssn);
1✔
998
    StreamTcpUTSetupStream(&ssn.server, 1);
1✔
999
    StreamTcpUTSetupStream(&ssn.client, 1);
1✔
1000

1001
    f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
1✔
1002
    FAIL_IF_NULL(f);
1✔
1003
    f->protoctx = &ssn;
1✔
1004
    f->proto = IPPROTO_TCP;
1✔
1005
    f->alproto = ALPROTO_SSH;
1✔
1006

1007
    p = PacketGetFromAlloc();
1✔
1008
    FAIL_IF(unlikely(p == NULL));
1✔
1009
    p->proto = IPPROTO_TCP;
1✔
1010
    p->flow = f;
1✔
1011

1012
    uint32_t seq = 2;
1✔
1013
    for (int i=0; i<3; i++) {
4✔
1014
        FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1);
3✔
1015
        seq += sshlens[i];
3✔
1016
        FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0);
3✔
1017
    }
3✔
1018

1019
    void *ssh_state = f->alstate;
1✔
1020
    FAIL_IF_NULL(ssh_state);
1✔
1021
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
1022
    FAIL_IF(SCSshTxGetFlags(tx, STREAM_TOCLIENT) != SshStateFinished);
1✔
1023

1024
    FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT));
1✔
1025

1026
    UTHFreePacket(p);
1✔
1027
    UTHFreeFlow(f);
1✔
1028
    StreamTcpUTClearSession(&ssn);
1✔
1029
    StreamTcpUTDeinit(ra_ctx);
1✔
1030
    PASS;
1✔
1031
}
1✔
1032

1033
/** \test Send toserver a banner and 2 records record in four chunks. */
1034
static int SSHParserTest17(void)
1035
{
1✔
1036
    TcpReassemblyThreadCtx *ra_ctx = NULL;
1✔
1037
    ThreadVars tv;
1✔
1038
    TcpSession ssn;
1✔
1039
    Flow *f = NULL;
1✔
1040
    Packet *p = NULL;
1✔
1041

1042
    uint8_t sshbuf1[] = "SSH-";
1✔
1043
    uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n";
1✔
1044
    uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 17, 0x00};
1✔
1045
    uint8_t sshbuf4[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00};
1✔
1046

1047
    uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4};
1✔
1048
    uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3), sizeof(sshbuf4)};
1✔
1049

1050
    memset(&tv, 0x00, sizeof(tv));
1✔
1051

1052
    StreamTcpUTInit(&ra_ctx);
1✔
1053
    StreamTcpUTInitInline();
1✔
1054
    StreamTcpUTSetupSession(&ssn);
1✔
1055
    StreamTcpUTSetupStream(&ssn.server, 1);
1✔
1056
    StreamTcpUTSetupStream(&ssn.client, 1);
1✔
1057

1058
    f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
1✔
1059
    FAIL_IF_NULL(f);
1✔
1060
    f->protoctx = &ssn;
1✔
1061
    f->proto = IPPROTO_TCP;
1✔
1062
    f->alproto = ALPROTO_SSH;
1✔
1063

1064
    p = PacketGetFromAlloc();
1✔
1065
    FAIL_IF(unlikely(p == NULL));
1✔
1066
    p->proto = IPPROTO_TCP;
1✔
1067
    p->flow = f;
1✔
1068

1069
    uint32_t seq = 2;
1✔
1070
    for (int i=0; i<4; i++) {
5✔
1071
        FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1);
4✔
1072
        seq += sshlens[i];
4✔
1073
        FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0);
4✔
1074
    }
4✔
1075

1076
    void *ssh_state = f->alstate;
1✔
1077
    FAIL_IF_NULL(ssh_state);
1✔
1078
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
1079
    FAIL_IF(SCSshTxGetFlags(tx, STREAM_TOCLIENT) != SshStateFinished);
1✔
1080

1081
    FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT));
1✔
1082

1083
    UTHFreePacket(p);
1✔
1084
    UTHFreeFlow(f);
1✔
1085
    StreamTcpUTClearSession(&ssn);
1✔
1086
    StreamTcpUTDeinit(ra_ctx);
1✔
1087
    PASS;
1✔
1088
}
1✔
1089

1090
/** \test 2 directional test */
1091
static int SSHParserTest18(void)
1092
{
1✔
1093
    TcpReassemblyThreadCtx *ra_ctx = NULL;
1✔
1094
    ThreadVars tv;
1✔
1095
    TcpSession ssn;
1✔
1096
    Flow *f = NULL;
1✔
1097
    Packet *p = NULL;
1✔
1098

1099
    uint8_t server1[] = "SSH-2.0-OpenSSH_4.7p1 Debian-8ubuntu3\r\n";
1✔
1100
    uint8_t sshbuf1[] = "SSH-";
1✔
1101
    uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n";
1✔
1102
    uint8_t server2[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00 };
1✔
1103
    uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00 };
1✔
1104

1105

1106
    memset(&tv, 0x00, sizeof(tv));
1✔
1107

1108
    StreamTcpUTInit(&ra_ctx);
1✔
1109
    StreamTcpUTInitInline();
1✔
1110
    StreamTcpUTSetupSession(&ssn);
1✔
1111
    StreamTcpUTSetupStream(&ssn.server, 1);
1✔
1112
    StreamTcpUTSetupStream(&ssn.client, 1);
1✔
1113

1114
    uint8_t* sshbufs[5] = {server1, sshbuf1, sshbuf2, server2, sshbuf3};
1✔
1115
    uint32_t sshlens[5] = {sizeof(server1) - 1, sizeof(sshbuf1) - 1, sizeof(sshbuf2) -1, sizeof(server2) - 1, sizeof(sshbuf3)};
1✔
1116
    bool sshdirs[5] = {true, false, false, true, false};
1✔
1117

1118
    f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
1✔
1119
    FAIL_IF_NULL(f);
1✔
1120
    f->protoctx = &ssn;
1✔
1121
    f->proto = IPPROTO_TCP;
1✔
1122
    f->alproto = ALPROTO_SSH;
1✔
1123

1124
    p = PacketGetFromAlloc();
1✔
1125
    FAIL_IF(unlikely(p == NULL));
1✔
1126
    p->proto = IPPROTO_TCP;
1✔
1127
    p->flow = f;
1✔
1128

1129
    uint32_t seqcli = 2;
1✔
1130
    uint32_t seqsrv = 2;
1✔
1131
    for (int i=0; i<5; i++) {
6✔
1132
        if (sshdirs[i]) {
5✔
1133
            FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seqsrv, sshbufs[i], sshlens[i]) == -1);
2✔
1134
            seqsrv += sshlens[i];
2✔
1135
            FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn,  &ssn.server, p, UPDATE_DIR_PACKET) < 0);
2✔
1136
        } else {
3✔
1137
            FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx,  &ssn.client, seqcli, sshbufs[i], sshlens[i]) == -1);
3✔
1138
            seqcli += sshlens[i];
3✔
1139
            FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < 0);
3✔
1140
        }
3✔
1141
    }
5✔
1142

1143
    void *ssh_state = f->alstate;
1✔
1144
    FAIL_IF_NULL(ssh_state);
1✔
1145
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
1146
    FAIL_IF(SCSshTxGetFlags(tx, STREAM_TOCLIENT) != SshStateFinished);
1✔
1147

1148
    FAIL_IF(!(SCAppLayerParserStateIssetFlag(f->alparser, APP_LAYER_PARSER_NO_INSPECTION)));
1✔
1149

1150
    UTHFreePacket(p);
1✔
1151
    UTHFreeFlow(f);
1✔
1152
    StreamTcpUTClearSession(&ssn);
1✔
1153
    StreamTcpUTDeinit(ra_ctx);
1✔
1154
    PASS;
1✔
1155
}
1✔
1156

1157
/** \test Really long banner handling: bannel exactly 255 */
1158
static int SSHParserTest19(void)
1159
{
1✔
1160
    TcpReassemblyThreadCtx *ra_ctx = NULL;
1✔
1161
    ThreadVars tv;
1✔
1162
    TcpSession ssn;
1✔
1163
    Flow *f = NULL;
1✔
1164
    Packet *p = NULL;
1✔
1165

1166
    uint8_t sshbuf1[] = "SSH-";
1✔
1167
    uint8_t sshbuf2[] = "2.0-";
1✔
1168
    uint8_t sshbuf3[] = "abcdefghijklmnopqrstuvwxyz"
1✔
1169
                        "abcdefghijklmnopqrstuvwxyz"//60
1✔
1170
                        "abcdefghijklmnopqrstuvwxyz"
1✔
1171
                        "abcdefghijklmnopqrstuvwxyz"//112
1✔
1172
                        "abcdefghijklmnopqrstuvwxyz"
1✔
1173
                        "abcdefghijklmnopqrstuvwxyz"//164
1✔
1174
                        "abcdefghijklmnopqrstuvwxyz"
1✔
1175
                        "abcdefghijklmnopqrstuvwxyz"//216
1✔
1176
                        "abcdefghijklmnopqrstuvwxyz"//242
1✔
1177
                        "abcdefghijkl\r";//255
1✔
1178
    uint8_t sshbuf4[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00};
1✔
1179

1180
    uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4};
1✔
1181
    uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, sizeof(sshbuf4)};
1✔
1182

1183
    memset(&tv, 0x00, sizeof(tv));
1✔
1184

1185
    StreamTcpUTInit(&ra_ctx);
1✔
1186
    StreamTcpUTInitInline();
1✔
1187
    StreamTcpUTSetupSession(&ssn);
1✔
1188
    StreamTcpUTSetupStream(&ssn.server, 1);
1✔
1189
    StreamTcpUTSetupStream(&ssn.client, 1);
1✔
1190

1191
    f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
1✔
1192
    FAIL_IF_NULL(f);
1✔
1193
    f->protoctx = &ssn;
1✔
1194
    f->proto = IPPROTO_TCP;
1✔
1195
    f->alproto = ALPROTO_SSH;
1✔
1196

1197
    p = PacketGetFromAlloc();
1✔
1198
    FAIL_IF(unlikely(p == NULL));
1✔
1199
    p->proto = IPPROTO_TCP;
1✔
1200
    p->flow = f;
1✔
1201

1202
    uint32_t seq = 2;
1✔
1203
    for (int i=0; i<4; i++) {
5✔
1204
        FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1);
4✔
1205
        seq += sshlens[i];
4✔
1206
        FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0);
4✔
1207
    }
4✔
1208

1209
    void *ssh_state = f->alstate;
1✔
1210
    FAIL_IF_NULL(ssh_state);
1✔
1211
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
1212
    FAIL_IF(SCSshTxGetFlags(tx, STREAM_TOCLIENT) != SshStateFinished);
1✔
1213

1214
    sshbuf3[sizeof(sshbuf3) - 2] = 0;
1✔
1215
    FAIL_IF(SSHParserTestUtilCheck("2.0", (char *)sshbuf3, tx, STREAM_TOCLIENT));
1✔
1216

1217
    UTHFreePacket(p);
1✔
1218
    UTHFreeFlow(f);
1✔
1219
    StreamTcpUTClearSession(&ssn);
1✔
1220
    StreamTcpUTDeinit(ra_ctx);
1✔
1221
    PASS;
1✔
1222
}
1✔
1223

1224
/** \test Really long banner handling: banner exactly 255,
1225
 *        followed by malformed record */
1226
static int SSHParserTest20(void)
1227
{
1✔
1228
    TcpReassemblyThreadCtx *ra_ctx = NULL;
1✔
1229
    ThreadVars tv;
1✔
1230
    TcpSession ssn;
1✔
1231
    Flow *f = NULL;
1✔
1232
    Packet *p = NULL;
1✔
1233

1234
    uint8_t sshbuf1[] = "SSH-";
1✔
1235
    uint8_t sshbuf2[] = "2.0-";
1✔
1236
    uint8_t sshbuf3[] = "abcdefghijklmnopqrstuvwxyz"
1✔
1237
                        "abcdefghijklmnopqrstuvwxyz"//60
1✔
1238
                        "abcdefghijklmnopqrstuvwxyz"
1✔
1239
                        "abcdefghijklmnopqrstuvwxyz"//112
1✔
1240
                        "abcdefghijklmnopqrstuvwxyz"
1✔
1241
                        "abcdefghijklmnopqrstuvwxyz"//164
1✔
1242
                        "abcdefghijklmnopqrstuvwxyz"
1✔
1243
                        "abcdefghijklmnopqrstuvwxyz"//216
1✔
1244
                        "abcdefghijklmnopqrstuvwxyz"//242
1✔
1245
                        "abcdefghijklm\r";//256
1✔
1246
    uint8_t sshbuf4[] = {'a','b','c','d','e','f', '\r',
1✔
1247
                         0x00, 0x00, 0x00, 0x06, 0x01, 21, 0x00, 0x00, 0x00};
1✔
1248

1249
    uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4};
1✔
1250
    uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, sizeof(sshbuf4) - 1};
1✔
1251

1252
    memset(&tv, 0x00, sizeof(tv));
1✔
1253

1254
    StreamTcpUTInit(&ra_ctx);
1✔
1255
    StreamTcpUTInitInline();
1✔
1256
    StreamTcpUTSetupSession(&ssn);
1✔
1257
    StreamTcpUTSetupStream(&ssn.server, 1);
1✔
1258
    StreamTcpUTSetupStream(&ssn.client, 1);
1✔
1259

1260
    f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
1✔
1261
    FAIL_IF_NULL(f);
1✔
1262
    f->protoctx = &ssn;
1✔
1263
    f->proto = IPPROTO_TCP;
1✔
1264
    f->alproto = ALPROTO_SSH;
1✔
1265

1266
    p = PacketGetFromAlloc();
1✔
1267
    FAIL_IF(unlikely(p == NULL));
1✔
1268
    p->proto = IPPROTO_TCP;
1✔
1269
    p->flow = f;
1✔
1270

1271
    uint32_t seq = 2;
1✔
1272
    for (int i=0; i<4; i++) {
5✔
1273
        FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1);
4✔
1274
        seq += sshlens[i];
4✔
1275
        FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0);
4✔
1276
    }
4✔
1277

1278
    void *ssh_state = f->alstate;
1✔
1279
    FAIL_IF_NULL(ssh_state);
1✔
1280
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
1281
    FAIL_IF(SCSshTxGetFlags(tx, STREAM_TOCLIENT) != SshStateFinished);
1✔
1282

1283
    FAIL_IF(SSHParserTestUtilCheck("2.0", NULL, tx, STREAM_TOCLIENT));
1✔
1284

1285
    UTHFreePacket(p);
1✔
1286
    UTHFreeFlow(f);
1✔
1287
    StreamTcpUTClearSession(&ssn);
1✔
1288
    StreamTcpUTDeinit(ra_ctx);
1✔
1289
    PASS;
1✔
1290
}
1✔
1291

1292
/** \test Fragmented banner handling: chunk has final part of bannel plus
1293
 *        a record. */
1294
static int SSHParserTest21(void)
1295
{
1✔
1296
    TcpReassemblyThreadCtx *ra_ctx = NULL;
1✔
1297
    ThreadVars tv;
1✔
1298
    TcpSession ssn;
1✔
1299
    Flow *f = NULL;
1✔
1300
    Packet *p = NULL;
1✔
1301

1302
    uint8_t sshbuf1[] = "SSH-";
1✔
1303
    uint8_t sshbuf2[] = "2.0-";
1✔
1304
    uint8_t sshbuf3[] = "abcdefghijklmnopqrstuvwxyz"
1✔
1305
                        "abcdefghijklmnopqrstuvwxyz"//60
1✔
1306
                        "abcdefghijklmnopqrstuvwxyz"
1✔
1307
                        "abcdefghijklmnopqrstuvwxyz"//112
1✔
1308
                        "abcdefghijklmnopqrstuvwxyz"
1✔
1309
                        "abcdefghijklmnopqrstuvwxyz"//164
1✔
1310
                        "abcdefghijklmnopqrstuvwxyz"
1✔
1311
                        "abcdefghijklmnopqrstuvwxyz"//216
1✔
1312
                        "abcdefghijklmnopqrstuvwxy";//241
1✔
1313
    uint8_t sshbuf4[] = {'l','i','b','s','s','h', '\r',
1✔
1314
                         0x00, 0x00, 0x00, 0x06, 0x01, 21, 0x00, 0x00, 0x00};
1✔
1315

1316
    uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4};
1✔
1317
    uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, sizeof(sshbuf4)};
1✔
1318

1319
    memset(&tv, 0x00, sizeof(tv));
1✔
1320

1321
    StreamTcpUTInit(&ra_ctx);
1✔
1322
    StreamTcpUTInitInline();
1✔
1323
    StreamTcpUTSetupSession(&ssn);
1✔
1324
    StreamTcpUTSetupStream(&ssn.server, 1);
1✔
1325
    StreamTcpUTSetupStream(&ssn.client, 1);
1✔
1326

1327
    f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
1✔
1328
    FAIL_IF_NULL(f);
1✔
1329
    f->protoctx = &ssn;
1✔
1330
    f->proto = IPPROTO_TCP;
1✔
1331
    f->alproto = ALPROTO_SSH;
1✔
1332

1333
    p = PacketGetFromAlloc();
1✔
1334
    FAIL_IF(unlikely(p == NULL));
1✔
1335
    p->proto = IPPROTO_TCP;
1✔
1336
    p->flow = f;
1✔
1337

1338
    uint32_t seq = 2;
1✔
1339
    for (int i=0; i<4; i++) {
5✔
1340
        FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1);
4✔
1341
        seq += sshlens[i];
4✔
1342
        FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0);
4✔
1343
    }
4✔
1344

1345
    void *ssh_state = f->alstate;
1✔
1346
    FAIL_IF_NULL(ssh_state);
1✔
1347
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
1348
    FAIL_IF(SCSshTxGetFlags(tx, STREAM_TOCLIENT) != SshStateFinished);
1✔
1349

1350
    FAIL_IF(SSHParserTestUtilCheck("2.0", NULL, tx, STREAM_TOCLIENT));
1✔
1351

1352
    UTHFreePacket(p);
1✔
1353
    UTHFreeFlow(f);
1✔
1354
    StreamTcpUTClearSession(&ssn);
1✔
1355
    StreamTcpUTDeinit(ra_ctx);
1✔
1356
    PASS;
1✔
1357
}
1✔
1358

1359
/** \test Fragmented banner handling: chunk has final part of bannel plus
1360
 *        a record. */
1361
static int SSHParserTest22(void)
1362
{
1✔
1363
    TcpReassemblyThreadCtx *ra_ctx = NULL;
1✔
1364
    ThreadVars tv;
1✔
1365
    TcpSession ssn;
1✔
1366
    Flow *f = NULL;
1✔
1367
    Packet *p = NULL;
1✔
1368

1369
    uint8_t sshbuf1[] = "SSH-";
1✔
1370
    uint8_t sshbuf2[] = "2.0-";
1✔
1371
    uint8_t sshbuf3[] = {
1✔
1372
        'l', 'i', 'b', 's', 's', 'h', '\r', // 7
1✔
1373

1374
        0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 17,
1✔
1375
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, 0x00,
1✔
1376
        0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00,
1✔
1377
        0x00, 0x00, 0x00, // 50
1✔
1378

1379
        0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 17,
1✔
1380
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, 0x00,
1✔
1381
        0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00,
1✔
1382
        0x00, 0x00, 0x00, // 100
1✔
1383

1384
        0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 17,
1✔
1385
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, 0x00,
1✔
1386
        0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00,
1✔
1387
        0x00, 0x00, 0x00, // 150
1✔
1388

1389
        0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 17,
1✔
1390
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, 0x00,
1✔
1391
        0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00,
1✔
1392
        0x00, 0x00, 0x00, // 200
1✔
1393

1394
        0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 17,
1✔
1395
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, 0x00,
1✔
1396
        0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00,
1✔
1397
        0x00, 0x00, 0x00, // 250
1✔
1398

1399
        0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 17,
1✔
1400
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, 0x00,
1✔
1401
        0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 21, 0x00,
1✔
1402
        0x00, 0x00, 0x00, // 300
1✔
1403
    };
1✔
1404

1405
    uint8_t *sshbufs[3] = { sshbuf1, sshbuf2, sshbuf3 };
1✔
1406
    uint32_t sshlens[3] = { sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1 };
1✔
1407

1408
    memset(&tv, 0x00, sizeof(tv));
1✔
1409

1410
    StreamTcpUTInit(&ra_ctx);
1✔
1411
    StreamTcpUTInitInline();
1✔
1412
    StreamTcpUTSetupSession(&ssn);
1✔
1413
    StreamTcpUTSetupStream(&ssn.server, 1);
1✔
1414
    StreamTcpUTSetupStream(&ssn.client, 1);
1✔
1415

1416
    f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
1✔
1417
    FAIL_IF_NULL(f);
1✔
1418
    f->protoctx = &ssn;
1✔
1419
    f->proto = IPPROTO_TCP;
1✔
1420
    f->alproto = ALPROTO_SSH;
1✔
1421

1422
    p = PacketGetFromAlloc();
1✔
1423
    FAIL_IF(unlikely(p == NULL));
1✔
1424
    p->proto = IPPROTO_TCP;
1✔
1425
    p->flow = f;
1✔
1426

1427
    uint32_t seq = 2;
1✔
1428
    for (int i = 0; i < 3; i++) {
4✔
1429
        FAIL_IF(StreamTcpUTAddSegmentWithPayload(
3✔
1430
                        &tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1);
3✔
1431
        seq += sshlens[i];
3✔
1432
        FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) <
3✔
1433
                0);
3✔
1434
    }
3✔
1435

1436
    void *ssh_state = f->alstate;
1✔
1437
    FAIL_IF_NULL(ssh_state);
1✔
1438
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
1439
    FAIL_IF(SCSshTxGetFlags(tx, STREAM_TOCLIENT) != SshStateFinished);
1✔
1440

1441
    FAIL_IF(SSHParserTestUtilCheck("2.0", "libssh", tx, STREAM_TOCLIENT));
1✔
1442

1443
    UTHFreePacket(p);
1✔
1444
    UTHFreeFlow(f);
1✔
1445
    StreamTcpUTClearSession(&ssn);
1✔
1446
    StreamTcpUTDeinit(ra_ctx);
1✔
1447
    PASS;
1✔
1448
}
1✔
1449

1450
/** \test Send a version string in one chunk (client version str). */
1451
static int SSHParserTest23(void)
1452
{
1✔
1453
    int result = 0;
1✔
1454
    Flow f;
1✔
1455
    uint8_t sshbuf[] = "SSH-2.0\r-MySSHClient-0.5.1\n";
1✔
1456
    uint32_t sshlen = sizeof(sshbuf) - 1;
1✔
1457
    TcpSession ssn;
1✔
1458
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1✔
1459

1460
    memset(&f, 0, sizeof(f));
1✔
1461
    memset(&ssn, 0, sizeof(ssn));
1✔
1462
    FLOW_INITIALIZE(&f);
1✔
1463
    f.protoctx = (void *)&ssn;
1✔
1464
    f.proto = IPPROTO_TCP;
1✔
1465
    f.alproto = ALPROTO_SSH;
1✔
1466

1467
    StreamTcpInitConfig(true);
1✔
1468

1469
    int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1✔
1470
                                STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen);
1✔
1471
    if (r == 0) {
1✔
1472
        printf("toclient chunk 1 returned 0 expected non null: ");
1473
        goto end;
1474
    }
1475

1476
    result = 1;
1✔
1477
end:
1✔
1478
    if (alp_tctx != NULL)
1✔
1479
        AppLayerParserThreadCtxFree(alp_tctx);
1✔
1480
    StreamTcpFreeConfig(true);
1✔
1481
    FLOW_DESTROY(&f);
1✔
1482
    return result;
1✔
1483
}
1✔
1484

1485
/** \test Send a version string in one chunk (client version str). */
1486
static int SSHParserTest24(void)
1487
{
1✔
1488
    int result = 0;
1✔
1489
    Flow f;
1✔
1490
    uint8_t sshbuf[] = "SSH-2.0-\rMySSHClient-0.5.1\n";
1✔
1491
    uint32_t sshlen = sizeof(sshbuf) - 1;
1✔
1492
    TcpSession ssn;
1✔
1493
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1✔
1494

1495
    memset(&f, 0, sizeof(f));
1✔
1496
    memset(&ssn, 0, sizeof(ssn));
1✔
1497
    FLOW_INITIALIZE(&f);
1✔
1498
    f.protoctx = (void *)&ssn;
1✔
1499
    f.proto = IPPROTO_TCP;
1✔
1500
    f.alproto = ALPROTO_SSH;
1✔
1501

1502
    StreamTcpInitConfig(true);
1✔
1503

1504
    int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1✔
1505
                                STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen);
1✔
1506
    if (r != 0) {
1✔
1507
        printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r);
1508
        goto end;
1509
    }
1510

1511
    void *ssh_state = f.alstate;
1✔
1512
    if (ssh_state == NULL) {
1✔
1513
        printf("no ssh state: ");
1514
        goto end;
1515
    }
1516
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
1517
    if (SCSshTxGetFlags(tx, STREAM_TOSERVER) != SshStateBannerDone) {
1✔
1518
        printf("Didn't detect the msg code of new keys (ciphered data starts): ");
1519
        goto end;
1520
    }
1521
    if (SSHParserTestUtilCheck("2.0", NULL, tx, STREAM_TOSERVER))
1✔
1522
        goto end;
1523

1524
    result = 1;
1✔
1525
end:
1✔
1526
    FLOW_DESTROY(&f);
1✔
1527
    if (alp_tctx != NULL)
1✔
1528
        AppLayerParserThreadCtxFree(alp_tctx);
1✔
1529
    StreamTcpFreeConfig(true);
1✔
1530
    return result;
1✔
1531
}
1✔
1532

1533
/** \test Send a malformed banner */
1534
static int SSHParserTest25(void)
1535
{
1✔
1536
    Flow f;
1✔
1537
    uint8_t sshbuf[] = "\n";
1✔
1538
    uint32_t sshlen = sizeof(sshbuf) - 1;
1✔
1539
    TcpSession ssn;
1✔
1540
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1✔
1541
    FAIL_IF_NULL(alp_tctx);
1✔
1542

1543
    memset(&f, 0, sizeof(f));
1✔
1544
    memset(&ssn, 0, sizeof(ssn));
1✔
1545
    FLOW_INITIALIZE(&f);
1✔
1546
    f.protoctx = (void *)&ssn;
1✔
1547
    f.proto = IPPROTO_TCP;
1✔
1548
    f.alproto = ALPROTO_SSH;
1✔
1549

1550
    StreamTcpInitConfig(true);
1✔
1551

1552
    int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1✔
1553
                                STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen);
1✔
1554
    FAIL_IF(r != -1);
1✔
1555

1556
    void *ssh_state = f.alstate;
1✔
1557
    FAIL_IF_NULL(ssh_state);
1✔
1558
    void *tx = SCSshStateGetTx(ssh_state, 0);
1✔
1559
    FAIL_IF(SCSshTxGetFlags(tx, STREAM_TOSERVER) == SshStateBannerDone);
1✔
1560
    const uint8_t *dummy = NULL;
1✔
1561
    uint32_t dummy_len = 0;
1✔
1562
    FAIL_IF(SCSshTxGetSoftware(tx, STREAM_TOCLIENT, &dummy, &dummy_len) != 0);
1✔
1563

1564
    FLOW_DESTROY(&f);
1✔
1565
    AppLayerParserThreadCtxFree(alp_tctx);
1✔
1566
    StreamTcpFreeConfig(true);
1✔
1567
    PASS;
1✔
1568
}
1✔
1569

1570
#endif /* UNITTESTS */
1571

1572
void SSHParserRegisterTests(void)
1573
{
1✔
1574
#ifdef UNITTESTS
1✔
1575
    UtRegisterTest("SSHParserTest01 - ToServer", SSHParserTest01);
1✔
1576
    UtRegisterTest("SSHParserTest02 - ToServer", SSHParserTest02);
1✔
1577
    UtRegisterTest("SSHParserTest03 - ToServer", SSHParserTest03);
1✔
1578
    UtRegisterTest("SSHParserTest04 - ToClient", SSHParserTest04);
1✔
1579
    UtRegisterTest("SSHParserTest05 - ToClient", SSHParserTest05);
1✔
1580
    UtRegisterTest("SSHParserTest06 - ToClient", SSHParserTest06);
1✔
1581
    UtRegisterTest("SSHParserTest07 - ToServer 2 chunks", SSHParserTest07);
1✔
1582
    UtRegisterTest("SSHParserTest08 - ToServer 3 chunks", SSHParserTest08);
1✔
1583
    UtRegisterTest("SSHParserTest09 - ToClient 2 chunks", SSHParserTest09);
1✔
1584
    UtRegisterTest("SSHParserTest10 - ToClient 3 chunks", SSHParserTest10);
1✔
1585
    UtRegisterTest("SSHParserTest11 - ToClient 4 chunks", SSHParserTest11);
1✔
1586
    UtRegisterTest("SSHParserTest12 - ToClient 4 chunks", SSHParserTest12);
1✔
1587
    UtRegisterTest("SSHParserTest13 - ToClient 4 chunks", SSHParserTest13);
1✔
1588
    UtRegisterTest("SSHParserTest14 - ToClient 4 chunks", SSHParserTest14);
1✔
1589
    UtRegisterTest("SSHParserTest15", SSHParserTest15);
1✔
1590
    UtRegisterTest("SSHParserTest16", SSHParserTest16);
1✔
1591
    UtRegisterTest("SSHParserTest17", SSHParserTest17);
1✔
1592
    UtRegisterTest("SSHParserTest18", SSHParserTest18);
1✔
1593
    UtRegisterTest("SSHParserTest19", SSHParserTest19);
1✔
1594
    UtRegisterTest("SSHParserTest20", SSHParserTest20);
1✔
1595
    UtRegisterTest("SSHParserTest21", SSHParserTest21);
1✔
1596
    UtRegisterTest("SSHParserTest22", SSHParserTest22);
1✔
1597
    UtRegisterTest("SSHParserTest23", SSHParserTest23);
1✔
1598
    UtRegisterTest("SSHParserTest24", SSHParserTest24);
1✔
1599
    UtRegisterTest("SSHParserTest25", SSHParserTest25);
1✔
1600
#endif /* UNITTESTS */
1✔
1601
}
1✔
1602

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc