Coverage Report

Created: 2025-07-23 07:29

/src/suricata7/src/detect-ssh-proto-version.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2007-2020 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
 *
23
 * Implements the ssh.protoversion keyword
24
 * You can specify a concrete version like ssh.protoversion: 1.66
25
 * or search for protoversion 2 compat (1.99 is considered as 2) like
26
 * ssh.protoversion:2_compat
27
 * or just the beginning of the string like ssh.protoversion:"1."
28
 */
29
30
#include "suricata-common.h"
31
#include "threads.h"
32
#include "decode.h"
33
34
#include "detect.h"
35
#include "detect-parse.h"
36
37
#include "detect-engine.h"
38
#include "detect-engine-mpm.h"
39
#include "detect-engine-state.h"
40
#include "detect-engine-build.h"
41
42
#include "flow.h"
43
#include "flow-var.h"
44
#include "flow-util.h"
45
46
#include "util-debug.h"
47
#include "util-unittest.h"
48
#include "util-unittest-helper.h"
49
50
#include "app-layer.h"
51
#include "app-layer-parser.h"
52
#include "app-layer-ssh.h"
53
#include "detect-ssh-proto-version.h"
54
#include "rust.h"
55
56
#include "stream-tcp.h"
57
58
/**
59
 * \brief Regex for parsing the protoversion string
60
 */
61
73
#define PARSE_REGEX  "^\\s*\"?\\s*([0-9]+([\\.\\-0-9]+)?|2_compat)\\s*\"?\\s*$"
62
63
static DetectParseRegex parse_regex;
64
65
static int DetectSshVersionMatch (DetectEngineThreadCtx *,
66
        Flow *, uint8_t, void *, void *,
67
        const Signature *, const SigMatchCtx *);
68
static int DetectSshVersionSetup (DetectEngineCtx *, Signature *, const char *);
69
#ifdef UNITTESTS
70
static void DetectSshVersionRegisterTests(void);
71
#endif
72
static void DetectSshVersionFree(DetectEngineCtx *, void *);
73
static int g_ssh_banner_list_id = 0;
74
75
/**
76
 * \brief Registration function for keyword: ssh.protoversion
77
 */
78
void DetectSshVersionRegister(void)
79
73
{
80
73
    sigmatch_table[DETECT_AL_SSH_PROTOVERSION].name = "ssh.protoversion";
81
73
    sigmatch_table[DETECT_AL_SSH_PROTOVERSION].desc = "match SSH protocol version";
82
73
    sigmatch_table[DETECT_AL_SSH_PROTOVERSION].url = "/rules/ssh-keywords.html#ssh-protoversion";
83
73
    sigmatch_table[DETECT_AL_SSH_PROTOVERSION].AppLayerTxMatch = DetectSshVersionMatch;
84
73
    sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Setup = DetectSshVersionSetup;
85
73
    sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Free  = DetectSshVersionFree;
86
#ifdef UNITTESTS
87
    sigmatch_table[DETECT_AL_SSH_PROTOVERSION].RegisterTests = DetectSshVersionRegisterTests;
88
#endif
89
73
    sigmatch_table[DETECT_AL_SSH_PROTOVERSION].flags = SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_INFO_DEPRECATED;
90
73
    sigmatch_table[DETECT_AL_SSH_PROTOVERSION].alternative = DETECT_AL_SSH_PROTOCOL;
91
92
73
    DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
93
94
73
    g_ssh_banner_list_id = DetectBufferTypeRegister("ssh_banner");
95
73
}
96
97
/**
98
 * \brief match the specified version on a ssh session
99
 *
100
 * \param t pointer to thread vars
101
 * \param det_ctx pointer to the pattern matcher thread
102
 * \param p pointer to the current packet
103
 * \param m pointer to the sigmatch that we will cast into DetectSshVersionData
104
 *
105
 * \retval 0 no match
106
 * \retval 1 match
107
 */
108
static int DetectSshVersionMatch (DetectEngineThreadCtx *det_ctx,
109
        Flow *f, uint8_t flags, void *state, void *txv,
110
        const Signature *s, const SigMatchCtx *m)
111
0
{
112
0
    SCEnter();
113
114
0
    SCLogDebug("lets see");
115
116
0
    DetectSshVersionData *ssh = (DetectSshVersionData *)m;
117
0
    if (state == NULL) {
118
0
        SCLogDebug("no ssh state, no match");
119
0
        SCReturnInt(0);
120
0
    }
121
122
0
    int ret = 0;
123
0
    const uint8_t *protocol = NULL;
124
0
    uint32_t b_len = 0;
125
126
0
    if (rs_ssh_tx_get_protocol(txv, &protocol, &b_len, flags) != 1)
127
0
        SCReturnInt(0);
128
0
    if (protocol == NULL || b_len == 0)
129
0
        SCReturnInt(0);
130
131
0
    if (ssh->flags & SSH_FLAG_PROTOVERSION_2_COMPAT) {
132
0
        SCLogDebug("looking for ssh protoversion 2 compat");
133
0
        if (protocol[0] == '2') {
134
0
            ret = 1;
135
0
        } else if (b_len >= 4) {
136
0
            if (memcmp(protocol, "1.99", 4) == 0)    {
137
0
                ret = 1;
138
0
            }
139
0
        }
140
0
    } else {
141
0
        SCLogDebug("looking for ssh protoversion %s length %"PRIu16"", ssh->ver, ssh->len);
142
0
        if (b_len == ssh->len) {
143
0
            if (memcmp(protocol, ssh->ver, ssh->len) == 0) {
144
0
                ret = 1;
145
0
            }
146
0
        }
147
0
    }
148
0
    SCReturnInt(ret);
149
0
}
150
151
/**
152
 * \brief This function is used to parse IPV4 ip_id passed via keyword: "id"
153
 *
154
 * \param de_ctx Pointer to the detection engine context
155
 * \param idstr Pointer to the user provided id option
156
 *
157
 * \retval id_d pointer to DetectSshVersionData on success
158
 * \retval NULL on failure
159
 */
160
static DetectSshVersionData *DetectSshVersionParse (DetectEngineCtx *de_ctx, const char *str)
161
4
{
162
4
    DetectSshVersionData *ssh = NULL;
163
4
    int res = 0;
164
4
    size_t pcre2_len;
165
166
4
    pcre2_match_data *match = NULL;
167
4
    int ret = DetectParsePcreExec(&parse_regex, &match, str, 0, 0);
168
4
    if (ret < 1 || ret > 3) {
169
3
        SCLogError("invalid ssh.protoversion option");
170
3
        goto error;
171
3
    }
172
173
1
    if (ret > 1) {
174
1
        const char *str_ptr;
175
1
        res = pcre2_substring_get_bynumber(match, 1, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len);
176
1
        if (res < 0) {
177
0
            SCLogError("pcre2_substring_get_bynumber failed");
178
0
            goto error;
179
0
        }
180
181
        /* We have a correct id option */
182
1
        ssh = SCMalloc(sizeof(DetectSshVersionData));
183
1
        if (unlikely(ssh == NULL)) {
184
0
            pcre2_substring_free((PCRE2_UCHAR *)str_ptr);
185
0
            goto error;
186
0
        }
187
1
        memset(ssh, 0x00, sizeof(DetectSshVersionData));
188
189
        /* If we expect a protocol version 2 or 1.99 (considered 2, we
190
         * will compare it with both strings) */
191
1
        if (strcmp("2_compat", str_ptr) == 0) {
192
0
            ssh->flags |= SSH_FLAG_PROTOVERSION_2_COMPAT;
193
0
            SCLogDebug("will look for ssh protocol version 2 (2, 2.0, 1.99 that's considered as 2");
194
0
            pcre2_substring_free((PCRE2_UCHAR *)str_ptr);
195
0
            return ssh;
196
0
        }
197
198
1
        ssh->ver = (uint8_t *)SCStrdup((char*)str_ptr);
199
1
        if (ssh->ver == NULL) {
200
0
            pcre2_substring_free((PCRE2_UCHAR *)str_ptr);
201
0
            goto error;
202
0
        }
203
1
        ssh->len = (uint16_t)strlen((char *)ssh->ver);
204
1
        pcre2_substring_free((PCRE2_UCHAR *)str_ptr);
205
206
1
        SCLogDebug("will look for ssh %s", ssh->ver);
207
1
    }
208
209
1
    pcre2_match_data_free(match);
210
1
    return ssh;
211
212
3
error:
213
3
    if (match) {
214
3
        pcre2_match_data_free(match);
215
3
    }
216
3
    if (ssh != NULL)
217
0
        DetectSshVersionFree(de_ctx, ssh);
218
3
    return NULL;
219
220
1
}
221
222
/**
223
 * \brief this function is used to add the parsed "id" option
224
 * \brief into the current signature
225
 *
226
 * \param de_ctx pointer to the Detection Engine Context
227
 * \param s pointer to the Current Signature
228
 * \param idstr pointer to the user provided "id" option
229
 *
230
 * \retval 0 on Success
231
 * \retval -1 on Failure
232
 */
233
static int DetectSshVersionSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
234
5
{
235
5
    DetectSshVersionData *ssh = NULL;
236
5
    SigMatch *sm = NULL;
237
238
5
    if (DetectSignatureSetAppProto(s, ALPROTO_SSH) != 0)
239
1
        return -1;
240
241
4
    ssh = DetectSshVersionParse(de_ctx, str);
242
4
    if (ssh == NULL)
243
3
        goto error;
244
245
    /* Okay so far so good, lets get this into a SigMatch
246
     * and put it in the Signature. */
247
1
    sm = SigMatchAlloc();
248
1
    if (sm == NULL)
249
0
        goto error;
250
251
1
    sm->type = DETECT_AL_SSH_PROTOVERSION;
252
1
    sm->ctx = (void *)ssh;
253
254
1
    SigMatchAppendSMToList(s, sm, g_ssh_banner_list_id);
255
1
    return 0;
256
257
3
error:
258
3
    if (ssh != NULL)
259
0
        DetectSshVersionFree(de_ctx, ssh);
260
3
    if (sm != NULL)
261
0
        SCFree(sm);
262
3
    return -1;
263
264
1
}
265
266
/**
267
 * \brief this function will free memory associated with DetectSshVersionData
268
 *
269
 * \param id_d pointer to DetectSshVersionData
270
 */
271
void DetectSshVersionFree(DetectEngineCtx *de_ctx, void *ptr)
272
1
{
273
1
    DetectSshVersionData *sshd = (DetectSshVersionData *)ptr;
274
1
    SCFree(sshd->ver);
275
1
    SCFree(sshd);
276
1
}
277
278
#ifdef UNITTESTS /* UNITTESTS */
279
#include "detect-engine-alert.h"
280
281
/**
282
 * \test DetectSshVersionTestParse01 is a test to make sure that we parse
283
 *       a proto version correctly
284
 */
285
static int DetectSshVersionTestParse01 (void)
286
{
287
    DetectSshVersionData *ssh = NULL;
288
    ssh = DetectSshVersionParse(NULL, "1.0");
289
    FAIL_IF_NULL(ssh);
290
    FAIL_IF_NOT(strncmp((char *)ssh->ver, "1.0", 3) == 0);
291
    DetectSshVersionFree(NULL, ssh);
292
293
    PASS;
294
}
295
296
/**
297
 * \test DetectSshVersionTestParse02 is a test to make sure that we parse
298
 *       the proto version (compatible with proto version 2) correctly
299
 */
300
static int DetectSshVersionTestParse02 (void)
301
{
302
    DetectSshVersionData *ssh = NULL;
303
    ssh = DetectSshVersionParse(NULL, "2_compat");
304
    FAIL_IF_NOT(ssh->flags & SSH_FLAG_PROTOVERSION_2_COMPAT);
305
    DetectSshVersionFree(NULL, ssh);
306
307
    PASS;
308
}
309
310
/**
311
 * \test DetectSshVersionTestParse03 is a test to make sure that we
312
 *       don't return a ssh_data with an invalid value specified
313
 */
314
static int DetectSshVersionTestParse03 (void)
315
{
316
    DetectSshVersionData *ssh = NULL;
317
    ssh = DetectSshVersionParse(NULL, "2_com");
318
    FAIL_IF_NOT_NULL(ssh);
319
    ssh = DetectSshVersionParse(NULL, "");
320
    FAIL_IF_NOT_NULL(ssh);
321
    ssh = DetectSshVersionParse(NULL, ".1");
322
    FAIL_IF_NOT_NULL(ssh);
323
    ssh = DetectSshVersionParse(NULL, "lalala");
324
    FAIL_IF_NOT_NULL(ssh);
325
326
    PASS;
327
}
328
329
330
#include "stream-tcp-reassemble.h"
331
#include "stream-tcp-util.h"
332
333
/** \test Send a get request in three chunks + more data. */
334
static int DetectSshVersionTestDetect01(void)
335
{
336
    TcpReassemblyThreadCtx *ra_ctx = NULL;
337
    ThreadVars tv;
338
    TcpSession ssn;
339
    Flow *f = NULL;
340
    Packet *p = NULL;
341
342
    uint8_t sshbuf1[] = "SSH-1.";
343
    uint8_t sshbuf2[] = "10-PuTTY_2.123" ;
344
    uint8_t sshbuf3[] = "\n";
345
    uint8_t sshbuf4[] = "whatever...";
346
347
    uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4};
348
    uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, sizeof(sshbuf4) - 1};
349
350
    memset(&tv, 0x00, sizeof(tv));
351
352
    StreamTcpUTInit(&ra_ctx);
353
    StreamTcpUTInitInline();
354
    StreamTcpUTSetupSession(&ssn);
355
    StreamTcpUTSetupStream(&ssn.server, 1);
356
    StreamTcpUTSetupStream(&ssn.client, 1);
357
358
    f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
359
    FAIL_IF_NULL(f);
360
    f->protoctx = &ssn;
361
    f->proto = IPPROTO_TCP;
362
    f->alproto = ALPROTO_SSH;
363
364
    p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
365
    FAIL_IF(unlikely(p == NULL));
366
    p->flow = f;
367
368
    Signature *s = NULL;
369
    ThreadVars th_v;
370
    DetectEngineThreadCtx *det_ctx = NULL;
371
372
    memset(&th_v, 0, sizeof(th_v));
373
374
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
375
    FAIL_IF_NULL(de_ctx);
376
377
    de_ctx->flags |= DE_QUIET;
378
379
    s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.protoversion:1.10; sid:1;)");
380
    FAIL_IF_NULL(s);
381
382
    SigGroupBuild(de_ctx);
383
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
384
385
    uint32_t seq = 2;
386
    for (int i=0; i<4; i++) {
387
        FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1);
388
        seq += sshlens[i];
389
        FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0);
390
    }
391
392
    void *ssh_state = f->alstate;
393
    FAIL_IF_NULL(ssh_state);
394
395
    /* do detect */
396
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
397
398
    FAIL_IF(PacketAlertCheck(p, 1));
399
400
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
401
    DetectEngineCtxFree(de_ctx);
402
403
    UTHFreePacket(p);
404
    StreamTcpUTClearSession(&ssn);
405
    StreamTcpUTDeinit(ra_ctx);
406
    UTHFreeFlow(f);
407
    PASS;
408
}
409
410
/** \test Send a get request in three chunks + more data. */
411
static int DetectSshVersionTestDetect02(void)
412
{
413
    TcpReassemblyThreadCtx *ra_ctx = NULL;
414
    ThreadVars tv;
415
    TcpSession ssn;
416
    Flow *f = NULL;
417
    Packet *p = NULL;
418
419
    uint8_t sshbuf1[] = "SSH-1.99-Pu";
420
    uint8_t sshbuf2[] = "TTY_2.123" ;
421
    uint8_t sshbuf3[] = "\n";
422
    uint8_t sshbuf4[] = "whatever...";
423
424
    uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4};
425
    uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, sizeof(sshbuf4) - 1};
426
427
    memset(&tv, 0x00, sizeof(tv));
428
429
    StreamTcpUTInit(&ra_ctx);
430
    StreamTcpUTInitInline();
431
    StreamTcpUTSetupSession(&ssn);
432
    StreamTcpUTSetupStream(&ssn.server, 1);
433
    StreamTcpUTSetupStream(&ssn.client, 1);
434
435
    f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
436
    FAIL_IF_NULL(f);
437
    f->protoctx = &ssn;
438
    f->proto = IPPROTO_TCP;
439
    f->alproto = ALPROTO_SSH;
440
441
    p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
442
    FAIL_IF(unlikely(p == NULL));
443
    p->flow = f;
444
445
    Signature *s = NULL;
446
    ThreadVars th_v;
447
    DetectEngineThreadCtx *det_ctx = NULL;
448
449
    memset(&th_v, 0, sizeof(th_v));
450
451
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
452
    FAIL_IF_NULL(de_ctx);
453
454
    de_ctx->flags |= DE_QUIET;
455
456
    s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.protoversion:2_compat; sid:1;)");
457
    FAIL_IF_NULL(s);
458
459
    SigGroupBuild(de_ctx);
460
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
461
462
    uint32_t seq = 2;
463
    for (int i=0; i<4; i++) {
464
        FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1);
465
        seq += sshlens[i];
466
        FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0);
467
    }
468
469
    void *ssh_state = f->alstate;
470
    FAIL_IF_NULL(ssh_state);
471
472
    /* do detect */
473
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
474
475
    FAIL_IF(PacketAlertCheck(p, 1));
476
477
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
478
    DetectEngineCtxFree(de_ctx);
479
480
    UTHFreePacket(p);
481
    StreamTcpUTClearSession(&ssn);
482
    StreamTcpUTDeinit(ra_ctx);
483
    UTHFreeFlow(f);
484
    PASS;
485
}
486
487
/** \test Send a get request in three chunks + more data. */
488
static int DetectSshVersionTestDetect03(void)
489
{
490
    TcpReassemblyThreadCtx *ra_ctx = NULL;
491
    ThreadVars tv;
492
    TcpSession ssn;
493
    Flow *f = NULL;
494
    Packet *p = NULL;
495
496
    uint8_t sshbuf1[] = "SSH-1.";
497
    uint8_t sshbuf2[] = "7-PuTTY_2.123" ;
498
    uint8_t sshbuf3[] = "\n";
499
    uint8_t sshbuf4[] = "whatever...";
500
501
    uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4};
502
    uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, sizeof(sshbuf4) - 1};
503
504
    memset(&tv, 0x00, sizeof(tv));
505
506
    StreamTcpUTInit(&ra_ctx);
507
    StreamTcpUTInitInline();
508
    StreamTcpUTSetupSession(&ssn);
509
    StreamTcpUTSetupStream(&ssn.server, 1);
510
    StreamTcpUTSetupStream(&ssn.client, 1);
511
512
    f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222);
513
    FAIL_IF_NULL(f);
514
    f->protoctx = &ssn;
515
    f->proto = IPPROTO_TCP;
516
    f->alproto = ALPROTO_SSH;
517
518
    p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
519
    FAIL_IF(unlikely(p == NULL));
520
    p->flow = f;
521
522
    Signature *s = NULL;
523
    ThreadVars th_v;
524
    DetectEngineThreadCtx *det_ctx = NULL;
525
526
    memset(&th_v, 0, sizeof(th_v));
527
528
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
529
    FAIL_IF_NULL(de_ctx);
530
531
    de_ctx->flags |= DE_QUIET;
532
533
    s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.protoversion:2_compat; sid:1;)");
534
    FAIL_IF_NULL(s);
535
536
    SigGroupBuild(de_ctx);
537
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
538
539
    uint32_t seq = 2;
540
    for (int i=0; i<4; i++) {
541
        FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1);
542
        seq += sshlens[i];
543
        FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0);
544
    }
545
546
    void *ssh_state = f->alstate;
547
    FAIL_IF_NULL(ssh_state);
548
549
    /* do detect */
550
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
551
552
    FAIL_IF(PacketAlertCheck(p, 1));
553
554
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
555
    DetectEngineCtxFree(de_ctx);
556
557
    UTHFreePacket(p);
558
    StreamTcpUTClearSession(&ssn);
559
    StreamTcpUTDeinit(ra_ctx);
560
    UTHFreeFlow(f);
561
    PASS;
562
}
563
564
/**
565
 * \brief this function registers unit tests for DetectSshVersion
566
 */
567
static void DetectSshVersionRegisterTests(void)
568
{
569
    UtRegisterTest("DetectSshVersionTestParse01", DetectSshVersionTestParse01);
570
    UtRegisterTest("DetectSshVersionTestParse02", DetectSshVersionTestParse02);
571
    UtRegisterTest("DetectSshVersionTestParse03", DetectSshVersionTestParse03);
572
    UtRegisterTest("DetectSshVersionTestDetect01",
573
                   DetectSshVersionTestDetect01);
574
    UtRegisterTest("DetectSshVersionTestDetect02",
575
                   DetectSshVersionTestDetect02);
576
    UtRegisterTest("DetectSshVersionTestDetect03",
577
                   DetectSshVersionTestDetect03);
578
}
579
#endif /* UNITTESTS */