Coverage Report

Created: 2025-11-16 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata/src/detect-app-layer-protocol.c
Line
Count
Source
1
/* Copyright (C) 2007-2025 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 Anoop Saldanha <anoopsaldanha@gmail.com>
22
 */
23
24
#include "suricata-common.h"
25
#include "detect-engine.h"
26
#include "detect-engine-build.h"
27
#include "detect-engine-prefilter.h"
28
#include "detect-engine-prefilter-common.h"
29
#include "detect-parse.h"
30
#include "detect-app-layer-protocol.h"
31
#include "app-layer.h"
32
#include "app-layer-parser.h"
33
#include "util-debug.h"
34
#include "util-unittest.h"
35
#include "util-unittest-helper.h"
36
37
#ifdef UNITTESTS
38
static void DetectAppLayerProtocolRegisterTests(void);
39
#endif
40
41
enum {
42
    DETECT_ALPROTO_DIRECTION = 0,
43
    DETECT_ALPROTO_FINAL = 1,
44
    DETECT_ALPROTO_EITHER = 2,
45
    DETECT_ALPROTO_TOSERVER = 3,
46
    DETECT_ALPROTO_TOCLIENT = 4,
47
    DETECT_ALPROTO_ORIG = 5,
48
};
49
50
typedef struct DetectAppLayerProtocolData_ {
51
    AppProto alproto;
52
    uint8_t negated;
53
    uint8_t mode;
54
} DetectAppLayerProtocolData;
55
56
static int DetectAppLayerProtocolPacketMatch(
57
        DetectEngineThreadCtx *det_ctx,
58
        Packet *p, const Signature *s, const SigMatchCtx *ctx)
59
40.7k
{
60
40.7k
    SCEnter();
61
62
40.7k
    bool r = false;
63
40.7k
    const DetectAppLayerProtocolData *data = (const DetectAppLayerProtocolData *)ctx;
64
65
    /* if the sig is PD-only we only match when PD packet flags are set */
66
40.7k
    if (s->type == SIG_TYPE_PDONLY &&
67
39.1k
            (p->flags & (PKT_PROTO_DETECT_TS_DONE | PKT_PROTO_DETECT_TC_DONE)) == 0) {
68
35.7k
        SCLogDebug("packet %"PRIu64": flags not set", p->pcap_cnt);
69
35.7k
        SCReturnInt(0);
70
35.7k
    }
71
72
4.92k
    const Flow *f = p->flow;
73
4.92k
    if (f == NULL) {
74
3
        SCLogDebug("packet %"PRIu64": no flow", p->pcap_cnt);
75
3
        SCReturnInt(0);
76
3
    }
77
78
4.92k
    switch (data->mode) {
79
4.21k
        case DETECT_ALPROTO_DIRECTION:
80
4.21k
            if (data->negated) {
81
3.93k
                if (p->flowflags & FLOW_PKT_TOSERVER) {
82
2.88k
                    if (f->alproto_ts == ALPROTO_UNKNOWN)
83
360
                        SCReturnInt(0);
84
2.52k
                    r = AppProtoEquals(data->alproto, f->alproto_ts);
85
2.52k
                } else {
86
1.04k
                    if (f->alproto_tc == ALPROTO_UNKNOWN)
87
89
                        SCReturnInt(0);
88
955
                    r = AppProtoEquals(data->alproto, f->alproto_tc);
89
955
                }
90
3.93k
            } else {
91
281
                if (p->flowflags & FLOW_PKT_TOSERVER) {
92
167
                    r = AppProtoEquals(data->alproto, f->alproto_ts);
93
167
                } else {
94
114
                    r = AppProtoEquals(data->alproto, f->alproto_tc);
95
114
                }
96
281
            }
97
3.76k
            break;
98
3.76k
        case DETECT_ALPROTO_ORIG:
99
0
            if (data->negated) {
100
0
                if (f->alproto_orig == ALPROTO_UNKNOWN)
101
0
                    SCReturnInt(0);
102
0
                r = AppProtoEquals(data->alproto, f->alproto_orig);
103
0
            } else {
104
0
                r = AppProtoEquals(data->alproto, f->alproto_orig);
105
0
            }
106
0
            break;
107
681
        case DETECT_ALPROTO_FINAL:
108
681
            if (data->negated) {
109
681
                if (f->alproto == ALPROTO_UNKNOWN)
110
0
                    SCReturnInt(0);
111
681
                r = AppProtoEquals(data->alproto, f->alproto);
112
681
            } else {
113
0
                r = AppProtoEquals(data->alproto, f->alproto);
114
0
            }
115
681
            break;
116
681
        case DETECT_ALPROTO_TOSERVER:
117
0
            if (data->negated) {
118
0
                if (f->alproto_ts == ALPROTO_UNKNOWN)
119
0
                    SCReturnInt(0);
120
0
                r = AppProtoEquals(data->alproto, f->alproto_ts);
121
0
            } else {
122
0
                r = AppProtoEquals(data->alproto, f->alproto_ts);
123
0
            }
124
0
            break;
125
0
        case DETECT_ALPROTO_TOCLIENT:
126
0
            if (data->negated) {
127
0
                if (f->alproto_tc == ALPROTO_UNKNOWN)
128
0
                    SCReturnInt(0);
129
0
                r = AppProtoEquals(data->alproto, f->alproto_tc);
130
0
            } else {
131
0
                r = AppProtoEquals(data->alproto, f->alproto_tc);
132
0
            }
133
0
            break;
134
34
        case DETECT_ALPROTO_EITHER:
135
34
            if (data->negated) {
136
34
                if (f->alproto_ts == ALPROTO_UNKNOWN && f->alproto_tc == ALPROTO_UNKNOWN)
137
25
                    SCReturnInt(0);
138
9
                r = AppProtoEquals(data->alproto, f->alproto_tc) ||
139
9
                    AppProtoEquals(data->alproto, f->alproto_ts);
140
9
            } else {
141
0
                r = AppProtoEquals(data->alproto, f->alproto_tc) ||
142
0
                    AppProtoEquals(data->alproto, f->alproto_ts);
143
0
            }
144
9
            break;
145
4.92k
    }
146
4.45k
    r = r ^ data->negated;
147
4.45k
    if (r) {
148
3.41k
        SCReturnInt(1);
149
3.41k
    }
150
4.45k
    SCReturnInt(0);
151
4.45k
}
152
153
185
#define MAX_ALPROTO_NAME 50
154
static DetectAppLayerProtocolData *DetectAppLayerProtocolParse(const char *arg, bool negate)
155
5.93k
{
156
5.93k
    DetectAppLayerProtocolData *data;
157
5.93k
    AppProto alproto = ALPROTO_UNKNOWN;
158
159
5.93k
    char alproto_copy[MAX_ALPROTO_NAME];
160
5.93k
    char *sep = strchr(arg, ',');
161
5.93k
    char *alproto_name;
162
5.93k
    if (sep && sep - arg < MAX_ALPROTO_NAME) {
163
145
        strlcpy(alproto_copy, arg, sep - arg + 1);
164
145
        alproto_name = alproto_copy;
165
5.78k
    } else {
166
5.78k
        alproto_name = (char *)arg;
167
5.78k
    }
168
5.93k
    if (strcmp(alproto_name, "failed") == 0) {
169
33
        alproto = ALPROTO_FAILED;
170
5.89k
    } else if (strcmp(alproto_name, "unknown") == 0) {
171
3
        if (negate) {
172
0
            SCLogError("app-layer-protocol "
173
0
                       "keyword can't use negation with protocol 'unknown'");
174
0
            return NULL;
175
0
        }
176
3
        alproto = ALPROTO_UNKNOWN;
177
5.89k
    } else {
178
5.89k
        alproto = AppLayerGetProtoByName(alproto_name);
179
5.89k
        if (alproto == ALPROTO_UNKNOWN) {
180
372
            SCLogError("app-layer-protocol "
181
372
                       "keyword supplied with unknown protocol \"%s\"",
182
372
                    alproto_name);
183
372
            return NULL;
184
372
        }
185
5.89k
    }
186
5.56k
    uint8_t mode = DETECT_ALPROTO_DIRECTION;
187
5.56k
    if (sep) {
188
142
        if (strcmp(sep + 1, "final") == 0) {
189
92
            mode = DETECT_ALPROTO_FINAL;
190
92
        } else if (strcmp(sep + 1, "original") == 0) {
191
7
            mode = DETECT_ALPROTO_ORIG;
192
43
        } else if (strcmp(sep + 1, "either") == 0) {
193
14
            mode = DETECT_ALPROTO_EITHER;
194
29
        } else if (strcmp(sep + 1, "to_server") == 0) {
195
3
            mode = DETECT_ALPROTO_TOSERVER;
196
26
        } else if (strcmp(sep + 1, "to_client") == 0) {
197
3
            mode = DETECT_ALPROTO_TOCLIENT;
198
23
        } else if (strcmp(sep + 1, "direction") == 0) {
199
3
            mode = DETECT_ALPROTO_DIRECTION;
200
20
        } else {
201
20
            SCLogError("app-layer-protocol "
202
20
                       "keyword supplied with unknown mode \"%s\"",
203
20
                    sep + 1);
204
20
            return NULL;
205
20
        }
206
142
    }
207
208
5.54k
    data = SCMalloc(sizeof(DetectAppLayerProtocolData));
209
5.54k
    if (unlikely(data == NULL))
210
0
        return NULL;
211
5.54k
    data->alproto = alproto;
212
5.54k
    data->negated = negate;
213
5.54k
    data->mode = mode;
214
215
5.54k
    return data;
216
5.54k
}
217
218
static bool HasConflicts(const DetectAppLayerProtocolData *us,
219
                          const DetectAppLayerProtocolData *them)
220
1.27k
{
221
    /* mixing negated and non negated is illegal */
222
1.27k
    if ((them->negated ^ us->negated) && them->mode == us->mode)
223
686
        return true;
224
    /* multiple non-negated is illegal */
225
590
    if (!us->negated && them->mode == us->mode)
226
3
        return true;
227
    /* duplicate option */
228
587
    if (us->alproto == them->alproto && them->mode == us->mode)
229
7
        return true;
230
231
    /* all good */
232
580
    return false;
233
587
}
234
235
static int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx,
236
        Signature *s, const char *arg)
237
6.53k
{
238
6.53k
    DetectAppLayerProtocolData *data = NULL;
239
240
6.53k
    if (s->alproto != ALPROTO_UNKNOWN) {
241
39
        SCLogError("Either we already "
242
39
                   "have the rule match on an app layer protocol set through "
243
39
                   "other keywords that match on this protocol, or have "
244
39
                   "already seen a non-negated app-layer-protocol.");
245
39
        goto error;
246
39
    }
247
248
6.49k
    data = DetectAppLayerProtocolParse(arg, s->init_data->negated);
249
6.49k
    if (data == NULL)
250
468
        goto error;
251
252
6.03k
    SigMatch *tsm = s->init_data->smlists[DETECT_SM_LIST_MATCH];
253
7.81k
    for ( ; tsm != NULL; tsm = tsm->next) {
254
2.51k
        if (tsm->type == DETECT_APP_LAYER_PROTOCOL) {
255
1.34k
            const DetectAppLayerProtocolData *them = (const DetectAppLayerProtocolData *)tsm->ctx;
256
257
1.34k
            if (HasConflicts(data, them)) {
258
735
                SCLogError("can't mix "
259
735
                           "positive app-layer-protocol match with negated "
260
735
                           "match or match for 'failed'.");
261
735
                goto error;
262
735
            }
263
1.34k
        }
264
2.51k
    }
265
266
5.29k
    if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_APP_LAYER_PROTOCOL, (SigMatchCtx *)data,
267
5.29k
                DETECT_SM_LIST_MATCH) == NULL) {
268
0
        goto error;
269
0
    }
270
5.29k
    return 0;
271
272
1.24k
error:
273
1.24k
    if (data != NULL)
274
735
        SCFree(data);
275
1.24k
    return -1;
276
5.29k
}
277
278
static void DetectAppLayerProtocolFree(DetectEngineCtx *de_ctx, void *ptr)
279
4.84k
{
280
4.84k
    SCFree(ptr);
281
4.84k
}
282
283
/** \internal
284
 *  \brief prefilter function for protocol detect matching
285
 */
286
static void
287
PrefilterPacketAppProtoMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
288
135
{
289
135
    const PrefilterPacketHeaderCtx *ctx = pectx;
290
291
135
    if (!PrefilterPacketHeaderExtraMatch(ctx, p)) {
292
0
        SCLogDebug("packet %"PRIu64": extra match failed", p->pcap_cnt);
293
0
        SCReturn;
294
0
    }
295
296
135
    if (p->flow == NULL) {
297
0
        SCLogDebug("packet %"PRIu64": no flow, no alproto", p->pcap_cnt);
298
0
        SCReturn;
299
0
    }
300
301
135
    if ((p->flags & (PKT_PROTO_DETECT_TS_DONE|PKT_PROTO_DETECT_TC_DONE)) == 0) {
302
129
        SCLogDebug("packet %"PRIu64": flags not set", p->pcap_cnt);
303
129
        SCReturn;
304
129
    }
305
306
6
    Flow *f = p->flow;
307
6
    AppProto alproto = ALPROTO_UNKNOWN;
308
6
    bool negated = (bool)ctx->v1.u8[2];
309
6
    switch (ctx->v1.u8[3]) {
310
6
        case DETECT_ALPROTO_DIRECTION:
311
6
            if (p->flowflags & FLOW_PKT_TOSERVER) {
312
4
                alproto = f->alproto_ts;
313
4
            } else {
314
2
                alproto = f->alproto_tc;
315
2
            }
316
6
            break;
317
0
        case DETECT_ALPROTO_ORIG:
318
0
            alproto = f->alproto_orig;
319
0
            break;
320
0
        case DETECT_ALPROTO_FINAL:
321
0
            alproto = f->alproto;
322
0
            break;
323
0
        case DETECT_ALPROTO_TOSERVER:
324
0
            alproto = f->alproto_ts;
325
0
            break;
326
0
        case DETECT_ALPROTO_TOCLIENT:
327
0
            alproto = f->alproto_tc;
328
0
            break;
329
0
        case DETECT_ALPROTO_EITHER:
330
            // check if either protocol toclient or toserver matches
331
            // the one in the signature ctx
332
0
            if (negated) {
333
0
                if (f->alproto_tc != ALPROTO_UNKNOWN &&
334
0
                        !AppProtoEquals(ctx->v1.u16[0], f->alproto_tc)) {
335
0
                    PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
336
0
                } else if (f->alproto_ts != ALPROTO_UNKNOWN &&
337
0
                           !AppProtoEquals(ctx->v1.u16[0], f->alproto_ts)) {
338
0
                    PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
339
0
                }
340
0
            } else {
341
0
                if (AppProtoEquals(ctx->v1.u16[0], f->alproto_tc) ||
342
0
                        AppProtoEquals(ctx->v1.u16[0], f->alproto_ts)) {
343
0
                    PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
344
0
                }
345
0
            }
346
            // We return right away to avoid calling PrefilterAddSids again
347
0
            return;
348
6
    }
349
350
6
    if (negated) {
351
6
        if (alproto != ALPROTO_UNKNOWN) {
352
6
            if (!AppProtoEquals(ctx->v1.u16[0], alproto)) {
353
6
                PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
354
6
            }
355
6
        }
356
6
    } else {
357
0
        if (AppProtoEquals(ctx->v1.u16[0], alproto)) {
358
0
            PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
359
0
        }
360
0
    }
361
6
}
362
363
static void
364
PrefilterPacketAppProtoSet(PrefilterPacketHeaderValue *v, void *smctx)
365
276
{
366
276
    const DetectAppLayerProtocolData *a = smctx;
367
276
    v->u16[0] = a->alproto;
368
276
    v->u8[2] = (uint8_t)a->negated;
369
276
    v->u8[3] = a->mode;
370
276
}
371
372
static bool
373
PrefilterPacketAppProtoCompare(PrefilterPacketHeaderValue v, void *smctx)
374
120
{
375
120
    const DetectAppLayerProtocolData *a = smctx;
376
120
    if (v.u16[0] == a->alproto && v.u8[2] == (uint8_t)a->negated && v.u8[3] == a->mode)
377
112
        return true;
378
8
    return false;
379
120
}
380
381
static int PrefilterSetupAppProto(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
382
211
{
383
211
    return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_APP_LAYER_PROTOCOL, SIG_MASK_REQUIRE_FLOW,
384
211
            PrefilterPacketAppProtoSet, PrefilterPacketAppProtoCompare,
385
211
            PrefilterPacketAppProtoMatch);
386
211
}
387
388
static bool PrefilterAppProtoIsPrefilterable(const Signature *s)
389
0
{
390
0
    if (s->type == SIG_TYPE_PDONLY) {
391
0
        SCLogDebug("prefilter on PD %u", s->id);
392
0
        return true;
393
0
    }
394
0
    return false;
395
0
}
396
397
void DetectAppLayerProtocolRegister(void)
398
39
{
399
39
    sigmatch_table[DETECT_APP_LAYER_PROTOCOL].name = "app-layer-protocol";
400
39
    sigmatch_table[DETECT_APP_LAYER_PROTOCOL].desc = "match on the detected app-layer protocol";
401
39
    sigmatch_table[DETECT_APP_LAYER_PROTOCOL].url = "/rules/app-layer.html#app-layer-protocol";
402
39
    sigmatch_table[DETECT_APP_LAYER_PROTOCOL].Match = DetectAppLayerProtocolPacketMatch;
403
39
    sigmatch_table[DETECT_APP_LAYER_PROTOCOL].Setup = DetectAppLayerProtocolSetup;
404
39
    sigmatch_table[DETECT_APP_LAYER_PROTOCOL].Free = DetectAppLayerProtocolFree;
405
#ifdef UNITTESTS
406
    sigmatch_table[DETECT_APP_LAYER_PROTOCOL].RegisterTests = DetectAppLayerProtocolRegisterTests;
407
#endif
408
39
    sigmatch_table[DETECT_APP_LAYER_PROTOCOL].flags =
409
39
            (SIGMATCH_QUOTES_OPTIONAL | SIGMATCH_HANDLE_NEGATION | SIGMATCH_SUPPORT_FIREWALL);
410
411
39
    sigmatch_table[DETECT_APP_LAYER_PROTOCOL].SetupPrefilter = PrefilterSetupAppProto;
412
39
    sigmatch_table[DETECT_APP_LAYER_PROTOCOL].SupportsPrefilter = PrefilterAppProtoIsPrefilterable;
413
39
}
414
415
/**********************************Unittests***********************************/
416
417
#ifdef UNITTESTS
418
419
static int DetectAppLayerProtocolTest01(void)
420
{
421
    DetectAppLayerProtocolData *data = DetectAppLayerProtocolParse("http", false);
422
    FAIL_IF_NULL(data);
423
    FAIL_IF(data->alproto != ALPROTO_HTTP);
424
    FAIL_IF(data->negated != 0);
425
    DetectAppLayerProtocolFree(NULL, data);
426
    PASS;
427
}
428
429
static int DetectAppLayerProtocolTest02(void)
430
{
431
    DetectAppLayerProtocolData *data = DetectAppLayerProtocolParse("http", true);
432
    FAIL_IF_NULL(data);
433
    FAIL_IF(data->alproto != ALPROTO_HTTP);
434
    FAIL_IF(data->negated == 0);
435
    DetectAppLayerProtocolFree(NULL, data);
436
    PASS;
437
}
438
439
static int DetectAppLayerProtocolTest03(void)
440
{
441
    Signature *s = NULL;
442
    DetectAppLayerProtocolData *data = NULL;
443
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
444
    FAIL_IF_NULL(de_ctx);
445
    de_ctx->flags |= DE_QUIET;
446
447
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
448
            "(app-layer-protocol:http; sid:1;)");
449
    FAIL_IF_NULL(s);
450
451
    FAIL_IF(s->alproto != ALPROTO_UNKNOWN);
452
453
    FAIL_IF_NULL(s->init_data->smlists[DETECT_SM_LIST_MATCH]);
454
    FAIL_IF_NULL(s->init_data->smlists[DETECT_SM_LIST_MATCH]->ctx);
455
456
    data = (DetectAppLayerProtocolData *)s->init_data->smlists[DETECT_SM_LIST_MATCH]->ctx;
457
    FAIL_IF(data->alproto != ALPROTO_HTTP);
458
    FAIL_IF(data->negated);
459
    DetectEngineCtxFree(de_ctx);
460
    PASS;
461
}
462
463
static int DetectAppLayerProtocolTest04(void)
464
{
465
    Signature *s = NULL;
466
    DetectAppLayerProtocolData *data = NULL;
467
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
468
    FAIL_IF_NULL(de_ctx);
469
    de_ctx->flags |= DE_QUIET;
470
471
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
472
            "(app-layer-protocol:!http; sid:1;)");
473
    FAIL_IF_NULL(s);
474
    FAIL_IF(s->alproto != ALPROTO_UNKNOWN);
475
    FAIL_IF(s->flags & SIG_FLAG_APPLAYER);
476
477
    FAIL_IF_NULL(s->init_data->smlists[DETECT_SM_LIST_MATCH]);
478
    FAIL_IF_NULL(s->init_data->smlists[DETECT_SM_LIST_MATCH]->ctx);
479
480
    data = (DetectAppLayerProtocolData *)s->init_data->smlists[DETECT_SM_LIST_MATCH]->ctx;
481
    FAIL_IF_NULL(data);
482
    FAIL_IF(data->alproto != ALPROTO_HTTP);
483
    FAIL_IF(data->negated == 0);
484
485
    DetectEngineCtxFree(de_ctx);
486
    PASS;
487
}
488
489
static int DetectAppLayerProtocolTest05(void)
490
{
491
    Signature *s = NULL;
492
    DetectAppLayerProtocolData *data = NULL;
493
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
494
    FAIL_IF_NULL(de_ctx);
495
    de_ctx->flags |= DE_QUIET;
496
497
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
498
            "(app-layer-protocol:!http; app-layer-protocol:!smtp; sid:1;)");
499
    FAIL_IF_NULL(s);
500
    FAIL_IF(s->alproto != ALPROTO_UNKNOWN);
501
    FAIL_IF(s->flags & SIG_FLAG_APPLAYER);
502
503
    FAIL_IF_NULL(s->init_data->smlists[DETECT_SM_LIST_MATCH]);
504
    FAIL_IF_NULL(s->init_data->smlists[DETECT_SM_LIST_MATCH]->ctx);
505
506
    data = (DetectAppLayerProtocolData *)s->init_data->smlists[DETECT_SM_LIST_MATCH]->ctx;
507
    FAIL_IF_NULL(data);
508
    FAIL_IF(data->alproto != ALPROTO_HTTP);
509
    FAIL_IF(data->negated == 0);
510
511
    data = (DetectAppLayerProtocolData *)s->init_data->smlists[DETECT_SM_LIST_MATCH]->next->ctx;
512
    FAIL_IF_NULL(data);
513
    FAIL_IF(data->alproto != ALPROTO_SMTP);
514
    FAIL_IF(data->negated == 0);
515
516
    DetectEngineCtxFree(de_ctx);
517
    PASS;
518
}
519
520
static int DetectAppLayerProtocolTest06(void)
521
{
522
    Signature *s = NULL;
523
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
524
    FAIL_IF_NULL(de_ctx);
525
    de_ctx->flags |= DE_QUIET;
526
527
    s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any "
528
            "(app-layer-protocol:smtp; sid:1;)");
529
    FAIL_IF_NOT_NULL(s);
530
    DetectEngineCtxFree(de_ctx);
531
    PASS;
532
}
533
534
static int DetectAppLayerProtocolTest07(void)
535
{
536
    Signature *s = NULL;
537
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
538
    FAIL_IF_NULL(de_ctx);
539
    de_ctx->flags |= DE_QUIET;
540
541
    s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any "
542
            "(app-layer-protocol:!smtp; sid:1;)");
543
    FAIL_IF_NOT_NULL(s);
544
    DetectEngineCtxFree(de_ctx);
545
    PASS;
546
}
547
548
static int DetectAppLayerProtocolTest08(void)
549
{
550
    Signature *s = NULL;
551
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
552
    FAIL_IF_NULL(de_ctx);
553
    de_ctx->flags |= DE_QUIET;
554
555
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
556
            "(app-layer-protocol:!smtp; app-layer-protocol:http; sid:1;)");
557
    FAIL_IF_NOT_NULL(s);
558
    DetectEngineCtxFree(de_ctx);
559
    PASS;
560
}
561
562
static int DetectAppLayerProtocolTest09(void)
563
{
564
    Signature *s = NULL;
565
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
566
    FAIL_IF_NULL(de_ctx);
567
    de_ctx->flags |= DE_QUIET;
568
569
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
570
            "(app-layer-protocol:http; app-layer-protocol:!smtp; sid:1;)");
571
    FAIL_IF_NOT_NULL(s);
572
    DetectEngineCtxFree(de_ctx);
573
    PASS;
574
}
575
576
static int DetectAppLayerProtocolTest10(void)
577
{
578
    Signature *s = NULL;
579
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
580
    FAIL_IF_NULL(de_ctx);
581
    de_ctx->flags |= DE_QUIET;
582
583
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
584
            "(app-layer-protocol:smtp; app-layer-protocol:!http; sid:1;)");
585
    FAIL_IF_NOT_NULL(s);
586
    DetectEngineCtxFree(de_ctx);
587
    PASS;
588
}
589
590
static int DetectAppLayerProtocolTest11(void)
591
{
592
    DetectAppLayerProtocolData *data = DetectAppLayerProtocolParse("failed", false);
593
    FAIL_IF_NULL(data);
594
    FAIL_IF(data->alproto != ALPROTO_FAILED);
595
    FAIL_IF(data->negated != 0);
596
    DetectAppLayerProtocolFree(NULL, data);
597
    PASS;
598
}
599
600
static int DetectAppLayerProtocolTest12(void)
601
{
602
    DetectAppLayerProtocolData *data = DetectAppLayerProtocolParse("failed", true);
603
    FAIL_IF_NULL(data);
604
    FAIL_IF(data->alproto != ALPROTO_FAILED);
605
    FAIL_IF(data->negated == 0);
606
    DetectAppLayerProtocolFree(NULL, data);
607
    PASS;
608
}
609
610
static int DetectAppLayerProtocolTest13(void)
611
{
612
    Signature *s = NULL;
613
    DetectAppLayerProtocolData *data = NULL;
614
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
615
    FAIL_IF_NULL(de_ctx);
616
    de_ctx->flags |= DE_QUIET;
617
618
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
619
            "(app-layer-protocol:failed; sid:1;)");
620
    FAIL_IF_NULL(s);
621
622
    FAIL_IF(s->alproto != ALPROTO_UNKNOWN);
623
624
    FAIL_IF_NULL(s->init_data->smlists[DETECT_SM_LIST_MATCH]);
625
    FAIL_IF_NULL(s->init_data->smlists[DETECT_SM_LIST_MATCH]->ctx);
626
627
    data = (DetectAppLayerProtocolData *)s->init_data->smlists[DETECT_SM_LIST_MATCH]->ctx;
628
    FAIL_IF(data->alproto != ALPROTO_FAILED);
629
    FAIL_IF(data->negated);
630
    DetectEngineCtxFree(de_ctx);
631
    PASS;
632
}
633
634
static int DetectAppLayerProtocolTest14(void)
635
{
636
    DetectAppLayerProtocolData *data = NULL;
637
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
638
    FAIL_IF_NULL(de_ctx);
639
    de_ctx->flags |= DE_QUIET;
640
641
    Signature *s1 = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
642
            "(app-layer-protocol:http; flowbits:set,blah; sid:1;)");
643
    FAIL_IF_NULL(s1);
644
    FAIL_IF(s1->alproto != ALPROTO_UNKNOWN);
645
    FAIL_IF_NULL(s1->init_data->smlists[DETECT_SM_LIST_MATCH]);
646
    FAIL_IF_NULL(s1->init_data->smlists[DETECT_SM_LIST_MATCH]->ctx);
647
    data = (DetectAppLayerProtocolData *)s1->init_data->smlists[DETECT_SM_LIST_MATCH]->ctx;
648
    FAIL_IF(data->alproto != ALPROTO_HTTP);
649
    FAIL_IF(data->negated);
650
651
    Signature *s2 = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
652
            "(app-layer-protocol:http; flow:to_client; sid:2;)");
653
    FAIL_IF_NULL(s2);
654
    FAIL_IF(s2->alproto != ALPROTO_UNKNOWN);
655
    FAIL_IF_NULL(s2->init_data->smlists[DETECT_SM_LIST_MATCH]);
656
    FAIL_IF_NULL(s2->init_data->smlists[DETECT_SM_LIST_MATCH]->ctx);
657
    data = (DetectAppLayerProtocolData *)s2->init_data->smlists[DETECT_SM_LIST_MATCH]->ctx;
658
    FAIL_IF(data->alproto != ALPROTO_HTTP);
659
    FAIL_IF(data->negated);
660
661
    /* flow:established and other options not supported for PD-only */
662
    Signature *s3 = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
663
            "(app-layer-protocol:http; flow:to_client,established; sid:3;)");
664
    FAIL_IF_NULL(s3);
665
    FAIL_IF(s3->alproto != ALPROTO_UNKNOWN);
666
    FAIL_IF_NULL(s3->init_data->smlists[DETECT_SM_LIST_MATCH]);
667
    FAIL_IF_NULL(s3->init_data->smlists[DETECT_SM_LIST_MATCH]->ctx);
668
    data = (DetectAppLayerProtocolData *)s3->init_data->smlists[DETECT_SM_LIST_MATCH]->ctx;
669
    FAIL_IF(data->alproto != ALPROTO_HTTP);
670
    FAIL_IF(data->negated);
671
672
    SigGroupBuild(de_ctx);
673
    FAIL_IF_NOT(s1->type == SIG_TYPE_PDONLY);
674
    FAIL_IF_NOT(s2->type == SIG_TYPE_PDONLY);
675
    FAIL_IF(s3->type == SIG_TYPE_PDONLY); // failure now
676
677
    DetectEngineCtxFree(de_ctx);
678
    PASS;
679
}
680
681
682
static void DetectAppLayerProtocolRegisterTests(void)
683
{
684
    UtRegisterTest("DetectAppLayerProtocolTest01",
685
                   DetectAppLayerProtocolTest01);
686
    UtRegisterTest("DetectAppLayerProtocolTest02",
687
                   DetectAppLayerProtocolTest02);
688
    UtRegisterTest("DetectAppLayerProtocolTest03",
689
                   DetectAppLayerProtocolTest03);
690
    UtRegisterTest("DetectAppLayerProtocolTest04",
691
                   DetectAppLayerProtocolTest04);
692
    UtRegisterTest("DetectAppLayerProtocolTest05",
693
                   DetectAppLayerProtocolTest05);
694
    UtRegisterTest("DetectAppLayerProtocolTest06",
695
                   DetectAppLayerProtocolTest06);
696
    UtRegisterTest("DetectAppLayerProtocolTest07",
697
                   DetectAppLayerProtocolTest07);
698
    UtRegisterTest("DetectAppLayerProtocolTest08",
699
                   DetectAppLayerProtocolTest08);
700
    UtRegisterTest("DetectAppLayerProtocolTest09",
701
                   DetectAppLayerProtocolTest09);
702
    UtRegisterTest("DetectAppLayerProtocolTest10",
703
                   DetectAppLayerProtocolTest10);
704
    UtRegisterTest("DetectAppLayerProtocolTest11",
705
                   DetectAppLayerProtocolTest11);
706
    UtRegisterTest("DetectAppLayerProtocolTest12",
707
                   DetectAppLayerProtocolTest12);
708
    UtRegisterTest("DetectAppLayerProtocolTest13",
709
                   DetectAppLayerProtocolTest13);
710
    UtRegisterTest("DetectAppLayerProtocolTest14",
711
                   DetectAppLayerProtocolTest14);
712
}
713
#endif /* UNITTESTS */