suricata
app-layer-detect-proto.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2022 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 Victor Julien <victor@inliniac.net>
22 * \author Anoop Saldanha <anoopsaldanha@gmail.com>
23 */
24
25#include "suricata-common.h"
26#include "decode.h"
27#include "threads.h"
28#include "threadvars.h"
29#include "tm-threads.h"
30
31#include "detect.h"
32#include "detect-engine-port.h"
33#include "detect-engine-build.h"
34#include "detect-parse.h"
35#include "detect-engine.h"
36#include "detect-content.h"
37#include "detect-engine-mpm.h"
38#include "detect-engine-state.h"
39
40#include "util-print.h"
41#include "util-pool.h"
42#include "util-unittest.h"
44#include "util-validate.h"
45
46#include "flow.h"
47#include "flow-util.h"
48#include "flow-private.h"
49
50#include "stream-tcp-private.h"
52#include "stream-tcp.h"
53#include "stream.h"
54
55#include "app-layer.h"
56#include "app-layer-protos.h"
57#include "app-layer-parser.h"
60
61#include "conf.h"
62#include "util-memcmp.h"
63#include "util-spm.h"
64#include "util-debug.h"
65
66#include "runmodes.h"
67
70 /* the min length of data that has to be supplied to invoke the parser */
71 uint16_t min_depth;
72 /* the max length of data after which this parser won't be invoked */
73 uint16_t max_depth;
74
75 /* the to_server probing parser function */
77
78 /* the to_client probing parser function */
80
83
85 /* the port no for which probing parser(s) are invoked */
86 uint16_t port;
87 /* wether to use this probing parser port-based */
88 // WebSocket has this set to false as it only works with protocol change
90
91 /* the max depth for all the probing parsers registered for this port */
92 uint16_t dp_max_depth;
93 uint16_t sp_max_depth;
94
97
100
107
119
121 uint16_t pp_max_len;
122 uint16_t min_len;
124
125 /** Mapping between pattern id and signature. As each signature has a
126 * unique pattern with a unique id, we can lookup the signature by
127 * the pattern id. */
130
131 /* \todo we don't need this except at setup time. Get rid of it. */
135
140
141/**
142 * \brief The app layer protocol detection context.
143 */
145 /* Context per ip_proto.
146 * \todo Modify ctx_ipp to hold for only tcp and udp. The rest can be
147 * implemented if needed. Waste of space otherwise. */
149
150 /* Global SPM thread context prototype. */
152
154
155 /* Indicates the protocols that have registered themselves
156 * for protocol detection. This table is independent of the
157 * ipproto. It should be allocated to contain ALPROTO_MAX
158 * protocols. */
159 const char **alproto_names;
161
162 /* Protocol expectations, like ftp-data on tcp.
163 * It should be allocated to contain ALPROTO_MAX
164 * app-layer protocols. For each protocol, an iptype
165 * is referenced (or 0 if there is no expectation). */
169
175
176/**
177 * \brief The app layer protocol detection thread context.
178 */
181 /* The value 2 is for direction(0 - toserver, 1 - toclient). */
184};
185
186/* The global app layer proto detection context. */
187static AppLayerProtoDetectCtx alpd_ctx;
188static AppLayerProtoDetectAliases *alpda_ctx = NULL;
189
190static void AppLayerProtoDetectPEGetIpprotos(AppProto alproto,
191 uint8_t *ipprotos);
192
193/***** Static Internal Calls: Protocol Retrieval *****/
194
195/** \internal
196 * \brief Handle SPM search for Signature
197 * \param buflen full size of the input buffer
198 * \param searchlen pattern matching portion of buffer */
199static AppProto AppLayerProtoDetectPMMatchSignature(const AppLayerProtoDetectPMSignature *s,
200 AppLayerProtoDetectThreadCtx *tctx, Flow *f, uint8_t flags, const uint8_t *buf,
201 uint32_t buflen, uint16_t searchlen, bool *rflow)
202{
203 SCEnter();
204
205 if (s->cd->offset > searchlen) {
206 SCLogDebug("s->co->offset (%"PRIu16") > searchlen (%"PRIu16")",
207 s->cd->offset, searchlen);
209 }
210 if (s->cd->depth > searchlen) {
211 SCLogDebug("s->co->depth (%"PRIu16") > searchlen (%"PRIu16")",
212 s->cd->depth, searchlen);
214 }
215
216 const uint8_t *sbuf = buf + s->cd->offset;
217 uint16_t ssearchlen = s->cd->depth - s->cd->offset;
218 SCLogDebug("s->co->offset (%"PRIu16") s->cd->depth (%"PRIu16")",
219 s->cd->offset, s->cd->depth);
220
221 uint8_t *found = SpmScan(s->cd->spm_ctx, tctx->spm_thread_ctx,
222 sbuf, ssearchlen);
223 if (found == NULL) {
225 }
226
227 uint8_t direction = (flags & (STREAM_TOSERVER | STREAM_TOCLIENT));
228 SCLogDebug("matching, s->direction %s, our dir %s",
229 (s->direction & STREAM_TOSERVER) ? "toserver" : "toclient",
230 (flags & STREAM_TOSERVER) ? "toserver" : "toclient");
231 if (s->PPFunc == NULL) {
232 if (direction == s->direction) {
233 SCLogDebug("direction is correct");
234 } else {
235 SCLogDebug("direction is wrong, rflow = true");
236 *rflow = true;
237 }
238 /* validate using Probing Parser */
239 } else {
240 if (s->pp_min_depth > buflen) {
241 SCLogDebug("PP can't be run yet as pp_min_depth %u > buflen %u",
242 s->pp_min_depth, buflen);
244 }
245
246 uint8_t rdir = 0;
247 AppProto r = s->PPFunc(f, flags, buf, buflen, &rdir);
248 if (r == s->alproto) {
249 SCLogDebug("found %s/%u, rdir %02x reverse_flow? %s",
250 AppProtoToString(r), r, rdir,
251 (rdir && direction != rdir) ? "true" : "false");
252 *rflow = (rdir && direction != rdir);
254 } else if (r == ALPROTO_FAILED) {
256 } else {
257 /* unknown: lets see if we will try again later */
258 if (s->pp_max_depth < buflen) {
259 SCLogDebug("depth reached and answer inconclusive: fail");
261 }
263 }
264 }
266}
267
268/**
269 * \retval 0 no matches
270 * \retval -1 no matches, mpm depth reached
271 */
272static inline int PMGetProtoInspect(AppLayerProtoDetectThreadCtx *tctx,
273 AppLayerProtoDetectPMCtx *pm_ctx, MpmThreadCtx *mpm_tctx, Flow *f, const uint8_t *buf,
274 uint32_t buflen, uint8_t flags, AppProto *pm_results, bool *rflow)
275{
276 int pm_matches = 0;
277
278 // maxdepth is u16, so minimum is u16
279 uint16_t searchlen = (uint16_t)MIN(buflen, pm_ctx->mpm_ctx.maxdepth);
280 SCLogDebug("searchlen %u buflen %u", searchlen, buflen);
281
282 /* do the mpm search */
283 uint32_t search_cnt = mpm_table[pm_ctx->mpm_ctx.mpm_type].Search(
284 &pm_ctx->mpm_ctx, mpm_tctx, &tctx->pmq,
285 buf, searchlen);
286 if (search_cnt == 0) {
287 if (buflen >= pm_ctx->mpm_ctx.maxdepth)
288 return -1;
289 return 0;
290 }
291
292 /* alproto bit field */
293 uint8_t pm_results_bf[(g_alproto_max / 8) + 1];
294 memset(pm_results_bf, 0, sizeof(pm_results_bf));
295
296 /* loop through unique pattern id's. Can't use search_cnt here,
297 * as that contains all matches, tctx->pmq.pattern_id_array_cnt
298 * contains only *unique* matches. */
299 for (uint32_t cnt = 0; cnt < tctx->pmq.rule_id_array_cnt; cnt++) {
300 const AppLayerProtoDetectPMSignature *s = pm_ctx->map[tctx->pmq.rule_id_array[cnt]];
301 while (s != NULL) {
302 AppProto proto = AppLayerProtoDetectPMMatchSignature(
303 s, tctx, f, flags, buf, buflen, searchlen, rflow);
304
305 /* store each unique proto once */
306 if (AppProtoIsValid(proto) &&
307 !(pm_results_bf[proto / 8] & (1 << (proto % 8))) )
308 {
309 pm_results[pm_matches++] = proto;
310 pm_results_bf[proto / 8] |= 1 << (proto % 8);
311 }
312 s = s->next;
313 }
314 }
315 if (pm_matches == 0 && buflen >= pm_ctx->pp_max_len) {
316 pm_matches = -2;
317 }
318 PmqReset(&tctx->pmq);
319 return pm_matches;
320}
321
322/** \internal
323 * \brief Run Pattern Sigs against buffer
324 * \param direction direction for the patterns
325 * \param pm_results[out] AppProto array of size g_alproto_max */
326static AppProto AppLayerProtoDetectPMGetProto(AppLayerProtoDetectThreadCtx *tctx, Flow *f,
327 const uint8_t *buf, uint32_t buflen, uint8_t flags, AppProto *pm_results, bool *rflow)
328{
329 SCEnter();
330
331 pm_results[0] = ALPROTO_UNKNOWN;
332
334 MpmThreadCtx *mpm_tctx;
335 int m = -1;
336
337 if (f->protomap >= FLOW_PROTO_DEFAULT) {
338 pm_results[0] = ALPROTO_FAILED;
339 SCReturnUInt(1);
340 }
341
342 if (flags & STREAM_TOSERVER) {
343 pm_ctx = &alpd_ctx.ctx_ipp[f->protomap].ctx_pm[0];
344 mpm_tctx = &tctx->mpm_tctx[f->protomap][0];
345 } else {
346 pm_ctx = &alpd_ctx.ctx_ipp[f->protomap].ctx_pm[1];
347 mpm_tctx = &tctx->mpm_tctx[f->protomap][1];
348 }
349 if (likely(pm_ctx->mpm_ctx.pattern_cnt > 0)) {
350 m = PMGetProtoInspect(tctx, pm_ctx, mpm_tctx, f, buf, buflen, flags, pm_results, rflow);
351 }
352 /* pattern found, yay */
353 if (m > 0) {
355 SCReturnUInt((uint16_t)m);
356
357 /* handle non-found in non-midstream case */
358 } else if (!stream_config.midstream) {
359 /* we can give up if mpm gave no results and its search depth
360 * was reached. */
361 if (m < 0) {
363 SCReturnUInt(0);
364 } else if (m == 0) {
365 SCReturnUInt(0);
366 }
367 SCReturnUInt((uint16_t)m);
368
369 /* handle non-found in midstream case */
370 } else if (m <= 0) {
371 if (flags & STREAM_TOSERVER) {
372 pm_ctx = &alpd_ctx.ctx_ipp[f->protomap].ctx_pm[1];
373 mpm_tctx = &tctx->mpm_tctx[f->protomap][1];
374 } else {
375 pm_ctx = &alpd_ctx.ctx_ipp[f->protomap].ctx_pm[0];
376 mpm_tctx = &tctx->mpm_tctx[f->protomap][0];
377 }
378 SCLogDebug("no matches and in midstream mode, lets try the "
379 "*patterns for the other side");
380
381 int om = -1;
382 if (likely(pm_ctx->mpm_ctx.pattern_cnt > 0)) {
383 om = PMGetProtoInspect(
384 tctx, pm_ctx, mpm_tctx, f, buf, buflen, flags, pm_results, rflow);
385 }
386 /* found! */
387 if (om > 0) {
389 SCReturnUInt((uint16_t)om);
390
391 /* both sides failed */
392 } else if (om < 0 && m && m < 0) {
394 SCReturnUInt(0);
395
396 /* one side still uncertain */
397 } else if (om == 0 || m == 0) {
398 SCReturnUInt(0);
399 }
400 }
401 SCReturnUInt(0);
402}
403
404static AppLayerProtoDetectProbingParserElement *AppLayerProtoDetectGetProbingParser(
405 AppLayerProtoDetectProbingParser *pp, uint8_t ipproto, AppProto alproto)
406{
409
410 while (pp != NULL) {
411 if (pp->ipproto == ipproto)
412 break;
413 pp = pp->next;
414 }
415 if (pp == NULL)
416 return NULL;
417
418 pp_port = pp->port;
419 while (pp_port != NULL) {
420 if (pp_port->dp != NULL && pp_port->dp->alproto == alproto) {
421 pp_elem = pp_port->dp;
422 break;
423 }
424 if (pp_port->sp != NULL && pp_port->sp->alproto == alproto) {
425 pp_elem = pp_port->sp;
426 break;
427 }
428 pp_port = pp_port->next;
429 }
430
431 SCReturnPtr(pp_elem, "AppLayerProtoDetectProbingParserElement *");
432}
433
434static AppLayerProtoDetectProbingParserPort *AppLayerProtoDetectGetProbingParsers(AppLayerProtoDetectProbingParser *pp,
435 uint8_t ipproto,
436 uint16_t port)
437{
439
440 while (pp != NULL) {
441 if (pp->ipproto == ipproto)
442 break;
443
444 pp = pp->next;
445 }
446
447 if (pp == NULL)
448 goto end;
449
450 pp_port = pp->port;
451 while (pp_port != NULL) {
452 // always check use_ports
453 if ((pp_port->port == port || pp_port->port == 0) && pp_port->use_ports) {
454 break;
455 }
456 pp_port = pp_port->next;
457 }
458
459 end:
460 SCReturnPtr(pp_port, "AppLayerProtoDetectProbingParserPort *");
461}
462
463
464/**
465 * \brief Call the probing expectation to see if there is some for this flow.
466 *
467 */
468static AppProto AppLayerProtoDetectPEGetProto(Flow *f, uint8_t flags)
469{
470 AppProto alproto = ALPROTO_UNKNOWN;
471
472 SCLogDebug("expectation check for %p (dir %d)", f, flags);
474
475 alproto = AppLayerExpectationHandle(f, flags);
476
477 return alproto;
478}
479
480static inline AppProto PPGetProto(const AppLayerProtoDetectProbingParserElement *pe, Flow *f,
481 uint8_t flags, const uint8_t *buf, uint32_t buflen, uint32_t *alproto_masks, uint8_t *rdir,
482 uint8_t *nb_tried)
483{
484 while (pe != NULL) {
485 // callers make alproto_masks and nb_tried are either both defined or both NULL
486 if (alproto_masks != NULL) {
487 DEBUG_VALIDATE_BUG_ON(*nb_tried >= 32);
488 if (buflen < pe->min_depth || (alproto_masks[0] & BIT_U32(*nb_tried))) {
489 // skip if already failed once
490 pe = pe->next;
491 *nb_tried = *nb_tried + 1;
492 continue;
493 }
494 } else if (buflen < pe->min_depth) {
495 pe = pe->next;
496 continue;
497 }
498
499 AppProto alproto = ALPROTO_UNKNOWN;
500 if (flags & STREAM_TOSERVER && pe->ProbingParserTs != NULL) {
501 alproto = pe->ProbingParserTs(f, flags, buf, buflen, rdir);
502 } else if (flags & STREAM_TOCLIENT && pe->ProbingParserTc != NULL) {
503 alproto = pe->ProbingParserTc(f, flags, buf, buflen, rdir);
504 }
505 if (AppProtoIsValid(alproto)) {
506 SCReturnUInt(alproto);
507 }
508 if (alproto_masks != NULL) {
509 if ((alproto == ALPROTO_FAILED || (pe->max_depth != 0 && buflen > pe->max_depth))) {
510 // This PE failed, mask it from now on
511 alproto_masks[0] |= BIT_U32(*nb_tried);
512 }
513 *nb_tried = *nb_tried + 1;
514 }
515 pe = pe->next;
516 }
517
519}
520
521/**
522 * \brief Call the probing parser if it exists for this flow.
523 *
524 * First we check the flow's dp as it's most likely to match. If that didn't
525 * lead to a PP, we try the sp.
526 *
527 */
528static AppProto AppLayerProtoDetectPPGetProto(Flow *f, const uint8_t *buf, uint32_t buflen,
529 uint8_t ipproto, const uint8_t flags, bool *reverse_flow)
530{
531 const AppLayerProtoDetectProbingParserPort *pp_port_dp = NULL;
532 const AppLayerProtoDetectProbingParserPort *pp_port_sp = NULL;
536 AppProto alproto = ALPROTO_UNKNOWN;
537 // number of tried protocols :
538 // used against alproto_masks to see if al tried protocols failed
539 // Instead of keeping a bitmask for all protocols, we
540 // use only the protocols relevant to this flow, so as to
541 // have alproto_masks a u32 but we have more than 32 alprotos
542 // in Suricata, but we do not allow more than 32 probing parsers
543 // on one flow.
544 // alproto_masks is consistent throughout different calls here
545 // from different packets in the flow.
546 // We can have up to 4 calls to PPGetProto with a mask :
547 // destination port (probing parser), source port,
548 // and again with the reversed flow in case of midstream.
549 uint8_t nb_tried = 0;
550 uint32_t *alproto_masks = NULL;
551 uint8_t idir = (flags & (STREAM_TOSERVER | STREAM_TOCLIENT));
552 uint8_t dir = idir;
553 uint16_t dp = f->protodetect_dp ? f->protodetect_dp : FLOW_GET_DP(f);
554 uint16_t sp = FLOW_GET_SP(f);
555 bool probe_is_found = false;
556
557again_midstream:
558 if (idir != dir) {
559 SWAP_VARS(uint16_t, dp, sp); /* look up parsers in rev dir */
560 }
561 SCLogDebug("%u->%u %s", sp, dp,
562 (dir == STREAM_TOSERVER) ? "toserver" : "toclient");
563
564 if (dir == STREAM_TOSERVER) {
565 /* first try the destination port */
566 pp_port_dp = AppLayerProtoDetectGetProbingParsers(alpd_ctx.ctx_pp, ipproto, dp);
567 alproto_masks = &f->probing_parser_toserver_alproto_masks;
568 if (pp_port_dp != NULL) {
569 SCLogDebug("toserver - Probing parser found for destination port %"PRIu16, dp);
570
571 /* found based on destination port, so use dp registration */
572 pe1 = pp_port_dp->dp;
573 } else {
574 SCLogDebug("toserver - No probing parser registered for dest port %"PRIu16, dp);
575 }
576
577 pp_port_sp = AppLayerProtoDetectGetProbingParsers(alpd_ctx.ctx_pp, ipproto, sp);
578 if (pp_port_sp != NULL) {
579 SCLogDebug("toserver - Probing parser found for source port %"PRIu16, sp);
580
581 /* found based on source port, so use sp registration */
582 pe2 = pp_port_sp->sp;
583 } else {
584 SCLogDebug("toserver - No probing parser registered for source port %"PRIu16, sp);
585 }
586 } else {
587 /* first try the destination port */
588 pp_port_dp = AppLayerProtoDetectGetProbingParsers(alpd_ctx.ctx_pp, ipproto, dp);
589 if (dir == idir) {
590 // do not update alproto_masks to let a chance to second packet
591 // for instance when sending a junk packet to a DNS server
592 alproto_masks = &f->probing_parser_toclient_alproto_masks;
593 }
594 if (pp_port_dp != NULL) {
595 SCLogDebug("toclient - Probing parser found for destination port %"PRIu16, dp);
596
597 /* found based on destination port, so use dp registration */
598 pe1 = pp_port_dp->dp;
599 } else {
600 SCLogDebug("toclient - No probing parser registered for dest port %"PRIu16, dp);
601 }
602
603 pp_port_sp = AppLayerProtoDetectGetProbingParsers(alpd_ctx.ctx_pp, ipproto, sp);
604 if (pp_port_sp != NULL) {
605 SCLogDebug("toclient - Probing parser found for source port %"PRIu16, sp);
606
607 pe2 = pp_port_sp->sp;
608 } else {
609 SCLogDebug("toclient - No probing parser registered for source port %"PRIu16, sp);
610 }
611 }
612
614 // needed for websocket which does not use ports
615 pe0 = AppLayerProtoDetectGetProbingParser(alpd_ctx.ctx_pp, ipproto, f->alproto_expect);
616 } else if (dir == STREAM_TOSERVER && f->alproto_tc != ALPROTO_UNKNOWN) {
617 pe0 = AppLayerProtoDetectGetProbingParser(alpd_ctx.ctx_pp, ipproto, f->alproto_tc);
618 } else if (dir == STREAM_TOCLIENT && f->alproto_ts != ALPROTO_UNKNOWN) {
619 pe0 = AppLayerProtoDetectGetProbingParser(alpd_ctx.ctx_pp, ipproto, f->alproto_ts);
620 }
621
622 if (pe1 == NULL && pe2 == NULL && pe0 == NULL) {
623 SCLogDebug("%s - No probing parsers found for either port",
624 (dir == STREAM_TOSERVER) ? "toserver":"toclient");
625 goto noparsers;
626 } else {
627 probe_is_found = true;
628 }
629
630 /* run the parser(s): always call with original direction */
631 uint8_t rdir = 0;
632 // pe0 can change based on the flow state, do not use mask for it
633 alproto = PPGetProto(pe0, f, flags, buf, buflen, NULL, &rdir, NULL);
634 if (AppProtoIsValid(alproto))
635 goto end;
636 alproto = PPGetProto(pe1, f, flags, buf, buflen, alproto_masks, &rdir, &nb_tried);
637 if (AppProtoIsValid(alproto))
638 goto end;
639 alproto = PPGetProto(pe2, f, flags, buf, buflen, alproto_masks, &rdir, &nb_tried);
640 if (AppProtoIsValid(alproto))
641 goto end;
642
643 /* get the mask we need for this direction */
644 if (dir == idir) {
645 // if we tried 3 protocols, we set probing parsing done if
646 // alproto_masks[0] = 7 = 0b111 = BIT_U32(3) - 1 = 1<<3 - 1
647 if (alproto_masks[0] == BIT_U32(nb_tried) - 1) {
648 FLOW_SET_PP_DONE(f, dir);
649 SCLogDebug("%s, mask is now %08x, needed %08x, so done",
650 (dir == STREAM_TOSERVER) ? "toserver" : "toclient", alproto_masks[0],
651 BIT_U32(nb_tried) - 1);
652 } else {
653 SCLogDebug("%s, mask is now %08x, need %08x",
654 (dir == STREAM_TOSERVER) ? "toserver" : "toclient", alproto_masks[0],
655 BIT_U32(nb_tried) - 1);
656 }
657 }
658
659noparsers:
660 if (stream_config.midstream && idir == dir) {
661 if (idir == STREAM_TOSERVER) {
662 dir = STREAM_TOCLIENT;
663 } else {
664 dir = STREAM_TOSERVER;
665 }
666 SCLogDebug("no match + midstream, retry the other direction %s",
667 (dir == STREAM_TOSERVER) ? "toserver" : "toclient");
668 goto again_midstream;
669 } else if (!probe_is_found) {
670 FLOW_SET_PP_DONE(f, idir);
671 }
672
673 end:
674 if (AppProtoIsValid(alproto) && rdir != 0 && rdir != idir) {
675 SCLogDebug("PP found %u, is reverse flow", alproto);
676 *reverse_flow = true;
677 }
678
679 SCLogDebug("%s, mask is now %08x",
680 (idir == STREAM_TOSERVER) ? "toserver":"toclient", alproto_masks[0]);
681 SCReturnUInt(alproto);
682}
683
684/***** Static Internal Calls: PP registration *****/
685
686static void AppLayerProtoDetectPPGetIpprotos(AppProto alproto,
687 uint8_t *ipprotos)
688{
689 SCEnter();
690
694
695 for (pp = alpd_ctx.ctx_pp; pp != NULL; pp = pp->next) {
696 for (pp_port = pp->port; pp_port != NULL; pp_port = pp_port->next) {
697 for (pp_pe = pp_port->dp; pp_pe != NULL; pp_pe = pp_pe->next) {
698 if (alproto == pp_pe->alproto)
699 ipprotos[pp->ipproto / 8] |= 1 << (pp->ipproto % 8);
700 }
701 for (pp_pe = pp_port->sp; pp_pe != NULL; pp_pe = pp_pe->next) {
702 if (alproto == pp_pe->alproto)
703 ipprotos[pp->ipproto / 8] |= 1 << (pp->ipproto % 8);
704 }
705 }
706 }
707
708 SCReturn;
709}
710
711static AppLayerProtoDetectProbingParserElement *AppLayerProtoDetectProbingParserElementAlloc(void)
712{
713 SCEnter();
714
717 if (unlikely(p == NULL)) {
718 exit(EXIT_FAILURE);
719 }
720
721 SCReturnPtr(p, "AppLayerProtoDetectProbingParserElement");
722}
723
724
725static void AppLayerProtoDetectProbingParserElementFree(AppLayerProtoDetectProbingParserElement *p)
726{
727 SCEnter();
728 SCFree(p);
729 SCReturn;
730}
731
732static AppLayerProtoDetectProbingParserPort *AppLayerProtoDetectProbingParserPortAlloc(void)
733{
734 SCEnter();
735
738 if (unlikely(p == NULL)) {
739 exit(EXIT_FAILURE);
740 }
741
742 SCReturnPtr(p, "AppLayerProtoDetectProbingParserPort");
743}
744
745static void AppLayerProtoDetectProbingParserPortFree(AppLayerProtoDetectProbingParserPort *p)
746{
747 SCEnter();
748
750
751 e = p->dp;
752 while (e != NULL) {
754 AppLayerProtoDetectProbingParserElementFree(e);
755 e = e_next;
756 }
757
758 e = p->sp;
759 while (e != NULL) {
761 AppLayerProtoDetectProbingParserElementFree(e);
762 e = e_next;
763 }
764
765 SCFree(p);
766
767 SCReturn;
768}
769
770static AppLayerProtoDetectProbingParser *AppLayerProtoDetectProbingParserAlloc(void)
771{
772 SCEnter();
773
775 if (unlikely(p == NULL)) {
776 exit(EXIT_FAILURE);
777 }
778
779 SCReturnPtr(p, "AppLayerProtoDetectProbingParser");
780}
781
782static void AppLayerProtoDetectProbingParserFree(AppLayerProtoDetectProbingParser *p)
783{
784 SCEnter();
785
787 while (pt != NULL) {
789 AppLayerProtoDetectProbingParserPortFree(pt);
790 pt = pt_next;
791 }
792
793 SCFree(p);
794
795 SCReturn;
796}
797
798static AppLayerProtoDetectProbingParserElement *AppLayerProtoDetectProbingParserElementCreate(
799 AppProto alproto, uint16_t min_depth, uint16_t max_depth)
800{
801 AppLayerProtoDetectProbingParserElement *pe = AppLayerProtoDetectProbingParserElementAlloc();
802
803 pe->alproto = alproto;
804 pe->min_depth = min_depth;
805 pe->max_depth = max_depth;
806 pe->next = NULL;
807
808 if (max_depth != 0 && min_depth >= max_depth) {
809 SCLogError("Invalid arguments sent to "
810 "register the probing parser. min_depth >= max_depth");
811 goto error;
812 }
813 if (alproto <= ALPROTO_UNKNOWN || alproto >= g_alproto_max) {
814 SCLogError("Invalid arguments sent to register "
815 "the probing parser. Invalid alproto - %d",
816 alproto);
817 goto error;
818 }
819
820 SCReturnPtr(pe, "AppLayerProtoDetectProbingParserElement");
821 error:
822 AppLayerProtoDetectProbingParserElementFree(pe);
823 SCReturnPtr(NULL, "AppLayerProtoDetectProbingParserElement");
824}
825
827AppLayerProtoDetectProbingParserElementDuplicate(AppLayerProtoDetectProbingParserElement *pe)
828{
829 SCEnter();
830
831 AppLayerProtoDetectProbingParserElement *new_pe = AppLayerProtoDetectProbingParserElementAlloc();
832
833 new_pe->alproto = pe->alproto;
834 new_pe->min_depth = pe->min_depth;
835 new_pe->max_depth = pe->max_depth;
836 new_pe->ProbingParserTs = pe->ProbingParserTs;
837 new_pe->ProbingParserTc = pe->ProbingParserTc;
838 new_pe->next = NULL;
839
840 SCReturnPtr(new_pe, "AppLayerProtoDetectProbingParserElement");
841}
842
843#ifdef DEBUG
844static void AppLayerProtoDetectPrintProbingParsers(AppLayerProtoDetectProbingParser *pp)
845{
846 SCEnter();
847
850
851 printf("\nProtocol Detection Configuration\n");
852
853 for ( ; pp != NULL; pp = pp->next) {
854 /* print ip protocol */
855 if (pp->ipproto == IPPROTO_TCP)
856 printf("IPProto: TCP\n");
857 else if (pp->ipproto == IPPROTO_UDP)
858 printf("IPProto: UDP\n");
859 else
860 printf("IPProto: %"PRIu8"\n", pp->ipproto);
861
862 pp_port = pp->port;
863 for ( ; pp_port != NULL; pp_port = pp_port->next) {
864 if (pp_port->dp != NULL) {
865 printf(" Port: %"PRIu16 "\n", pp_port->port);
866
867 printf(" Destination port: (max-depth: %" PRIu16 ")\n",
868 pp_port->dp_max_depth);
869 pp_pe = pp_port->dp;
870 for ( ; pp_pe != NULL; pp_pe = pp_pe->next) {
871
872 printf(" alproto: %s\n", AppProtoToString(pp_pe->alproto));
873 printf(" min_depth: %"PRIu32 "\n", pp_pe->min_depth);
874 printf(" max_depth: %"PRIu32 "\n", pp_pe->max_depth);
875
876 printf("\n");
877 }
878 }
879
880 if (pp_port->sp == NULL) {
881 continue;
882 }
883
884 printf(" Source port: (max-depth: %" PRIu16 ")\n", pp_port->sp_max_depth);
885 pp_pe = pp_port->sp;
886 for ( ; pp_pe != NULL; pp_pe = pp_pe->next) {
887
888 printf(" alproto: %s\n", AppProtoToString(pp_pe->alproto));
889 printf(" min_depth: %"PRIu32 "\n", pp_pe->min_depth);
890 printf(" max_depth: %"PRIu32 "\n", pp_pe->max_depth);
891
892 printf("\n");
893 }
894 }
895 }
896
897 SCReturn;
898}
899#endif
900
901static void AppLayerProtoDetectProbingParserElementAppend(AppLayerProtoDetectProbingParserElement **head_pe,
903{
904 SCEnter();
905
906 if (*head_pe == NULL) {
907 *head_pe = new_pe;
908 SCReturn;
909 }
910
911 AppLayerProtoDetectProbingParserElement *temp_pe = *head_pe;
912 while (temp_pe->next != NULL)
913 temp_pe = temp_pe->next;
914 temp_pe->next = new_pe;
915
916 SCReturn;
917}
918
919static void AppLayerProtoDetectProbingParserAppend(AppLayerProtoDetectProbingParser **head_pp,
921{
922 SCEnter();
923
924 if (*head_pp == NULL) {
925 *head_pp = new_pp;
926 goto end;
927 }
928
929 AppLayerProtoDetectProbingParser *temp_pp = *head_pp;
930 while (temp_pp->next != NULL)
931 temp_pp = temp_pp->next;
932 temp_pp->next = new_pp;
933
934 end:
935 SCReturn;
936}
937
938static void AppLayerProtoDetectProbingParserPortAppend(AppLayerProtoDetectProbingParserPort **head_port,
940{
941 SCEnter();
942
943 if (*head_port == NULL) {
944 *head_port = new_port;
945 goto end;
946 }
947
948 // port == 0 && use_ports is special run on any ports, kept at tail
949 if ((*head_port)->port == 0 && (*head_port)->use_ports) {
950 new_port->next = *head_port;
951 *head_port = new_port;
952 } else {
953 AppLayerProtoDetectProbingParserPort *temp_port = *head_port;
954 while (temp_port->next != NULL &&
955 !(temp_port->next->port == 0 && temp_port->next->use_ports)) {
956 temp_port = temp_port->next;
957 }
958 new_port->next = temp_port->next;
959 temp_port->next = new_port;
960 }
961
962 end:
963 SCReturn;
964}
965
966static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbingParser **pp,
967 uint8_t ipproto, bool use_ports, uint16_t port, AppProto alproto, uint16_t min_depth,
968 uint16_t max_depth, uint8_t direction, ProbingParserFPtr ProbingParser1,
969 ProbingParserFPtr ProbingParser2)
970{
971 SCEnter();
972
973 /* get the top level ipproto pp */
975 while (curr_pp != NULL) {
976 if (curr_pp->ipproto == ipproto)
977 break;
978 curr_pp = curr_pp->next;
979 }
980 if (curr_pp == NULL) {
981 AppLayerProtoDetectProbingParser *new_pp = AppLayerProtoDetectProbingParserAlloc();
982 new_pp->ipproto = ipproto;
983 AppLayerProtoDetectProbingParserAppend(pp, new_pp);
984 curr_pp = new_pp;
985 }
986
987 /* get the top level port pp */
988 AppLayerProtoDetectProbingParserPort *curr_port = curr_pp->port;
989 while (curr_port != NULL) {
990 // when not use_ports, always insert a new AppLayerProtoDetectProbingParserPort
991 if (curr_port->port == port && use_ports)
992 break;
993 curr_port = curr_port->next;
994 }
995 if (curr_port == NULL) {
996 AppLayerProtoDetectProbingParserPort *new_port = AppLayerProtoDetectProbingParserPortAlloc();
997 new_port->port = port;
998 new_port->use_ports = use_ports;
999 AppLayerProtoDetectProbingParserPortAppend(&curr_pp->port, new_port);
1000 curr_port = new_port;
1001 if (direction & STREAM_TOSERVER) {
1002 curr_port->dp_max_depth = max_depth;
1003 } else {
1004 curr_port->sp_max_depth = max_depth;
1005 }
1006
1008
1009 zero_port = curr_pp->port;
1010 // get special run on any port if any, to add it to this port
1011 while (zero_port != NULL && !(zero_port->port == 0 && zero_port->use_ports)) {
1012 zero_port = zero_port->next;
1013 }
1014 if (zero_port != NULL) {
1016
1017 zero_pe = zero_port->dp;
1018 for ( ; zero_pe != NULL; zero_pe = zero_pe->next) {
1019 if (curr_port->dp == NULL)
1020 curr_port->dp_max_depth = zero_pe->max_depth;
1021 if (zero_pe->max_depth == 0)
1022 curr_port->dp_max_depth = zero_pe->max_depth;
1023 if (curr_port->dp_max_depth != 0 &&
1024 curr_port->dp_max_depth < zero_pe->max_depth) {
1025 curr_port->dp_max_depth = zero_pe->max_depth;
1026 }
1027
1029 AppLayerProtoDetectProbingParserElementDuplicate(zero_pe);
1030 AppLayerProtoDetectProbingParserElementAppend(&curr_port->dp, dup_pe);
1031 }
1032
1033 zero_pe = zero_port->sp;
1034 for ( ; zero_pe != NULL; zero_pe = zero_pe->next) {
1035 if (curr_port->sp == NULL)
1036 curr_port->sp_max_depth = zero_pe->max_depth;
1037 if (zero_pe->max_depth == 0)
1038 curr_port->sp_max_depth = zero_pe->max_depth;
1039 if (curr_port->sp_max_depth != 0 &&
1040 curr_port->sp_max_depth < zero_pe->max_depth) {
1041 curr_port->sp_max_depth = zero_pe->max_depth;
1042 }
1043
1045 AppLayerProtoDetectProbingParserElementDuplicate(zero_pe);
1046 AppLayerProtoDetectProbingParserElementAppend(&curr_port->sp, dup_pe);
1047 }
1048 } /* if (zero_port != NULL) */
1049 } /* if (curr_port == NULL) */
1050
1051 /* insert the pe_pp */
1053 if (direction & STREAM_TOSERVER)
1054 curr_pe = curr_port->dp;
1055 else
1056 curr_pe = curr_port->sp;
1057 while (curr_pe != NULL) {
1058 if (curr_pe->alproto == alproto) {
1059 SCLogError("Duplicate pp registered - "
1060 "ipproto - %" PRIu8 " Port - %" PRIu16 " "
1061 "App Protocol - NULL, App Protocol(ID) - "
1062 "%" PRIu16 " min_depth - %" PRIu16 " "
1063 "max_dept - %" PRIu16 ".",
1064 ipproto, port, alproto, min_depth, max_depth);
1065 goto error;
1066 }
1067 curr_pe = curr_pe->next;
1068 }
1069 /* Get a new parser element */
1071 AppLayerProtoDetectProbingParserElementCreate(alproto, min_depth, max_depth);
1072 if (new_pe == NULL)
1073 goto error;
1074 curr_pe = new_pe;
1076 if (direction & STREAM_TOSERVER) {
1077 curr_pe->ProbingParserTs = ProbingParser1;
1078 curr_pe->ProbingParserTc = ProbingParser2;
1079 if (curr_port->dp == NULL)
1080 curr_port->dp_max_depth = new_pe->max_depth;
1081 if (new_pe->max_depth == 0)
1082 curr_port->dp_max_depth = new_pe->max_depth;
1083 if (curr_port->dp_max_depth != 0 &&
1084 curr_port->dp_max_depth < new_pe->max_depth) {
1085 curr_port->dp_max_depth = new_pe->max_depth;
1086 }
1087 head_pe = &curr_port->dp;
1088 } else {
1089 curr_pe->ProbingParserTs = ProbingParser2;
1090 curr_pe->ProbingParserTc = ProbingParser1;
1091 if (curr_port->sp == NULL)
1092 curr_port->sp_max_depth = new_pe->max_depth;
1093 if (new_pe->max_depth == 0)
1094 curr_port->sp_max_depth = new_pe->max_depth;
1095 if (curr_port->sp_max_depth != 0 &&
1096 curr_port->sp_max_depth < new_pe->max_depth) {
1097 curr_port->sp_max_depth = new_pe->max_depth;
1098 }
1099 head_pe = &curr_port->sp;
1100 }
1101 AppLayerProtoDetectProbingParserElementAppend(head_pe, new_pe);
1102
1103 // when adding special run on any port, add it on all existing ones
1104 if (curr_port->port == 0 && curr_port->use_ports) {
1105 AppLayerProtoDetectProbingParserPort *temp_port = curr_pp->port;
1106 while (temp_port != NULL && !(temp_port->port == 0 && temp_port->use_ports)) {
1107 if (direction & STREAM_TOSERVER) {
1108 if (temp_port->dp == NULL)
1109 temp_port->dp_max_depth = curr_pe->max_depth;
1110 if (curr_pe->max_depth == 0)
1111 temp_port->dp_max_depth = curr_pe->max_depth;
1112 if (temp_port->dp_max_depth != 0 &&
1113 temp_port->dp_max_depth < curr_pe->max_depth) {
1114 temp_port->dp_max_depth = curr_pe->max_depth;
1115 }
1116 AppLayerProtoDetectProbingParserElementAppend(
1117 &temp_port->dp, AppLayerProtoDetectProbingParserElementDuplicate(curr_pe));
1118 } else {
1119 if (temp_port->sp == NULL)
1120 temp_port->sp_max_depth = curr_pe->max_depth;
1121 if (curr_pe->max_depth == 0)
1122 temp_port->sp_max_depth = curr_pe->max_depth;
1123 if (temp_port->sp_max_depth != 0 &&
1124 temp_port->sp_max_depth < curr_pe->max_depth) {
1125 temp_port->sp_max_depth = curr_pe->max_depth;
1126 }
1127 AppLayerProtoDetectProbingParserElementAppend(
1128 &temp_port->sp, AppLayerProtoDetectProbingParserElementDuplicate(curr_pe));
1129 }
1130 temp_port = temp_port->next;
1131 } /* while */
1132 } /* if */
1133
1134 error:
1135 SCReturn;
1136}
1137
1138/***** Static Internal Calls: PM registration *****/
1139
1140static void AppLayerProtoDetectPMGetIpprotos(AppProto alproto,
1141 uint8_t *ipprotos)
1142{
1143 SCEnter();
1144
1145 for (uint8_t i = 0; i < FLOW_PROTO_DEFAULT; i++) {
1146 uint8_t ipproto = FlowGetReverseProtoMapping(i);
1147 for (int j = 0; j < 2; j++) {
1148 AppLayerProtoDetectPMCtx *pm_ctx = &alpd_ctx.ctx_ipp[i].ctx_pm[j];
1149
1150 for (SigIntId x = 0; x < pm_ctx->max_sig_id; x++) {
1151 const AppLayerProtoDetectPMSignature *s = pm_ctx->map[x];
1152 if (s->alproto == alproto)
1153 ipprotos[ipproto / 8] |= 1 << (ipproto % 8);
1154 }
1155 }
1156 }
1157
1158 SCReturn;
1159}
1160
1161static int AppLayerProtoDetectPMSetContentIDs(AppLayerProtoDetectPMCtx *ctx)
1162{
1163 SCEnter();
1164
1165 typedef struct TempContainer_ {
1166 PatIntId id;
1167 uint16_t content_len;
1168 uint8_t *content;
1169 } TempContainer;
1170
1172 uint32_t struct_total_size = 0;
1173 uint32_t content_total_size = 0;
1174 /* array hash buffer */
1175 uint8_t *ahb = NULL;
1176 uint8_t *content = NULL;
1177 uint16_t content_len = 0;
1178 PatIntId max_id = 0;
1179 TempContainer *struct_offset = NULL;
1180 uint8_t *content_offset = NULL;
1181 int ret = 0;
1182
1183 if (ctx->head == NULL)
1184 goto end;
1185
1186 for (s = ctx->head; s != NULL; s = s->next) {
1187 struct_total_size += sizeof(TempContainer);
1188 content_total_size += s->cd->content_len;
1189 ctx->max_sig_id++;
1190 }
1191
1192 ahb = SCMalloc(sizeof(uint8_t) * (struct_total_size + content_total_size));
1193 if (unlikely(ahb == NULL))
1194 goto error;
1195
1196 struct_offset = (TempContainer *)ahb;
1197 content_offset = ahb + struct_total_size;
1198 for (s = ctx->head; s != NULL; s = s->next) {
1199 TempContainer *tcdup = (TempContainer *)ahb;
1200 content = s->cd->content;
1201 content_len = s->cd->content_len;
1202
1203 for (; tcdup != struct_offset; tcdup++) {
1204 if (tcdup->content_len != content_len ||
1205 SCMemcmp(tcdup->content, content, tcdup->content_len) != 0)
1206 {
1207 continue;
1208 }
1209 break;
1210 }
1211
1212 if (tcdup != struct_offset) {
1213 s->cd->id = tcdup->id;
1214 continue;
1215 }
1216
1217 struct_offset->content_len = content_len;
1218 struct_offset->content = content_offset;
1219 content_offset += content_len;
1220 memcpy(struct_offset->content, content, content_len);
1221 struct_offset->id = max_id++;
1222 s->cd->id = struct_offset->id;
1223
1224 struct_offset++;
1225 }
1226
1227 ctx->max_pat_id = max_id;
1228
1229 goto end;
1230 error:
1231 ret = -1;
1232 end:
1233 if (ahb != NULL)
1234 SCFree(ahb);
1235 SCReturnInt(ret);
1236}
1237
1238static int AppLayerProtoDetectPMMapSignatures(AppLayerProtoDetectPMCtx *ctx)
1239{
1240 SCEnter();
1241
1242 int ret = 0;
1244 int mpm_ret;
1245 SigIntId id = 0;
1246
1247 ctx->map = SCCalloc(ctx->max_sig_id, sizeof(AppLayerProtoDetectPMSignature *));
1248 if (ctx->map == NULL)
1249 goto error;
1250
1251 /* add an array indexed by rule id to look up the sig */
1252 for (s = ctx->head; s != NULL; ) {
1253 next_s = s->next;
1254 s->id = id++;
1255 SCLogDebug("s->id %u offset %u depth %u",
1256 s->id, s->cd->offset, s->cd->depth);
1257
1258 if (s->cd->flags & DETECT_CONTENT_NOCASE) {
1259 mpm_ret = MpmAddPatternCI(&ctx->mpm_ctx,
1260 s->cd->content, s->cd->content_len,
1261 s->cd->offset, s->cd->depth, s->cd->id, s->id, 0);
1262 if (mpm_ret < 0)
1263 goto error;
1264 } else {
1265 mpm_ret = MpmAddPatternCS(&ctx->mpm_ctx,
1266 s->cd->content, s->cd->content_len,
1267 s->cd->offset, s->cd->depth, s->cd->id, s->id, 0);
1268 if (mpm_ret < 0)
1269 goto error;
1270 }
1271
1272 ctx->map[s->id] = s;
1273 s->next = NULL;
1274 s = next_s;
1275 }
1276 ctx->head = NULL;
1277
1278 goto end;
1279 error:
1280 ret = -1;
1281 end:
1282 SCReturnInt(ret);
1283}
1284
1285static int AppLayerProtoDetectPMPrepareMpm(AppLayerProtoDetectPMCtx *ctx)
1286{
1287 SCEnter();
1288
1289 int ret = 0;
1290 MpmCtx *mpm_ctx = &ctx->mpm_ctx;
1291
1292 if (mpm_table[mpm_ctx->mpm_type].Prepare(NULL, mpm_ctx) < 0)
1293 goto error;
1294
1295 goto end;
1296 error:
1297 ret = -1;
1298 end:
1299 SCReturnInt(ret);
1300}
1301
1302static void AppLayerProtoDetectPMFreeSignature(AppLayerProtoDetectPMSignature *sig)
1303{
1304 SCEnter();
1305 if (sig == NULL)
1306 SCReturn;
1307 if (sig->cd)
1308 DetectContentFree(NULL, sig->cd);
1309 SCFree(sig);
1310 SCReturn;
1311}
1312
1313static int AppLayerProtoDetectPMAddSignature(AppLayerProtoDetectPMCtx *ctx, DetectContentData *cd,
1314 AppProto alproto, uint8_t direction,
1315 ProbingParserFPtr PPFunc,
1316 uint16_t pp_min_depth, uint16_t pp_max_depth)
1317{
1318 SCEnter();
1319
1320 AppLayerProtoDetectPMSignature *s = SCCalloc(1, sizeof(*s));
1321 if (unlikely(s == NULL))
1322 SCReturnInt(-1);
1323
1324 s->alproto = alproto;
1325 s->direction = direction;
1326 s->cd = cd;
1327 s->PPFunc = PPFunc;
1328 s->pp_min_depth = pp_min_depth;
1329 s->pp_max_depth = pp_max_depth;
1330
1331 /* prepend to the list */
1332 s->next = ctx->head;
1333 ctx->head = s;
1334
1335 SCReturnInt(0);
1336}
1337
1338static int AppLayerProtoDetectPMRegisterPattern(uint8_t ipproto, AppProto alproto,
1339 const char *pattern,
1340 uint16_t depth, uint16_t offset,
1341 uint8_t direction,
1342 uint8_t is_cs,
1343 ProbingParserFPtr PPFunc,
1344 uint16_t pp_min_depth, uint16_t pp_max_depth)
1345{
1346 SCEnter();
1347
1348 AppLayerProtoDetectCtxIpproto *ctx_ipp = &alpd_ctx.ctx_ipp[FlowGetProtoMapping(ipproto)];
1349 AppLayerProtoDetectPMCtx *ctx_pm = NULL;
1350 int ret = 0;
1351
1353 alpd_ctx.spm_global_thread_ctx, pattern);
1354 if (cd == NULL)
1355 goto error;
1356 cd->depth = depth;
1357 cd->offset = offset;
1358 if (!is_cs) {
1359 /* Rebuild as nocase */
1361 cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 1,
1362 alpd_ctx.spm_global_thread_ctx);
1363 if (cd->spm_ctx == NULL) {
1364 goto error;
1365 }
1367 }
1368 if (depth < cd->content_len)
1369 goto error;
1370
1371 if (direction & STREAM_TOSERVER)
1372 ctx_pm = (AppLayerProtoDetectPMCtx *)&ctx_ipp->ctx_pm[0];
1373 else
1374 ctx_pm = (AppLayerProtoDetectPMCtx *)&ctx_ipp->ctx_pm[1];
1375
1376 if (pp_max_depth > ctx_pm->pp_max_len)
1377 ctx_pm->pp_max_len = pp_max_depth;
1378 if (depth < ctx_pm->min_len)
1379 ctx_pm->min_len = depth;
1380
1381 /* Finally turn it into a signature and add to the ctx. */
1382 AppLayerProtoDetectPMAddSignature(ctx_pm, cd, alproto, direction,
1383 PPFunc, pp_min_depth, pp_max_depth);
1384
1385 goto end;
1386 error:
1387 DetectContentFree(NULL, cd);
1388 ret = -1;
1389 end:
1390 SCReturnInt(ret);
1391}
1392
1393/***** Protocol Retrieval *****/
1394
1396 const uint8_t *buf, uint32_t buflen, uint8_t ipproto, uint8_t flags, bool *reverse_flow)
1397{
1398 SCEnter();
1399 SCLogDebug("buflen %u for %s direction", buflen,
1400 (flags & STREAM_TOSERVER) ? "toserver" : "toclient");
1401
1402 AppProto alproto = ALPROTO_UNKNOWN;
1403
1404 if (!FLOW_IS_PM_DONE(f, flags)) {
1405 AppProto pm_results[g_alproto_max];
1406 uint16_t pm_matches = AppLayerProtoDetectPMGetProto(
1407 tctx, f, buf, buflen, flags, pm_results, reverse_flow);
1408 if (pm_matches > 0) {
1409 DEBUG_VALIDATE_BUG_ON(pm_matches > 1);
1410 alproto = pm_results[0];
1411
1412 // rerun probing parser for other direction if it is unknown
1413 uint8_t reverse_dir = (flags & STREAM_TOSERVER) ? STREAM_TOCLIENT : STREAM_TOSERVER;
1414 if (FLOW_IS_PP_DONE(f, reverse_dir)) {
1415 AppProto rev_alproto = (flags & STREAM_TOSERVER) ? f->alproto_tc : f->alproto_ts;
1416 if (rev_alproto == ALPROTO_UNKNOWN) {
1417 FLOW_RESET_PP_DONE(f, reverse_dir);
1418 }
1419 }
1420 SCReturnUInt(alproto);
1421 }
1422 }
1423
1424 if (!FLOW_IS_PP_DONE(f, flags)) {
1425 DEBUG_VALIDATE_BUG_ON(*reverse_flow);
1426 alproto = AppLayerProtoDetectPPGetProto(f, buf, buflen, ipproto, flags, reverse_flow);
1427 if (AppProtoIsValid(alproto)) {
1428 SCReturnUInt(alproto);
1429 }
1430 }
1431
1432 /* Look if flow can be found in expectation list */
1433 if (!FLOW_IS_PE_DONE(f, flags)) {
1434 DEBUG_VALIDATE_BUG_ON(*reverse_flow);
1435 alproto = AppLayerProtoDetectPEGetProto(f, flags);
1436 }
1437
1438 SCReturnUInt(alproto);
1439}
1440
1441static void AppLayerProtoDetectFreeProbingParsers(AppLayerProtoDetectProbingParser *pp)
1442{
1443 SCEnter();
1444
1445 AppLayerProtoDetectProbingParser *tmp_pp = NULL;
1446
1447 if (pp == NULL)
1448 goto end;
1449
1450 while (pp != NULL) {
1451 tmp_pp = pp->next;
1452 AppLayerProtoDetectProbingParserFree(pp);
1453 pp = tmp_pp;
1454 }
1455
1456 end:
1457 SCReturn;
1458}
1459
1460static void AppLayerProtoDetectFreeAliases(void)
1461{
1462 SCEnter();
1463
1464 AppLayerProtoDetectAliases *cur_alias = alpda_ctx;
1465 if (cur_alias == NULL)
1466 goto end;
1467
1468 AppLayerProtoDetectAliases *next_alias = NULL;
1469 while (cur_alias != NULL) {
1470 next_alias = cur_alias->next;
1471 SCFree(cur_alias);
1472 cur_alias = next_alias;
1473 }
1474
1475 alpda_ctx = NULL;
1476
1477end:
1478 SCReturn;
1479}
1480
1481/***** State Preparation *****/
1482
1484{
1485 SCEnter();
1486
1488 int i, j;
1489 int ret = 0;
1490
1491 for (i = 0; i < FLOW_PROTO_DEFAULT; i++) {
1492 for (j = 0; j < 2; j++) {
1493 ctx_pm = &alpd_ctx.ctx_ipp[i].ctx_pm[j];
1494
1495 if (AppLayerProtoDetectPMSetContentIDs(ctx_pm) < 0)
1496 goto error;
1497
1498 if (ctx_pm->max_sig_id == 0)
1499 continue;
1500
1501 if (AppLayerProtoDetectPMMapSignatures(ctx_pm) < 0)
1502 goto error;
1503 if (AppLayerProtoDetectPMPrepareMpm(ctx_pm) < 0)
1504 goto error;
1505 }
1506 }
1507
1508#ifdef DEBUG
1509 if (SCLogDebugEnabled()) {
1510 AppLayerProtoDetectPrintProbingParsers(alpd_ctx.ctx_pp);
1511 }
1512#endif
1513
1514 goto end;
1515 error:
1516 ret = -1;
1517 end:
1518 SCReturnInt(ret);
1519}
1520
1521/***** PP registration *****/
1522
1523/** \brief register parser at a port
1524 *
1525 * \param direction STREAM_TOSERVER or STREAM_TOCLIENT for dp or sp
1526 */
1527void SCAppLayerProtoDetectPPRegister(uint8_t ipproto, const char *portstr, AppProto alproto,
1528 uint16_t min_depth, uint16_t max_depth, uint8_t direction, ProbingParserFPtr ProbingParser1,
1529 ProbingParserFPtr ProbingParser2)
1530{
1531 SCEnter();
1532
1533 DetectPort *head = NULL;
1534 if (portstr == NULL) {
1535 // WebSocket has a probing parser, but no port
1536 // as it works only on HTTP1 protocol upgrade
1537 AppLayerProtoDetectInsertNewProbingParser(&alpd_ctx.ctx_pp, ipproto, false, 0, alproto,
1538 min_depth, max_depth, direction, ProbingParser1, ProbingParser2);
1539 return;
1540 }
1541 DetectPortParse(NULL,&head, portstr);
1542 DetectPort *temp_dp = head;
1543 while (temp_dp != NULL) {
1544 uint16_t port = temp_dp->port;
1545 if (port == 0 && temp_dp->port2 != 0)
1546 port++;
1547 for (;;) {
1548 AppLayerProtoDetectInsertNewProbingParser(&alpd_ctx.ctx_pp, ipproto, true, port,
1549 alproto, min_depth, max_depth, direction, ProbingParser1, ProbingParser2);
1550 if (port == temp_dp->port2) {
1551 break;
1552 } else {
1553 port++;
1554 }
1555 }
1556 temp_dp = temp_dp->next;
1557 }
1559
1560 SCReturn;
1561}
1562
1563int SCAppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, uint8_t ipproto,
1564 const char *alproto_name, AppProto alproto, uint16_t min_depth, uint16_t max_depth,
1565 ProbingParserFPtr ProbingParserTs, ProbingParserFPtr ProbingParserTc)
1566{
1567 SCEnter();
1568
1569 char param[100];
1570 int r;
1571 SCConfNode *node;
1572 SCConfNode *port_node = NULL;
1573 int config = 0;
1574
1575 r = snprintf(param, sizeof(param), "%s%s%s", "app-layer.protocols.",
1576 alproto_name, ".detection-ports");
1577 if (r < 0) {
1578 FatalError("snprintf failure.");
1579 } else if (r > (int)sizeof(param)) {
1580 FatalError("buffer not big enough to write param.");
1581 }
1582 node = SCConfGetNode(param);
1583 if (node == NULL) {
1584 SCLogDebug("Entry for %s not found.", param);
1585 r = snprintf(param, sizeof(param), "%s%s%s%s%s", "app-layer.protocols.",
1586 alproto_name, ".", ipproto_name, ".detection-ports");
1587 if (r < 0) {
1588 FatalError("snprintf failure.");
1589 } else if (r > (int)sizeof(param)) {
1590 FatalError("buffer not big enough to write param.");
1591 }
1592 node = SCConfGetNode(param);
1593 if (node == NULL)
1594 goto end;
1595 }
1596
1597 /* detect by destination port of the flow (e.g. port 53 for DNS) */
1598 port_node = SCConfNodeLookupChild(node, "dp");
1599 if (port_node == NULL)
1600 port_node = SCConfNodeLookupChild(node, "toserver");
1601
1602 if (port_node != NULL && port_node->val != NULL) {
1603 SCAppLayerProtoDetectPPRegister(ipproto, port_node->val, alproto, min_depth, max_depth,
1604 STREAM_TOSERVER, /* to indicate dp */
1605 ProbingParserTs, ProbingParserTc);
1606 }
1607
1608 /* detect by source port of flow */
1609 port_node = SCConfNodeLookupChild(node, "sp");
1610 if (port_node == NULL)
1611 port_node = SCConfNodeLookupChild(node, "toclient");
1612
1613 if (port_node != NULL && port_node->val != NULL) {
1614 SCAppLayerProtoDetectPPRegister(ipproto, port_node->val, alproto, min_depth, max_depth,
1615 STREAM_TOCLIENT, /* to indicate sp */
1616 ProbingParserTc, ProbingParserTs);
1617 }
1618
1619 config = 1;
1620 end:
1621 SCReturnInt(config);
1622}
1623
1624/***** PM registration *****/
1625
1626int SCAppLayerProtoDetectPMRegisterPatternCS(uint8_t ipproto, AppProto alproto, const char *pattern,
1627 uint16_t depth, uint16_t offset, uint8_t direction)
1628{
1629 SCEnter();
1630 int r = AppLayerProtoDetectPMRegisterPattern(ipproto, alproto,
1631 pattern, depth, offset,
1632 direction, 1 /* case-sensitive */,
1633 NULL, 0, 0);
1634 SCReturnInt(r);
1635}
1636
1638 const char *pattern, uint16_t depth, uint16_t offset, uint8_t direction,
1639 ProbingParserFPtr PPFunc, uint16_t pp_min_depth, uint16_t pp_max_depth)
1640{
1641 SCEnter();
1642 int r = AppLayerProtoDetectPMRegisterPattern(ipproto, alproto,
1643 pattern, depth, offset,
1644 direction, 1 /* case-sensitive */,
1645 PPFunc, pp_min_depth, pp_max_depth);
1646 SCReturnInt(r);
1647}
1648
1649int SCAppLayerProtoDetectPMRegisterPatternCI(uint8_t ipproto, AppProto alproto, const char *pattern,
1650 uint16_t depth, uint16_t offset, uint8_t direction)
1651{
1652 SCEnter();
1653 int r = AppLayerProtoDetectPMRegisterPattern(ipproto, alproto,
1654 pattern, depth, offset,
1655 direction, 0 /* !case-sensitive */,
1656 NULL, 0, 0);
1657 SCReturnInt(r);
1658}
1659
1660/***** Setup/General Registration *****/
1661
1663{
1664 SCEnter();
1665
1666 int i, j;
1667
1668 memset(&alpd_ctx, 0, sizeof(alpd_ctx));
1669
1670 uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
1671 uint8_t mpm_matcher = PatternMatchDefaultMatcher();
1672
1673 alpd_ctx.spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
1674 if (alpd_ctx.spm_global_thread_ctx == NULL) {
1675 FatalError("Unable to alloc SpmGlobalThreadCtx.");
1676 }
1677
1678 for (i = 0; i < FLOW_PROTO_DEFAULT; i++) {
1679 for (j = 0; j < 2; j++) {
1680 MpmInitCtx(&alpd_ctx.ctx_ipp[i].ctx_pm[j].mpm_ctx, mpm_matcher);
1681 }
1682 }
1683
1684 alpd_ctx.alproto_names = SCCalloc(g_alproto_max, sizeof(char *));
1685 if (unlikely(alpd_ctx.alproto_names == NULL)) {
1686 FatalError("Unable to alloc alproto_names.");
1687 }
1689 // to realloc when dynamic protos are added
1690 alpd_ctx.expectation_proto = SCCalloc(g_alproto_max, sizeof(uint8_t));
1691 if (unlikely(alpd_ctx.expectation_proto == NULL)) {
1692 FatalError("Unable to alloc expectation_proto.");
1693 }
1696
1697 SCReturnInt(0);
1698}
1699
1700/**
1701 * \todo incomplete. Need more work.
1702 */
1704{
1705 SCEnter();
1706
1707 int ipproto_map = 0;
1708 int dir = 0;
1709 PatIntId id = 0;
1710 AppLayerProtoDetectPMCtx *pm_ctx = NULL;
1712
1713 for (ipproto_map = 0; ipproto_map < FLOW_PROTO_DEFAULT; ipproto_map++) {
1714 for (dir = 0; dir < 2; dir++) {
1715 pm_ctx = &alpd_ctx.ctx_ipp[ipproto_map].ctx_pm[dir];
1716 mpm_table[pm_ctx->mpm_ctx.mpm_type].DestroyCtx(&pm_ctx->mpm_ctx);
1717 for (id = 0; id < pm_ctx->max_sig_id; id++) {
1718 sig = pm_ctx->map[id];
1719 AppLayerProtoDetectPMFreeSignature(sig);
1720 }
1721 SCFree(pm_ctx->map);
1722 pm_ctx->map = NULL;
1723 }
1724 }
1725
1726 SCFree(alpd_ctx.alproto_names);
1727 alpd_ctx.alproto_names = NULL;
1728 alpd_ctx.alproto_names_len = 0;
1729 SCFree(alpd_ctx.expectation_proto);
1730 alpd_ctx.expectation_proto = NULL;
1731 alpd_ctx.expectation_proto_len = 0;
1732
1734
1735 AppLayerProtoDetectFreeAliases();
1736
1737 AppLayerProtoDetectFreeProbingParsers(alpd_ctx.ctx_pp);
1738
1739 SCReturnInt(0);
1740}
1741
1742void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_name)
1743{
1744 SCEnter();
1745
1746 if (alpd_ctx.alproto_names_len <= alproto && alproto < g_alproto_max) {
1747 void *tmp = SCRealloc(alpd_ctx.alproto_names, sizeof(char *) * g_alproto_max);
1748 if (unlikely(tmp == NULL)) {
1749 FatalError("Unable to realloc alproto_names.");
1750 }
1751 alpd_ctx.alproto_names = tmp;
1752 memset(&alpd_ctx.alproto_names[alpd_ctx.alproto_names_len], 0,
1753 sizeof(char *) * (g_alproto_max - alpd_ctx.alproto_names_len));
1755 }
1756 if (alpd_ctx.alproto_names[alproto] == NULL)
1757 alpd_ctx.alproto_names[alproto] = alproto_name;
1758
1759 SCReturn;
1760}
1761
1762void AppLayerProtoDetectRegisterAlias(const char *proto_name, const char *proto_alias)
1763{
1764 SCEnter();
1765
1767 if (unlikely(new_alias == NULL)) {
1768 exit(EXIT_FAILURE);
1769 }
1770
1771 new_alias->proto_name = proto_name;
1772 new_alias->proto_alias = proto_alias;
1773 new_alias->next = NULL;
1774
1775 if (alpda_ctx == NULL) {
1776 alpda_ctx = new_alias;
1777 } else {
1778 AppLayerProtoDetectAliases *cur_alias = alpda_ctx;
1779 while (cur_alias->next != NULL) {
1780 cur_alias = cur_alias->next;
1781 }
1782 cur_alias->next = new_alias;
1783 }
1784
1785 SCReturn;
1786}
1787
1788/** \brief request applayer to wrap up this protocol and rerun protocol
1789 * detection.
1790 *
1791 * When this is called, the old session is reset unconditionally. A
1792 * 'detect/log' flush packet is generated for both direction before
1793 * the reset, so allow for final detection and logging.
1794 *
1795 * \param f flow to act on
1796 * \param dp destination port to use in protocol detection. Set to 443
1797 * for start tls, set to the HTTP uri port for CONNECT and
1798 * set to 0 to not use it.
1799 * \param expect_proto expected protocol. AppLayer event will be set if
1800 * detected protocol differs from this.
1801 */
1802bool AppLayerRequestProtocolChange(Flow *f, uint16_t dp, AppProto expect_proto)
1803{
1804 if (FlowChangeProto(f)) {
1805 // If we are already changing protocols, from SMTP to TLS for instance,
1806 // and that we do not get TLS but HTTP1, which is requesting change to HTTP2,
1807 // we do not proceed the new protocol change
1808 return false;
1809 }
1811 f->protodetect_dp = dp;
1812 f->alproto_expect = expect_proto;
1814 f->alproto_orig = f->alproto;
1815 // If one side is unknown yet, set it to the other known side
1816 if (f->alproto_ts == ALPROTO_UNKNOWN) {
1817 f->alproto_ts = f->alproto;
1818 }
1819 if (f->alproto_tc == ALPROTO_UNKNOWN) {
1820 f->alproto_tc = f->alproto;
1821 }
1822 return true;
1823}
1824
1825/** \brief request applayer to wrap up this protocol and rerun protocol
1826 * detection with expectation of TLS. Used by STARTTLS.
1827 *
1828 * Sets detection port to 443 to make port based TLS detection work for
1829 * SMTP, FTP etc as well.
1830 *
1831 * \param f flow to act on
1832 */
1837
1838/** \brief Forces a flow app-layer protocol change.
1839 * Happens for instance when a HTTP2 flow is seen as DOH2
1840 *
1841 * \param f flow to act on
1842 * \param new_proto new app-layer protocol
1843 */
1845{
1846 if (new_proto != f->alproto) {
1847 f->alproto_orig = f->alproto;
1848 f->alproto = new_proto;
1849 f->alproto_ts = f->alproto;
1850 f->alproto_tc = f->alproto;
1851 }
1852}
1853
1855{
1856 FLOW_RESET_PM_DONE(f, STREAM_TOSERVER);
1857 FLOW_RESET_PM_DONE(f, STREAM_TOCLIENT);
1858 FLOW_RESET_PP_DONE(f, STREAM_TOSERVER);
1859 FLOW_RESET_PP_DONE(f, STREAM_TOCLIENT);
1860 FLOW_RESET_PE_DONE(f, STREAM_TOSERVER);
1861 FLOW_RESET_PE_DONE(f, STREAM_TOCLIENT);
1864 // Does not free the structures for the parser
1865 // keeps f->alstate for new state creation
1866 f->alparser = NULL;
1870}
1871
1873 const char *ipproto, const char *alproto, bool default_enabled)
1874{
1875 SCEnter();
1876
1877 BUG_ON(ipproto == NULL || alproto == NULL);
1878
1879 int enabled = 1;
1880 char param[100];
1881 SCConfNode *node;
1882 int r;
1883
1884 if (RunmodeIsUnittests())
1885 goto enabled;
1886
1887#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1888 // so that fuzzig takes place for DNP3 and such
1889 default_enabled = true;
1890#endif
1891
1892 r = snprintf(param, sizeof(param), "%s%s%s", "app-layer.protocols.",
1893 alproto, ".enabled");
1894 if (r < 0) {
1895 FatalError("snprintf failure.");
1896 } else if (r > (int)sizeof(param)) {
1897 FatalError("buffer not big enough to write param.");
1898 }
1899
1900 node = SCConfGetNode(param);
1901 if (node == NULL) {
1902 SCLogDebug("Entry for %s not found.", param);
1903 r = snprintf(param, sizeof(param), "%s%s%s%s%s", "app-layer.protocols.",
1904 alproto, ".", ipproto, ".enabled");
1905 if (r < 0) {
1906 FatalError("snprintf failure.");
1907 } else if (r > (int)sizeof(param)) {
1908 FatalError("buffer not big enough to write param.");
1909 }
1910
1911 node = SCConfGetNode(param);
1912 if (node == NULL) {
1913 SCLogDebug("Entry for %s not found.", param);
1914 if (default_enabled) {
1915 goto enabled;
1916 } else {
1917 goto disabled;
1918 }
1919 }
1920 }
1921
1922 if (node->val) {
1923 if (SCConfValIsTrue(node->val)) {
1924 goto enabled;
1925 } else if (SCConfValIsFalse(node->val)) {
1926 goto disabled;
1927 } else if (strcasecmp(node->val, "detection-only") == 0) {
1928 goto enabled;
1929 }
1930 }
1931
1932 /* Invalid or null value. */
1933 SCLogError("Invalid value found for %s.", param);
1934 exit(EXIT_FAILURE);
1935
1936 disabled:
1937 enabled = 0;
1938 enabled:
1939 SCReturnInt(enabled);
1940}
1941
1942int SCAppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, const char *alproto)
1943{
1944 return SCAppLayerProtoDetectConfProtoDetectionEnabledDefault(ipproto, alproto, true);
1945}
1946
1948{
1949 SCEnter();
1950
1952 MpmCtx *mpm_ctx;
1953 MpmThreadCtx *mpm_tctx;
1954 int i, j;
1955 PatIntId max_pat_id = 0;
1956
1957 for (i = 0; i < FLOW_PROTO_DEFAULT; i++) {
1958 for (j = 0; j < 2; j++) {
1959 if (max_pat_id == 0) {
1960 max_pat_id = alpd_ctx.ctx_ipp[i].ctx_pm[j].max_pat_id;
1961
1962 } else if (alpd_ctx.ctx_ipp[i].ctx_pm[j].max_pat_id &&
1963 max_pat_id < alpd_ctx.ctx_ipp[i].ctx_pm[j].max_pat_id)
1964 {
1965 max_pat_id = alpd_ctx.ctx_ipp[i].ctx_pm[j].max_pat_id;
1966 }
1967 }
1968 }
1969
1970 alpd_tctx = SCCalloc(1, sizeof(*alpd_tctx));
1971 if (alpd_tctx == NULL)
1972 goto error;
1973
1974 /* Get the max pat id for all the mpm ctxs. */
1975 if (PmqSetup(&alpd_tctx->pmq) < 0)
1976 goto error;
1977
1978 for (i = 0; i < FLOW_PROTO_DEFAULT; i++) {
1979 for (j = 0; j < 2; j++) {
1980 mpm_ctx = &alpd_ctx.ctx_ipp[i].ctx_pm[j].mpm_ctx;
1981 mpm_tctx = &alpd_tctx->mpm_tctx[i][j];
1982 MpmInitThreadCtx(mpm_tctx, mpm_ctx->mpm_type);
1983 }
1984 }
1985
1987 if (alpd_tctx->spm_thread_ctx == NULL) {
1988 goto error;
1989 }
1990
1991 goto end;
1992 error:
1993 if (alpd_tctx != NULL)
1995 alpd_tctx = NULL;
1996 end:
1997 SCReturnPtr(alpd_tctx, "AppLayerProtoDetectThreadCtx");
1998}
1999
2001{
2002 SCEnter();
2003
2004 MpmCtx *mpm_ctx;
2005 MpmThreadCtx *mpm_tctx;
2006 int ipproto_map, dir;
2007
2008 for (ipproto_map = 0; ipproto_map < FLOW_PROTO_DEFAULT; ipproto_map++) {
2009 for (dir = 0; dir < 2; dir++) {
2010 mpm_ctx = &alpd_ctx.ctx_ipp[ipproto_map].ctx_pm[dir].mpm_ctx;
2011 mpm_tctx = &alpd_tctx->mpm_tctx[ipproto_map][dir];
2012 MpmDestroyThreadCtx(mpm_tctx, mpm_ctx->mpm_type);
2013 }
2014 }
2016 if (alpd_tctx->spm_thread_ctx != NULL) {
2018 }
2020
2021 SCReturn;
2022}
2023
2024/***** Utility *****/
2025
2026void AppLayerProtoDetectSupportedIpprotos(AppProto alproto, uint8_t *ipprotos)
2027{
2028 SCEnter();
2029
2030 // Custom case for only signature-only protocol so far
2031 if (alproto == ALPROTO_HTTP) {
2034 } else if (alproto == ALPROTO_DOH2) {
2035 // DOH2 is not detected, just HTTP2
2037 } else {
2038 AppLayerProtoDetectPMGetIpprotos(alproto, ipprotos);
2039 AppLayerProtoDetectPPGetIpprotos(alproto, ipprotos);
2040 AppLayerProtoDetectPEGetIpprotos(alproto, ipprotos);
2041 }
2042
2043 SCReturn;
2044}
2045
2047{
2048 SCEnter();
2049
2050 AppLayerProtoDetectAliases *cur_alias = alpda_ctx;
2051 while (cur_alias != NULL) {
2052 if (strcasecmp(alproto_name, cur_alias->proto_alias) == 0) {
2053 alproto_name = cur_alias->proto_name;
2054 }
2055
2056 cur_alias = cur_alias->next;
2057 }
2058
2059 AppProto a;
2060 AppProto b = StringToAppProto(alproto_name);
2061 for (a = 0; a < g_alproto_max; a++) {
2062 if (alpd_ctx.alproto_names[a] != NULL && AppProtoEquals(b, a)) {
2063 // That means return HTTP_ANY if HTTP1 or HTTP2 is enabled
2064 SCReturnCT(b, "AppProto");
2065 }
2066 }
2067
2068 SCReturnCT(ALPROTO_UNKNOWN, "AppProto");
2069}
2070
2072{
2073 // Special case for http (any version) :
2074 // returns "http" if both versions are enabled
2075 // and returns "http1" or "http2" if only one version is enabled
2076 if (alproto == ALPROTO_HTTP) {
2077 if (alpd_ctx.alproto_names[ALPROTO_HTTP1]) {
2078 if (alpd_ctx.alproto_names[ALPROTO_HTTP2]) {
2079 return "http";
2080 } // else
2081 return alpd_ctx.alproto_names[ALPROTO_HTTP1];
2082 } // else
2083 return alpd_ctx.alproto_names[ALPROTO_HTTP2];
2084 }
2085 return alpd_ctx.alproto_names[alproto];
2086}
2087
2089{
2090 SCEnter();
2091
2092 memset(alprotos, 0, g_alproto_max * sizeof(AppProto));
2093
2094 int alproto;
2095
2096 for (alproto = 0; alproto != g_alproto_max; alproto++) {
2097 if (alpd_ctx.alproto_names[alproto] != NULL)
2098 alprotos[alproto] = 1;
2099 }
2100
2101 SCReturn;
2102}
2103
2104static void AppLayerProtoDetectPEGetIpprotos(AppProto alproto,
2105 uint8_t *ipprotos)
2106{
2107 if (alproto >= alpd_ctx.expectation_proto_len) {
2108 return;
2109 }
2110 if (alpd_ctx.expectation_proto[alproto] == IPPROTO_TCP) {
2111 ipprotos[IPPROTO_TCP / 8] |= 1 << (IPPROTO_TCP % 8);
2112 }
2113 if (alpd_ctx.expectation_proto[alproto] == IPPROTO_UDP) {
2114 ipprotos[IPPROTO_UDP / 8] |= 1 << (IPPROTO_UDP % 8);
2115 }
2116}
2117
2119{
2120 if (alpd_ctx.expectation_proto[alproto]) {
2121 if (proto != alpd_ctx.expectation_proto[alproto]) {
2122 SCLogError("Expectation on 2 IP protocols are not supported");
2123 }
2124 }
2125 alpd_ctx.expectation_proto[alproto] = proto;
2126}
2127
2128/***** Unittests *****/
2129
2130#ifdef UNITTESTS
2131
2132#include "app-layer-htp.h"
2133#include "detect-engine-alert.h"
2134
2135static AppLayerProtoDetectCtx alpd_ctx_ut;
2136
2138{
2139 SCEnter();
2140 alpd_ctx_ut = alpd_ctx;
2141 memset(&alpd_ctx, 0, sizeof(alpd_ctx));
2142 SCReturn;
2143}
2144
2146{
2147 SCEnter();
2148 alpd_ctx = alpd_ctx_ut;
2149 memset(&alpd_ctx_ut, 0, sizeof(alpd_ctx_ut));
2150 SCReturn;
2151}
2152
2153static int AppLayerProtoDetectTest01(void)
2154{
2157
2158 const char *buf = "HTTP";
2160 IPPROTO_TCP, ALPROTO_HTTP1, buf, 4, 0, STREAM_TOCLIENT);
2161 buf = "GET";
2163 IPPROTO_TCP, ALPROTO_HTTP1, buf, 4, 0, STREAM_TOSERVER);
2164
2166 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 1);
2167 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1);
2168
2171 PASS;
2172}
2173
2174static int AppLayerProtoDetectTest02(void)
2175{
2178
2179 const char *buf = "HTTP";
2181 IPPROTO_TCP, ALPROTO_HTTP1, buf, 4, 0, STREAM_TOCLIENT);
2182 buf = "ftp";
2183 SCAppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT);
2184
2186 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0);
2187 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2);
2188
2189 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL);
2190 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL);
2191
2194
2197 PASS;
2198}
2199
2200static int AppLayerProtoDetectTest03(void)
2201{
2204
2205 uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n";
2206 AppProto pm_results[g_alproto_max];
2207 memset(pm_results, 0, sizeof(pm_results));
2208 Flow f;
2209 memset(&f, 0x00, sizeof(f));
2210 f.protomap = FlowGetProtoMapping(IPPROTO_TCP);
2211
2212
2213 const char *buf = "HTTP";
2215 IPPROTO_TCP, ALPROTO_HTTP1, buf, 4, 0, STREAM_TOCLIENT);
2216 buf = "220 ";
2217 SCAppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT);
2218
2220 /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
2221 * it sets internal structures which depends on the above function. */
2224
2225 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0);
2226 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2);
2227 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL);
2228 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL);
2231
2232 bool rflow = false;
2233 uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
2234 &f, l7data, sizeof(l7data),
2235 STREAM_TOCLIENT,
2236 pm_results, &rflow);
2237 FAIL_IF(cnt != 1);
2238 FAIL_IF(pm_results[0] != ALPROTO_HTTP1);
2239
2243 PASS;
2244}
2245
2246static int AppLayerProtoDetectTest04(void)
2247{
2250
2251 uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n";
2252 Flow f;
2253 memset(&f, 0x00, sizeof(f));
2254 AppProto pm_results[g_alproto_max];
2255 memset(pm_results, 0, sizeof(pm_results));
2256 f.protomap = FlowGetProtoMapping(IPPROTO_TCP);
2257
2258 const char *buf = "200 ";
2260 IPPROTO_TCP, ALPROTO_HTTP1, buf, 13, 0, STREAM_TOCLIENT);
2261
2263 /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
2264 * it sets internal structures which depends on the above function. */
2267
2268 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0);
2269 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1);
2270 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL);
2271 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL);
2273
2274 bool rdir = false;
2275 uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
2276 &f, l7data, sizeof(l7data), STREAM_TOCLIENT,
2277 pm_results, &rdir);
2278 FAIL_IF(cnt != 1);
2279 FAIL_IF(pm_results[0] != ALPROTO_HTTP1);
2280
2284 PASS;
2285}
2286
2287static int AppLayerProtoDetectTest05(void)
2288{
2291
2292 uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n<HTML><BODY>Blahblah</BODY></HTML>";
2293 AppProto pm_results[g_alproto_max];
2294 memset(pm_results, 0, sizeof(pm_results));
2295 Flow f;
2296 memset(&f, 0x00, sizeof(f));
2297 f.protomap = FlowGetProtoMapping(IPPROTO_TCP);
2298
2299 const char *buf = "HTTP";
2301 IPPROTO_TCP, ALPROTO_HTTP1, buf, 4, 0, STREAM_TOCLIENT);
2302 buf = "220 ";
2303 SCAppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT);
2304
2306 /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
2307 * it sets internal structures which depends on the above function. */
2310
2311 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0);
2312 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2);
2313 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL);
2314 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL);
2317
2318 bool rdir = false;
2319 uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
2320 &f, l7data, sizeof(l7data),
2321 STREAM_TOCLIENT,
2322 pm_results, &rdir);
2323 FAIL_IF(cnt != 1);
2324 FAIL_IF(pm_results[0] != ALPROTO_HTTP1);
2325
2329 PASS;
2330}
2331
2332static int AppLayerProtoDetectTest06(void)
2333{
2336
2337 uint8_t l7data[] = "220 Welcome to the OISF FTP server\r\n";
2338 AppProto pm_results[g_alproto_max];
2339 memset(pm_results, 0, sizeof(pm_results));
2340 Flow f;
2341 memset(&f, 0x00, sizeof(f));
2342 f.protomap = FlowGetProtoMapping(IPPROTO_TCP);
2343
2344 const char *buf = "HTTP";
2346 IPPROTO_TCP, ALPROTO_HTTP1, buf, 4, 0, STREAM_TOCLIENT);
2347 buf = "220 ";
2348 SCAppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT);
2349
2351 /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
2352 * it sets internal structures which depends on the above function. */
2355
2356 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0);
2357 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2);
2358 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL);
2359 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL);
2362
2363 bool rdir = false;
2364 uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
2365 &f, l7data, sizeof(l7data), STREAM_TOCLIENT,
2366 pm_results, &rdir);
2367 FAIL_IF(cnt != 1);
2368 FAIL_IF(pm_results[0] != ALPROTO_FTP);
2369
2373 PASS;
2374}
2375
2376static int AppLayerProtoDetectTest07(void)
2377{
2380
2381 uint8_t l7data[] = "220 Welcome to the OISF HTTP/FTP server\r\n";
2382 Flow f;
2383 memset(&f, 0x00, sizeof(f));
2384 f.protomap = FlowGetProtoMapping(IPPROTO_TCP);
2385 AppProto pm_results[g_alproto_max];
2386 memset(pm_results, 0, sizeof(pm_results));
2387
2388 const char *buf = "HTTP";
2390 IPPROTO_TCP, ALPROTO_HTTP1, buf, 4, 0, STREAM_TOCLIENT);
2391
2393 /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
2394 * it sets internal structures which depends on the above function. */
2396
2397 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0);
2398 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1);
2399 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL);
2400 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL);
2402
2403 bool rdir = false;
2404 uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
2405 &f, l7data, sizeof(l7data), STREAM_TOCLIENT,
2406 pm_results, &rdir);
2407 FAIL_IF(cnt != 0);
2408
2412 PASS;
2413}
2414
2415static int AppLayerProtoDetectTest08(void)
2416{
2419
2420 uint8_t l7data[] = {
2421 0x00, 0x00, 0x00, 0x85, 0xff, 0x53, 0x4d, 0x42,
2422 0x72, 0x00, 0x00, 0x00, 0x00, 0x18, 0x53, 0xc8,
2423 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2424 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe,
2425 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x02,
2426 0x50, 0x43, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f,
2427 0x52, 0x4b, 0x20, 0x50, 0x52, 0x4f, 0x47, 0x52,
2428 0x41, 0x4d, 0x20, 0x31, 0x2e, 0x30, 0x00, 0x02,
2429 0x4c, 0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x31, 0x2e,
2430 0x30, 0x00, 0x02, 0x57, 0x69, 0x6e, 0x64, 0x6f,
2431 0x77, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x57,
2432 0x6f, 0x72, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70,
2433 0x73, 0x20, 0x33, 0x2e, 0x31, 0x61, 0x00, 0x02,
2434 0x4c, 0x4d, 0x31, 0x2e, 0x32, 0x58, 0x30, 0x30,
2435 0x32, 0x00, 0x02, 0x4c, 0x41, 0x4e, 0x4d, 0x41,
2436 0x4e, 0x32, 0x2e, 0x31, 0x00, 0x02, 0x4e, 0x54,
2437 0x20, 0x4c, 0x4d, 0x20, 0x30, 0x2e, 0x31, 0x32,
2438 0x00
2439 };
2440 AppProto pm_results[g_alproto_max];
2441 memset(pm_results, 0, sizeof(pm_results));
2442 Flow f;
2443 memset(&f, 0x00, sizeof(f));
2444 f.protomap = FlowGetProtoMapping(IPPROTO_TCP);
2445
2446 const char *buf = "|ff|SMB";
2447 SCAppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB, buf, 8, 4, STREAM_TOCLIENT);
2448
2450 /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
2451 * it sets internal structures which depends on the above function. */
2454
2455 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0);
2456 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1);
2457 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL);
2458 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL);
2460
2461 bool rdir = false;
2462 uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
2463 &f, l7data, sizeof(l7data), STREAM_TOCLIENT,
2464 pm_results, &rdir);
2465 FAIL_IF(cnt != 1);
2466 FAIL_IF(pm_results[0] != ALPROTO_SMB);
2467
2471 PASS;
2472}
2473
2474static int AppLayerProtoDetectTest09(void)
2475{
2478
2479 uint8_t l7data[] = {
2480 0x00, 0x00, 0x00, 0x66, 0xfe, 0x53, 0x4d, 0x42,
2481 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2482 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
2483 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2484 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2485 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2486 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2487 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2488 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x01, 0x00,
2489 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2490 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2491 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2492 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2493 0x00, 0x02, 0x02
2494 };
2495 AppProto pm_results[g_alproto_max];
2496 memset(pm_results, 0, sizeof(pm_results));
2497 Flow f;
2498 memset(&f, 0x00, sizeof(f));
2499 f.protomap = FlowGetProtoMapping(IPPROTO_TCP);
2500
2501 const char *buf = "|fe|SMB";
2502 SCAppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB, buf, 8, 4, STREAM_TOCLIENT);
2503
2505 /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
2506 * it sets internal structures which depends on the above function. */
2509
2510 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0);
2511 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1);
2512 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL);
2513 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL);
2515
2516 bool rdir = false;
2517 uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
2518 &f, l7data, sizeof(l7data), STREAM_TOCLIENT,
2519 pm_results, &rdir);
2520 FAIL_IF(cnt != 1);
2521 FAIL_IF(pm_results[0] != ALPROTO_SMB);
2522
2526 PASS;
2527}
2528
2529static int AppLayerProtoDetectTest10(void)
2530{
2533
2534 uint8_t l7data[] = {
2535 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00,
2536 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2537 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00,
2538 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
2539 0xb8, 0x4a, 0x9f, 0x4d, 0x1c, 0x7d, 0xcf, 0x11,
2540 0x86, 0x1e, 0x00, 0x20, 0xaf, 0x6e, 0x7c, 0x57,
2541 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a,
2542 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00,
2543 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00
2544 };
2545 AppProto pm_results[g_alproto_max];
2546 memset(pm_results, 0, sizeof(pm_results));
2547 Flow f;
2548 memset(&f, 0x00, sizeof(f));
2549 f.protomap = FlowGetProtoMapping(IPPROTO_TCP);
2550
2551 const char *buf = "|05 00|";
2553 IPPROTO_TCP, ALPROTO_DCERPC, buf, 4, 0, STREAM_TOCLIENT);
2554
2556 /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
2557 * it sets internal structures which depends on the above function. */
2560
2561 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0);
2562 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1);
2563 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL);
2564 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL);
2566
2567 bool rdir = false;
2568 uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
2569 &f, l7data, sizeof(l7data), STREAM_TOCLIENT,
2570 pm_results, &rdir);
2571 FAIL_IF(cnt != 1);
2572 FAIL_IF(pm_results[0] != ALPROTO_DCERPC);
2573
2577 PASS;
2578}
2579
2580/**
2581 * \test Why we still get http for connect... obviously because
2582 * we also match on the reply, duh
2583 */
2584static int AppLayerProtoDetectTest11(void)
2585{
2588
2589 uint8_t l7data[] = "CONNECT www.ssllabs.com:443 HTTP/1.0\r\n";
2590 uint8_t l7data_resp[] = "HTTP/1.1 405 Method Not Allowed\r\n";
2591 AppProto pm_results[g_alproto_max];
2592 memset(pm_results, 0, sizeof(pm_results));
2593 Flow f;
2594 memset(&f, 0x00, sizeof(f));
2595 f.protomap = FlowGetProtoMapping(IPPROTO_TCP);
2596
2598 IPPROTO_TCP, ALPROTO_HTTP1, "HTTP", 4, 0, STREAM_TOSERVER);
2600 IPPROTO_TCP, ALPROTO_HTTP1, "GET", 3, 0, STREAM_TOSERVER);
2602 IPPROTO_TCP, ALPROTO_HTTP1, "PUT", 3, 0, STREAM_TOSERVER);
2604 IPPROTO_TCP, ALPROTO_HTTP1, "POST", 4, 0, STREAM_TOSERVER);
2606 IPPROTO_TCP, ALPROTO_HTTP1, "TRACE", 5, 0, STREAM_TOSERVER);
2608 IPPROTO_TCP, ALPROTO_HTTP1, "OPTIONS", 7, 0, STREAM_TOSERVER);
2610 IPPROTO_TCP, ALPROTO_HTTP1, "CONNECT", 7, 0, STREAM_TOSERVER);
2612 IPPROTO_TCP, ALPROTO_HTTP1, "HTTP", 4, 0, STREAM_TOCLIENT);
2613
2615 /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
2616 * it sets internal structures which depends on the above function. */
2619
2620 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 7);
2621 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1);
2622 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map == NULL);
2623 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL);
2624
2633
2634 bool rdir = false;
2635 uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
2636 &f, l7data, sizeof(l7data), STREAM_TOSERVER,
2637 pm_results, &rdir);
2638 FAIL_IF(cnt != 1);
2639 FAIL_IF(pm_results[0] != ALPROTO_HTTP1);
2640
2641 memset(pm_results, 0, sizeof(pm_results));
2642 cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
2643 &f, l7data_resp, sizeof(l7data_resp), STREAM_TOCLIENT,
2644 pm_results, &rdir);
2645 FAIL_IF(cnt != 1);
2646 FAIL_IF(pm_results[0] != ALPROTO_HTTP1);
2647
2651 PASS;
2652}
2653
2654/**
2655 * \test AlpProtoSignature test
2656 */
2657static int AppLayerProtoDetectTest12(void)
2658{
2661
2662 int r = 0;
2663
2665 IPPROTO_TCP, ALPROTO_HTTP1, "HTTP", 4, 0, STREAM_TOSERVER);
2666 if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].head == NULL ||
2667 alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL)
2668 {
2669 printf("failure 1\n");
2670 goto end;
2671 }
2672
2674 if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 1) {
2675 printf("failure 2\n");
2676 goto end;
2677 }
2678 if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].head != NULL ||
2679 alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map == NULL)
2680 {
2681 printf("failure 3\n");
2682 goto end;
2683 }
2684 if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[0]->alproto != ALPROTO_HTTP1) {
2685 printf("failure 4\n");
2686 goto end;
2687 }
2688 if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[0]->cd->id != 0) {
2689 printf("failure 5\n");
2690 goto end;
2691 }
2692 if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[0]->next != NULL) {
2693 printf("failure 6\n");
2694 goto end;
2695 }
2696
2697 r = 1;
2698
2699 end:
2702 return r;
2703}
2704
2705/**
2706 * \test What about if we add some sigs only for udp but call for tcp?
2707 * It should not detect any proto
2708 */
2709static int AppLayerProtoDetectTest13(void)
2710{
2713
2714 uint8_t l7data[] = "CONNECT www.ssllabs.com:443 HTTP/1.0\r\n";
2715 uint8_t l7data_resp[] = "HTTP/1.1 405 Method Not Allowed\r\n";
2716 AppProto pm_results[g_alproto_max];
2717
2718 Flow f;
2719 memset(&f, 0x00, sizeof(f));
2720 f.protomap = FlowGetProtoMapping(IPPROTO_TCP);
2721
2723 IPPROTO_UDP, ALPROTO_HTTP1, "HTTP", 4, 0, STREAM_TOSERVER);
2725 IPPROTO_UDP, ALPROTO_HTTP1, "GET", 3, 0, STREAM_TOSERVER);
2727 IPPROTO_UDP, ALPROTO_HTTP1, "PUT", 3, 0, STREAM_TOSERVER);
2729 IPPROTO_UDP, ALPROTO_HTTP1, "POST", 4, 0, STREAM_TOSERVER);
2731 IPPROTO_UDP, ALPROTO_HTTP1, "TRACE", 5, 0, STREAM_TOSERVER);
2733 IPPROTO_UDP, ALPROTO_HTTP1, "OPTIONS", 7, 0, STREAM_TOSERVER);
2735 IPPROTO_UDP, ALPROTO_HTTP1, "CONNECT", 7, 0, STREAM_TOSERVER);
2737 IPPROTO_UDP, ALPROTO_HTTP1, "HTTP", 4, 0, STREAM_TOCLIENT);
2738
2740 /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
2741 * it sets internal structures which depends on the above function. */
2743
2744 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].max_pat_id != 7);
2745 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].max_pat_id != 1);
2746
2755
2756 memset(pm_results, 0, sizeof(pm_results));
2757 bool rdir = false;
2758 uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
2759 &f, l7data, sizeof(l7data), STREAM_TOSERVER,
2760 pm_results, &rdir);
2761 FAIL_IF(cnt != 0);
2762
2763 memset(pm_results, 0, sizeof(pm_results));
2764 cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
2765 &f, l7data_resp, sizeof(l7data_resp), STREAM_TOCLIENT,
2766 pm_results, &rdir);
2767 FAIL_IF(cnt != 0);
2768
2772 PASS;
2773}
2774
2775/**
2776 * \test What about if we add some sigs only for udp calling it for UDP?
2777 * It should detect ALPROTO_HTTP1 (over udp). This is just a check
2778 * to ensure that TCP/UDP differences work correctly.
2779 */
2780static int AppLayerProtoDetectTest14(void)
2781{
2784
2785 uint8_t l7data[] = "CONNECT www.ssllabs.com:443 HTTP/1.0\r\n";
2786 uint8_t l7data_resp[] = "HTTP/1.1 405 Method Not Allowed\r\n";
2787 AppProto pm_results[g_alproto_max];
2788 uint32_t cnt;
2789 Flow f;
2790 memset(&f, 0x00, sizeof(f));
2791 f.protomap = FlowGetProtoMapping(IPPROTO_UDP);
2792
2794 IPPROTO_UDP, ALPROTO_HTTP1, "HTTP", 4, 0, STREAM_TOSERVER);
2796 IPPROTO_UDP, ALPROTO_HTTP1, "GET", 3, 0, STREAM_TOSERVER);
2798 IPPROTO_UDP, ALPROTO_HTTP1, "PUT", 3, 0, STREAM_TOSERVER);
2800 IPPROTO_UDP, ALPROTO_HTTP1, "POST", 4, 0, STREAM_TOSERVER);
2802 IPPROTO_UDP, ALPROTO_HTTP1, "TRACE", 5, 0, STREAM_TOSERVER);
2804 IPPROTO_UDP, ALPROTO_HTTP1, "OPTIONS", 7, 0, STREAM_TOSERVER);
2806 IPPROTO_UDP, ALPROTO_HTTP1, "CONNECT", 7, 0, STREAM_TOSERVER);
2808 IPPROTO_UDP, ALPROTO_HTTP1, "HTTP", 4, 0, STREAM_TOCLIENT);
2809
2811 /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
2812 * it sets internal structures which depends on the above function. */
2815
2816 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].max_pat_id != 7);
2817 FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].max_pat_id != 1);
2818
2827
2828 memset(pm_results, 0, sizeof(pm_results));
2829 bool rdir = false;
2830 cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
2831 &f, l7data, sizeof(l7data), STREAM_TOSERVER,
2832 pm_results, &rdir);
2833 FAIL_IF(cnt != 1);
2834 FAIL_IF(pm_results[0] != ALPROTO_HTTP1);
2835
2836 memset(pm_results, 0, sizeof(pm_results));
2837 cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
2838 &f, l7data_resp, sizeof(l7data_resp), STREAM_TOCLIENT,
2839 pm_results, &rdir);
2840 FAIL_IF(cnt != 1);
2841 FAIL_IF(pm_results[0] != ALPROTO_HTTP1);
2842
2846 PASS;
2847}
2848
2856
2867
2868
2875
2876static int AppLayerProtoDetectPPTestData(AppLayerProtoDetectProbingParser *pp,
2878 int no_of_ip_proto)
2879{
2880 int result = 0;
2881 int i = -1, j = -1 , k = -1;
2882#ifdef DEBUG
2883 int dir = 0;
2884#endif
2885 for (i = 0; i < no_of_ip_proto; i++, pp = pp->next) {
2886 if (pp->ipproto != ip_proto[i].ipproto)
2887 goto end;
2888
2890 for (k = 0; k < ip_proto[i].no_of_port; k++, pp_port = pp_port->next) {
2891 if (pp_port->port != ip_proto[i].port[k].port)
2892 goto end;
2893 if (pp_port->dp_max_depth != ip_proto[i].port[k].dp_max_depth)
2894 goto end;
2895 if (pp_port->sp_max_depth != ip_proto[i].port[k].sp_max_depth)
2896 goto end;
2897
2898 AppLayerProtoDetectProbingParserElement *pp_element = pp_port->dp;
2899#ifdef DEBUG
2900 dir = 0;
2901#endif
2902 for (j = 0 ; j < ip_proto[i].port[k].ts_no_of_element;
2903 j++, pp_element = pp_element->next) {
2904
2905 if (pp_element->alproto != ip_proto[i].port[k].toserver_element[j].alproto) {
2906 goto end;
2907 }
2908 if (pp_element->min_depth != ip_proto[i].port[k].toserver_element[j].min_depth) {
2909 goto end;
2910 }
2911 if (pp_element->max_depth != ip_proto[i].port[k].toserver_element[j].max_depth) {
2912 goto end;
2913 }
2914 } /* for */
2915 if (pp_element != NULL)
2916 goto end;
2917
2918 pp_element = pp_port->sp;
2919#ifdef DEBUG
2920 dir = 1;
2921#endif
2922 for (j = 0 ; j < ip_proto[i].port[k].tc_no_of_element; j++, pp_element = pp_element->next) {
2923 if (pp_element->alproto != ip_proto[i].port[k].toclient_element[j].alproto) {
2924 goto end;
2925 }
2926 if (pp_element->min_depth != ip_proto[i].port[k].toclient_element[j].min_depth) {
2927 goto end;
2928 }
2929 if (pp_element->max_depth != ip_proto[i].port[k].toclient_element[j].max_depth) {
2930 goto end;
2931 }
2932 } /* for */
2933 if (pp_element != NULL)
2934 goto end;
2935 }
2936 if (pp_port != NULL)
2937 goto end;
2938 }
2939 if (pp != NULL)
2940 goto end;
2941
2942 result = 1;
2943 end:
2944#ifdef DEBUG
2945 printf("i = %d, k = %d, j = %d(%s)\n", i, k, j, (dir == 0) ? "ts" : "tc");
2946#endif
2947 return result;
2948}
2949
2950static uint16_t ProbingParserDummyForTesting(
2951 const Flow *f, uint8_t direction, const uint8_t *input, uint32_t input_len, uint8_t *rdir)
2952{
2953 return 0;
2954}
2955
2956static int AppLayerProtoDetectTest15(void)
2957{
2960
2961 int result = 0;
2962
2963 SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_HTTP1, 5, 8, STREAM_TOSERVER,
2964 ProbingParserDummyForTesting, NULL);
2965 SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_SMB, 5, 6, STREAM_TOSERVER,
2966 ProbingParserDummyForTesting, NULL);
2967 SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_FTP, 7, 10, STREAM_TOSERVER,
2968 ProbingParserDummyForTesting, NULL);
2969
2970 SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "81", ALPROTO_DCERPC, 9, 10, STREAM_TOSERVER,
2971 ProbingParserDummyForTesting, NULL);
2972 SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "81", ALPROTO_FTP, 7, 15, STREAM_TOSERVER,
2973 ProbingParserDummyForTesting, NULL);
2974 SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_SMTP, 12, 0, STREAM_TOSERVER,
2975 ProbingParserDummyForTesting, NULL);
2976 SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_TLS, 12, 18, STREAM_TOSERVER,
2977 ProbingParserDummyForTesting, NULL);
2978
2979 SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "85", ALPROTO_DCERPC, 9, 10, STREAM_TOSERVER,
2980 ProbingParserDummyForTesting, NULL);
2981 SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "85", ALPROTO_FTP, 7, 15, STREAM_TOSERVER,
2982 ProbingParserDummyForTesting, NULL);
2983 result = 1;
2984
2985 SCAppLayerProtoDetectPPRegister(IPPROTO_UDP, "85", ALPROTO_IMAP, 12, 23, STREAM_TOSERVER,
2986 ProbingParserDummyForTesting, NULL);
2987
2988 /* toclient */
2989 SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_JABBER, 12, 23, STREAM_TOCLIENT,
2990 ProbingParserDummyForTesting, NULL);
2991 SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_IRC, 12, 14, STREAM_TOCLIENT,
2992 ProbingParserDummyForTesting, NULL);
2993
2994 SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "85", ALPROTO_DCERPC, 9, 10, STREAM_TOCLIENT,
2995 ProbingParserDummyForTesting, NULL);
2996 SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "81", ALPROTO_FTP, 7, 15, STREAM_TOCLIENT,
2997 ProbingParserDummyForTesting, NULL);
2998 SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_TLS, 12, 18, STREAM_TOCLIENT,
2999 ProbingParserDummyForTesting, NULL);
3000 SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_HTTP1, 5, 8, STREAM_TOCLIENT,
3001 ProbingParserDummyForTesting, NULL);
3002 SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "81", ALPROTO_DCERPC, 9, 10, STREAM_TOCLIENT,
3003 ProbingParserDummyForTesting, NULL);
3004 SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "90", ALPROTO_FTP, 7, 15, STREAM_TOCLIENT,
3005 ProbingParserDummyForTesting, NULL);
3006 SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_SMB, 5, 6, STREAM_TOCLIENT,
3007 ProbingParserDummyForTesting, NULL);
3008 SCAppLayerProtoDetectPPRegister(IPPROTO_UDP, "85", ALPROTO_IMAP, 12, 23, STREAM_TOCLIENT,
3009 ProbingParserDummyForTesting, NULL);
3010 SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_SMTP, 12, 17, STREAM_TOCLIENT,
3011 ProbingParserDummyForTesting, NULL);
3012 SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_FTP, 7, 10, STREAM_TOCLIENT,
3013 ProbingParserDummyForTesting, NULL);
3014
3015 AppLayerProtoDetectPPTestDataElement element_ts_80[] = {
3016 { "http", ALPROTO_HTTP1, 80, 5, 8 },
3017 { "smb", ALPROTO_SMB, 80, 5, 6 },
3018 { "ftp", ALPROTO_FTP, 80, 7, 10 },
3019 { "smtp", ALPROTO_SMTP, 0, 12, 0 },
3020 { "tls", ALPROTO_TLS, 0, 12, 18 },
3021 { "irc", ALPROTO_IRC, 0, 12, 25 },
3022 { "jabber", ALPROTO_JABBER, 0, 12, 23 },
3023 };
3024 AppLayerProtoDetectPPTestDataElement element_tc_80[] = { { "http", ALPROTO_HTTP1, 80, 5, 8 },
3025 { "smb", ALPROTO_SMB, 80, 5, 6 }, { "ftp", ALPROTO_FTP, 80, 7, 10 },
3026 { "jabber", ALPROTO_JABBER, 0, 12, 23 }, { "irc", ALPROTO_IRC, 0, 12, 14 },
3027 { "tls", ALPROTO_TLS, 0, 12, 18 }, { "smtp", ALPROTO_SMTP, 0, 12, 17 } };
3028
3029 AppLayerProtoDetectPPTestDataElement element_ts_81[] = {
3030 { "dcerpc", ALPROTO_DCERPC, 81, 9, 10 },
3031 { "ftp", ALPROTO_FTP, 81, 7, 15 },
3032 { "smtp", ALPROTO_SMTP, 0, 12, 0 },
3033 { "tls", ALPROTO_TLS, 0, 12, 18 },
3034 { "irc", ALPROTO_IRC, 0, 12, 25 },
3035 { "jabber", ALPROTO_JABBER, 0, 12, 23 },
3036 };
3037 AppLayerProtoDetectPPTestDataElement element_tc_81[] = { { "ftp", ALPROTO_FTP, 81, 7, 15 },
3038 { "dcerpc", ALPROTO_DCERPC, 81, 9, 10 }, { "jabber", ALPROTO_JABBER, 0, 12, 23 },
3039 { "irc", ALPROTO_IRC, 0, 12, 14 }, { "tls", ALPROTO_TLS, 0, 12, 18 },
3040 { "smtp", ALPROTO_SMTP, 0, 12, 17 } };
3041
3042 AppLayerProtoDetectPPTestDataElement element_ts_85[] = {
3043 { "dcerpc", ALPROTO_DCERPC, 85, 9, 10 },
3044 { "ftp", ALPROTO_FTP, 85, 7, 15 },
3045 { "smtp", ALPROTO_SMTP, 0, 12, 0 },
3046 { "tls", ALPROTO_TLS, 0, 12, 18 },
3047 { "irc", ALPROTO_IRC, 0, 12, 25 },
3048 { "jabber", ALPROTO_JABBER, 0, 12, 23 },
3049 };
3050 AppLayerProtoDetectPPTestDataElement element_tc_85[] = { { "dcerpc", ALPROTO_DCERPC, 85, 9,
3051 10 },
3052 { "jabber", ALPROTO_JABBER, 0, 12, 23 }, { "irc", ALPROTO_IRC, 0, 12, 14 },
3053 { "tls", ALPROTO_TLS, 0, 12, 18 }, { "smtp", ALPROTO_SMTP, 0, 12, 17 } };
3054
3055 AppLayerProtoDetectPPTestDataElement element_ts_90[] = {
3056 { "smtp", ALPROTO_SMTP, 0, 12, 0 },
3057 { "tls", ALPROTO_TLS, 0, 12, 18 },
3058 { "irc", ALPROTO_IRC, 0, 12, 25 },
3059 { "jabber", ALPROTO_JABBER, 0, 12, 23 },
3060 };
3061 AppLayerProtoDetectPPTestDataElement element_tc_90[] = { { "ftp", ALPROTO_FTP, 90, 7, 15 },
3062 { "jabber", ALPROTO_JABBER, 0, 12, 23 }, { "irc", ALPROTO_IRC, 0, 12, 14 },
3063 { "tls", ALPROTO_TLS, 0, 12, 18 }, { "smtp", ALPROTO_SMTP, 0, 12, 17 } };
3064
3065 AppLayerProtoDetectPPTestDataElement element_ts_0[] = {
3066 { "smtp", ALPROTO_SMTP, 0, 12, 0 },
3067 { "tls", ALPROTO_TLS, 0, 12, 18 },
3068 { "irc", ALPROTO_IRC, 0, 12, 25 },
3069 { "jabber", ALPROTO_JABBER, 0, 12, 23 },
3070 };
3071 AppLayerProtoDetectPPTestDataElement element_tc_0[] = { { "jabber", ALPROTO_JABBER, 0, 12, 23 },
3072 { "irc", ALPROTO_IRC, 0, 12, 14 }, { "tls", ALPROTO_TLS, 0, 12, 18 },
3073 { "smtp", ALPROTO_SMTP, 0, 12, 17 } };
3074
3075 AppLayerProtoDetectPPTestDataElement element_ts_85_udp[] = {
3076 { "imap", ALPROTO_IMAP, 85, 12, 23 },
3077 };
3078 AppLayerProtoDetectPPTestDataElement element_tc_85_udp[] = {
3079 { "imap", ALPROTO_IMAP, 85, 12, 23 },
3080 };
3081
3082 AppLayerProtoDetectPPTestDataPort ports_tcp[] = {
3083 {
3084 80,
3085 23,
3086 23,
3087 element_ts_80,
3088 element_tc_80,
3089 sizeof(element_ts_80) / sizeof(AppLayerProtoDetectPPTestDataElement),
3090 sizeof(element_tc_80) / sizeof(AppLayerProtoDetectPPTestDataElement),
3091 },
3092 {
3093 81,
3094 23,
3095 23,
3096 element_ts_81,
3097 element_tc_81,
3098 sizeof(element_ts_81) / sizeof(AppLayerProtoDetectPPTestDataElement),
3099 sizeof(element_tc_81) / sizeof(AppLayerProtoDetectPPTestDataElement),
3100 },
3101 { 85, 23, 23, element_ts_85, element_tc_85,
3102 sizeof(element_ts_85) / sizeof(AppLayerProtoDetectPPTestDataElement),
3103 sizeof(element_tc_85) / sizeof(AppLayerProtoDetectPPTestDataElement) },
3104 { 90, 23, 23, element_ts_90, element_tc_90,
3105 sizeof(element_ts_90) / sizeof(AppLayerProtoDetectPPTestDataElement),
3106 sizeof(element_tc_90) / sizeof(AppLayerProtoDetectPPTestDataElement) },
3107 { 0, 23, 23, element_ts_0, element_tc_0,
3108 sizeof(element_ts_0) / sizeof(AppLayerProtoDetectPPTestDataElement),
3109 sizeof(element_tc_0) / sizeof(AppLayerProtoDetectPPTestDataElement) }
3110 };
3111
3112 AppLayerProtoDetectPPTestDataPort ports_udp[] = {
3113 {
3114 85,
3115 23,
3116 23,
3117 element_ts_85_udp,
3118 element_tc_85_udp,
3119 sizeof(element_ts_85_udp) / sizeof(AppLayerProtoDetectPPTestDataElement),
3120 sizeof(element_tc_85_udp) / sizeof(AppLayerProtoDetectPPTestDataElement),
3121 },
3122 };
3123
3125 { IPPROTO_TCP,
3126 ports_tcp,
3127 sizeof(ports_tcp) / sizeof(AppLayerProtoDetectPPTestDataPort),
3128 },
3129 { IPPROTO_UDP,
3130 ports_udp,
3131 sizeof(ports_udp) / sizeof(AppLayerProtoDetectPPTestDataPort),
3132 },
3133 };
3134
3135
3136 if (AppLayerProtoDetectPPTestData(alpd_ctx.ctx_pp, ip_proto,
3137 sizeof(ip_proto) / sizeof(AppLayerProtoDetectPPTestDataIPProto)) == 0) {
3138 goto end;
3139 }
3140 result = 1;
3141
3142 end:
3145 return result;
3146}
3147
3148
3149/** \test test if the engine detect the proto and match with it */
3150static int AppLayerProtoDetectTest16(void)
3151{
3152 int result = 0;
3153 Flow *f = NULL;
3154 HtpState *http_state = NULL;
3155 uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n"
3156 "User-Agent: Mozilla/1.0\r\n"
3157 "Cookie: hellocatch\r\n\r\n";
3158 uint32_t http_buf1_len = sizeof(http_buf1) - 1;
3159 TcpSession ssn;
3160 Packet *p = NULL;
3161 Signature *s = NULL;
3162 ThreadVars tv;
3163 DetectEngineThreadCtx *det_ctx = NULL;
3164 DetectEngineCtx *de_ctx = NULL;
3166
3167 memset(&tv, 0, sizeof(ThreadVars));
3168 memset(&ssn, 0, sizeof(TcpSession));
3169
3170 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
3171 if (p == NULL) {
3172 printf("packet setup failed: ");
3173 goto end;
3174 }
3175
3176 f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80);
3177 if (f == NULL) {
3178 printf("flow setup failed: ");
3179 goto end;
3180 }
3181 f->protoctx = &ssn;
3182 f->proto = IPPROTO_TCP;
3183 p->flow = f;
3184
3188
3190
3191 StreamTcpInitConfig(true);
3192
3194 if (de_ctx == NULL) {
3195 goto end;
3196 }
3197 de_ctx->flags |= DE_QUIET;
3198
3199 s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any "
3200 "(msg:\"Test content option\"; "
3201 "sid:1;)");
3202 if (s == NULL) {
3203 goto end;
3204 }
3205
3207 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
3208
3209 int r = AppLayerParserParse(
3210 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, http_buf1, http_buf1_len);
3211 if (r != 0) {
3212 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
3213 goto end;
3214 }
3215
3216 http_state = f->alstate;
3217 if (http_state == NULL) {
3218 printf("no http state: ");
3219 goto end;
3220 }
3221
3222 /* do detect */
3223 SigMatchSignatures(&tv, de_ctx, det_ctx, p);
3224
3225 if (!PacketAlertCheck(p, 1)) {
3226 printf("sig 1 didn't alert, but it should: ");
3227 goto end;
3228 }
3229 result = 1;
3230 end:
3231 if (alp_tctx != NULL)
3233 if (det_ctx != NULL)
3235 if (de_ctx != NULL)
3237 if (de_ctx != NULL)
3239
3240 StreamTcpFreeConfig(true);
3241
3242 UTHFreePackets(&p, 1);
3243 UTHFreeFlow(f);
3244 return result;
3245}
3246
3247/** \test test if the engine detect the proto on a non standar port
3248 * and match with it */
3249static int AppLayerProtoDetectTest17(void)
3250{
3251 int result = 0;
3252 Flow *f = NULL;
3253 HtpState *http_state = NULL;
3254 uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n"
3255 "User-Agent: Mozilla/1.0\r\n"
3256 "Cookie: hellocatch\r\n\r\n";
3257 uint32_t http_buf1_len = sizeof(http_buf1) - 1;
3258 TcpSession ssn;
3259 Packet *p = NULL;
3260 Signature *s = NULL;
3261 ThreadVars tv;
3262 DetectEngineThreadCtx *det_ctx = NULL;
3263 DetectEngineCtx *de_ctx = NULL;
3265
3266 memset(&tv, 0, sizeof(ThreadVars));
3267 memset(&ssn, 0, sizeof(TcpSession));
3268
3269 p = UTHBuildPacketSrcDstPorts(http_buf1, http_buf1_len, IPPROTO_TCP, 12345, 88);
3270
3271 f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80);
3272 if (f == NULL)
3273 goto end;
3274 f->protoctx = &ssn;
3275 f->proto = IPPROTO_TCP;
3276 p->flow = f;
3281
3282 StreamTcpInitConfig(true);
3283
3285 if (de_ctx == NULL) {
3286 goto end;
3287 }
3288 de_ctx->flags |= DE_QUIET;
3289
3290 s = de_ctx->sig_list = SigInit(de_ctx, "alert http any !80 -> any any "
3291 "(msg:\"http over non standar port\"; "
3292 "sid:1;)");
3293 if (s == NULL) {
3294 goto end;
3295 }
3296
3298 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
3299
3300 int r = AppLayerParserParse(
3301 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, http_buf1, http_buf1_len);
3302 if (r != 0) {
3303 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
3304 goto end;
3305 }
3306
3307 http_state = f->alstate;
3308 if (http_state == NULL) {
3309 printf("no http state: ");
3310 goto end;
3311 }
3312
3313 /* do detect */
3314 SigMatchSignatures(&tv, de_ctx, det_ctx, p);
3315
3316 if (!PacketAlertCheck(p, 1)) {
3317 printf("sig 1 didn't alert, but it should: ");
3318 goto end;
3319 }
3320
3321 result = 1;
3322
3323 end:
3324 if (alp_tctx != NULL)
3326 if (det_ctx != NULL)
3328 if (de_ctx != NULL)
3330 if (de_ctx != NULL)
3332
3333 StreamTcpFreeConfig(true);
3334
3335 UTHFreePackets(&p, 1);
3336 UTHFreeFlow(f);
3337 return result;
3338}
3339
3340/** \test test if the engine detect the proto and doesn't match
3341 * because the sig expects another proto (ex ftp)*/
3342static int AppLayerProtoDetectTest18(void)
3343{
3344 int result = 0;
3345 Flow *f = NULL;
3346 HtpState *http_state = NULL;
3347 uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n"
3348 "User-Agent: Mozilla/1.0\r\n"
3349 "Cookie: hellocatch\r\n\r\n";
3350 uint32_t http_buf1_len = sizeof(http_buf1) - 1;
3351 TcpSession ssn;
3352 Packet *p = NULL;
3353 Signature *s = NULL;
3354 ThreadVars tv;
3355 DetectEngineThreadCtx *det_ctx = NULL;
3356 DetectEngineCtx *de_ctx = NULL;
3358
3359 memset(&tv, 0, sizeof(ThreadVars));
3360 memset(&ssn, 0, sizeof(TcpSession));
3361
3362 p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP);
3363
3364 f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80);
3365 if (f == NULL)
3366 goto end;
3367 f->protoctx = &ssn;
3368 f->proto = IPPROTO_TCP;
3369 p->flow = f;
3374
3375 StreamTcpInitConfig(true);
3376
3378 if (de_ctx == NULL) {
3379 goto end;
3380 }
3381 de_ctx->flags |= DE_QUIET;
3382
3383 s = de_ctx->sig_list = SigInit(de_ctx, "alert ftp any any -> any any "
3384 "(msg:\"Test content option\"; "
3385 "sid:1;)");
3386 if (s == NULL) {
3387 goto end;
3388 }
3389
3391 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
3392
3393 int r = AppLayerParserParse(
3394 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, http_buf1, http_buf1_len);
3395 if (r != 0) {
3396 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
3397 goto end;
3398 }
3399
3400 http_state = f->alstate;
3401 if (http_state == NULL) {
3402 printf("no http state: ");
3403 goto end;
3404 }
3405
3406 /* do detect */
3407 SigMatchSignatures(&tv, de_ctx, det_ctx, p);
3408
3409 if (PacketAlertCheck(p, 1)) {
3410 printf("sig 1 alerted, but it should not (it's not ftp): ");
3411 goto end;
3412 }
3413
3414 result = 1;
3415 end:
3416 if (alp_tctx != NULL)
3418 if (det_ctx != NULL)
3420 if (de_ctx != NULL)
3422 if (de_ctx != NULL)
3424
3425 StreamTcpFreeConfig(true);
3426
3427 UTHFreePackets(&p, 1);
3428 UTHFreeFlow(f);
3429 return result;
3430}
3431
3432/** \test test if the engine detect the proto and doesn't match
3433 * because the packet has another proto (ex ftp) */
3434static int AppLayerProtoDetectTest19(void)
3435{
3436 int result = 0;
3437 Flow *f = NULL;
3438 uint8_t http_buf1[] = "MPUT one\r\n";
3439 uint32_t http_buf1_len = sizeof(http_buf1) - 1;
3440 TcpSession ssn;
3441 Packet *p = NULL;
3442 Signature *s = NULL;
3443 ThreadVars tv;
3444 DetectEngineThreadCtx *det_ctx = NULL;
3445 DetectEngineCtx *de_ctx = NULL;
3447
3448 memset(&tv, 0, sizeof(ThreadVars));
3449 memset(&ssn, 0, sizeof(TcpSession));
3450
3451 p = UTHBuildPacketSrcDstPorts(http_buf1, http_buf1_len, IPPROTO_TCP, 12345, 88);
3452
3453 f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80);
3454 if (f == NULL)
3455 goto end;
3456 f->protoctx = &ssn;
3457 f->proto = IPPROTO_TCP;
3458 p->flow = f;
3462 f->alproto = ALPROTO_FTP;
3463
3464 StreamTcpInitConfig(true);
3465
3467 if (de_ctx == NULL) {
3468 goto end;
3469 }
3470 de_ctx->flags |= DE_QUIET;
3471
3472 s = de_ctx->sig_list = SigInit(de_ctx, "alert http any !80 -> any any "
3473 "(msg:\"http over non standar port\"; "
3474 "sid:1;)");
3475 if (s == NULL) {
3476 goto end;
3477 }
3478
3480 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
3481
3482 int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_FTP,
3483 STREAM_TOSERVER, http_buf1, http_buf1_len);
3484 if (r != 0) {
3485 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
3486 goto end;
3487 }
3488
3489 /* do detect */
3490 SigMatchSignatures(&tv, de_ctx, det_ctx, p);
3491
3492 if (PacketAlertCheck(p, 1)) {
3493 printf("sig 1 alerted, but it should not (it's ftp): ");
3494 goto end;
3495 }
3496
3497 result = 1;
3498
3499 end:
3500 if (alp_tctx != NULL)
3502 if (det_ctx != NULL)
3504 if (de_ctx != NULL)
3506 if (de_ctx != NULL)
3508
3509 StreamTcpFreeConfig(true);
3510 UTHFreePackets(&p, 1);
3511 UTHFreeFlow(f);
3512 return result;
3513}
3514
3516{
3517 SCEnter();
3518
3519 UtRegisterTest("AppLayerProtoDetectTest01", AppLayerProtoDetectTest01);
3520 UtRegisterTest("AppLayerProtoDetectTest02", AppLayerProtoDetectTest02);
3521 UtRegisterTest("AppLayerProtoDetectTest03", AppLayerProtoDetectTest03);
3522 UtRegisterTest("AppLayerProtoDetectTest04", AppLayerProtoDetectTest04);
3523 UtRegisterTest("AppLayerProtoDetectTest05", AppLayerProtoDetectTest05);
3524 UtRegisterTest("AppLayerProtoDetectTest06", AppLayerProtoDetectTest06);
3525 UtRegisterTest("AppLayerProtoDetectTest07", AppLayerProtoDetectTest07);
3526 UtRegisterTest("AppLayerProtoDetectTest08", AppLayerProtoDetectTest08);
3527 UtRegisterTest("AppLayerProtoDetectTest09", AppLayerProtoDetectTest09);
3528 UtRegisterTest("AppLayerProtoDetectTest10", AppLayerProtoDetectTest10);
3529 UtRegisterTest("AppLayerProtoDetectTest11", AppLayerProtoDetectTest11);
3530 UtRegisterTest("AppLayerProtoDetectTest12", AppLayerProtoDetectTest12);
3531 UtRegisterTest("AppLayerProtoDetectTest13", AppLayerProtoDetectTest13);
3532 UtRegisterTest("AppLayerProtoDetectTest14", AppLayerProtoDetectTest14);
3533 UtRegisterTest("AppLayerProtoDetectTest15", AppLayerProtoDetectTest15);
3534 UtRegisterTest("AppLayerProtoDetectTest16", AppLayerProtoDetectTest16);
3535 UtRegisterTest("AppLayerProtoDetectTest17", AppLayerProtoDetectTest17);
3536 UtRegisterTest("AppLayerProtoDetectTest18", AppLayerProtoDetectTest18);
3537 UtRegisterTest("AppLayerProtoDetectTest19", AppLayerProtoDetectTest19);
3538
3539 SCReturn;
3540}
3541
3542#endif /* UNITTESTS */
void AppLayerProtoDetectSupportedAppProtocols(AppProto *alprotos)
struct AppLayerProtoDetectProbingParserPort_ AppLayerProtoDetectProbingParserPort
void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_name)
Registers a protocol for protocol detection phase.
int SCAppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, uint8_t ipproto, const char *alproto_name, AppProto alproto, uint16_t min_depth, uint16_t max_depth, ProbingParserFPtr ProbingParserTs, ProbingParserFPtr ProbingParserTc)
void SCAppLayerProtoDetectPPRegister(uint8_t ipproto, const char *portstr, AppProto alproto, uint16_t min_depth, uint16_t max_depth, uint8_t direction, ProbingParserFPtr ProbingParser1, ProbingParserFPtr ProbingParser2)
register parser at a port
struct AppLayerProtoDetectAliases_ AppLayerProtoDetectAliases
int SCAppLayerProtoDetectPMRegisterPatternCSwPP(uint8_t ipproto, AppProto alproto, const char *pattern, uint16_t depth, uint16_t offset, uint8_t direction, ProbingParserFPtr PPFunc, uint16_t pp_min_depth, uint16_t pp_max_depth)
AppProto AppLayerProtoDetectGetProto(AppLayerProtoDetectThreadCtx *tctx, Flow *f, const uint8_t *buf, uint32_t buflen, uint8_t ipproto, uint8_t flags, bool *reverse_flow)
Returns the app layer protocol given a buffer.
int AppLayerProtoDetectDeSetup(void)
Cleans up the app layer protocol detection phase.
int SCAppLayerProtoDetectConfProtoDetectionEnabledDefault(const char *ipproto, const char *alproto, bool default_enabled)
Given a protocol name, checks if proto detection is enabled in the conf file.
AppLayerProtoDetectThreadCtx * AppLayerProtoDetectGetCtxThread(void)
Inits and returns an app layer protocol detection thread context.
void AppLayerProtoDetectSupportedIpprotos(AppProto alproto, uint8_t *ipprotos)
void AppLayerProtoDetectUnittestCtxBackup(void)
Backs up the internal context used by the app layer proto detection module.
void AppLayerProtoDetectReset(Flow *f)
Reset proto detect for flow.
int AppLayerProtoDetectSetup(void)
The first function to be called. This initializes a global protocol detection context.
struct AppLayerProtoDetectProbingParserElement_ AppLayerProtoDetectProbingParserElement
bool AppLayerRequestProtocolChange(Flow *f, uint16_t dp, AppProto expect_proto)
request applayer to wrap up this protocol and rerun protocol detection.
int AppLayerProtoDetectPrepareState(void)
Prepares the internal state for protocol detection. This needs to be called once all the patterns and...
struct AppLayerProtoDetectProbingParser_ AppLayerProtoDetectProbingParser
struct AppLayerProtoDetectPMCtx_ AppLayerProtoDetectPMCtx
int SCAppLayerProtoDetectPMRegisterPatternCI(uint8_t ipproto, AppProto alproto, const char *pattern, uint16_t depth, uint16_t offset, uint8_t direction)
Registers a case-insensitive pattern for protocol detection.
void SCAppLayerForceProtocolChange(Flow *f, AppProto new_proto)
Forces a flow app-layer protocol change. Happens for instance when a HTTP2 flow is seen as DOH2.
struct AppLayerProtoDetectCtxIpproto_ AppLayerProtoDetectCtxIpproto
struct AppLayerProtoDetectCtx_ AppLayerProtoDetectCtx
The app layer protocol detection context.
void AppLayerProtoDetectRegisterAlias(const char *proto_name, const char *proto_alias)
struct AppLayerProtoDetectPPTestDataPort_ AppLayerProtoDetectPPTestDataPort
const char * AppLayerProtoDetectGetProtoName(AppProto alproto)
void AppLayerProtoDetectUnittestsRegister(void)
Register unittests for app layer proto detection module.
int SCAppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, const char *alproto)
Given a protocol name, checks if proto detection is enabled in the conf file.
struct AppLayerProtoDetectPPTestDataIPProto_ AppLayerProtoDetectPPTestDataIPProto
int SCAppLayerProtoDetectPMRegisterPatternCS(uint8_t ipproto, AppProto alproto, const char *pattern, uint16_t depth, uint16_t offset, uint8_t direction)
Registers a case-sensitive pattern for protocol detection.
AppProto AppLayerProtoDetectGetProtoByName(const char *alproto_name)
void AppLayerProtoDetectUnittestCtxRestore(void)
Restores back the internal context used by the app layer proto detection module, that was previously ...
void AppLayerRegisterExpectationProto(uint8_t proto, AppProto alproto)
struct AppLayerProtoDetectPMSignature_ AppLayerProtoDetectPMSignature
struct AppLayerProtoDetectPPTestDataElement_ AppLayerProtoDetectPPTestDataElement
bool SCAppLayerRequestProtocolTLSUpgrade(Flow *f)
request applayer to wrap up this protocol and rerun protocol detection with expectation of TLS....
void AppLayerProtoDetectDestroyCtxThread(AppLayerProtoDetectThreadCtx *alpd_tctx)
Destroys the app layer protocol detection thread context.
AppProto(* ProbingParserFPtr)(const Flow *f, uint8_t flags, const uint8_t *input, uint32_t input_len, uint8_t *rdir)
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol's parser thread context.
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, const uint8_t *input, uint32_t input_len)
AppProto g_alproto_max
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its string equivalent.
AppProto StringToAppProto(const char *proto_name)
Maps a string to its ALPROTO_* equivalent.
uint16_t AppProto
@ ALPROTO_TLS
@ ALPROTO_DCERPC
@ ALPROTO_IRC
@ ALPROTO_JABBER
@ ALPROTO_HTTP2
@ ALPROTO_FAILED
@ ALPROTO_FTP
@ ALPROTO_SMTP
@ ALPROTO_HTTP
@ ALPROTO_SMB
@ ALPROTO_UNKNOWN
@ ALPROTO_DOH2
@ ALPROTO_HTTP1
@ ALPROTO_IMAP
SCConfNode * SCConfNodeLookupChild(const SCConfNode *node, const char *name)
Lookup a child configuration node by name.
Definition conf.c:796
SCConfNode * SCConfGetNode(const char *name)
Get a SCConfNode by name.
Definition conf.c:181
int SCConfValIsTrue(const char *val)
Check if a value is true.
Definition conf.c:551
int SCConfValIsFalse(const char *val)
Check if a value is false.
Definition conf.c:576
uint8_t flags
Definition decode-gre.h:0
uint8_t proto
#define PKT_HAS_FLOW
Definition decode.h:1266
#define PKT_STREAM_EST
Definition decode.h:1262
DetectContentData * DetectContentParseEncloseQuotes(SpmGlobalThreadCtx *spm_global_thread_ctx, const char *contentstr)
void DetectContentFree(DetectEngineCtx *de_ctx, void *ptr)
this function will SCFree memory associated with DetectContentData
#define DETECT_CONTENT_NOCASE
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
int SigGroupCleanup(DetectEngineCtx *de_ctx)
uint8_t PatternMatchDefaultMatcher(void)
Function to return the multi pattern matcher algorithm to be used by the engine, based on the mpm-alg...
int DetectPortParse(const DetectEngineCtx *de_ctx, DetectPort **head, const char *str)
Function for parsing port strings.
void DetectPortCleanupList(const DetectEngineCtx *de_ctx, DetectPort *head)
Free a DetectPort list and each of its members.
DetectEngineCtx * DetectEngineCtxInit(void)
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Data structures and function prototypes for keeping state for the detection engine.
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
uint32_t id
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition detect.c:2420
#define DE_QUIET
Definition detect.h:330
TcpStreamCnf stream_config
Definition stream-tcp.c:219
Flow * head
Definition flow-hash.h:1
SCMutex m
Definition flow-hash.h:6
@ FLOW_PROTO_UDP
@ FLOW_PROTO_DEFAULT
@ FLOW_PROTO_TCP
uint8_t FlowGetReverseProtoMapping(uint8_t rproto)
Definition flow-util.c:113
uint8_t FlowGetProtoMapping(uint8_t proto)
Function to map the protocol to the defined FLOW_PROTO_* enumeration.
Definition flow-util.c:99
int FlowChangeProto(Flow *f)
Check if change proto flag is set for flow.
Definition flow.c:196
void FlowSetChangeProtoFlag(Flow *f)
Set flag to indicate to change proto for the flow.
Definition flow.c:177
#define FLOW_SET_PM_DONE(f, dir)
Definition flow.h:282
#define FLOW_SET_PP_DONE(f, dir)
Definition flow.h:283
#define FLOW_RESET_PE_DONE(f, dir)
Definition flow.h:288
#define FLOW_PKT_TOSERVER
Definition flow.h:233
#define FLOW_GET_DP(f)
Definition flow.h:177
#define FLOW_IS_PP_DONE(f, dir)
Definition flow.h:279
#define FLOW_RESET_PM_DONE(f, dir)
Definition flow.h:286
#define FLOW_GET_SP(f)
Definition flow.h:175
#define FLOW_PKT_ESTABLISHED
Definition flow.h:235
#define FLOW_RESET_PP_DONE(f, dir)
Definition flow.h:287
#define FLOW_IS_PM_DONE(f, dir)
Definition flow.h:278
#define FLOW_IS_PE_DONE(f, dir)
Definition flow.h:280
#define FLOW_SET_PE_DONE(f, dir)
Definition flow.h:284
AppLayerParserThreadCtx * alp_tctx
AppLayerProtoDetectThreadCtx * alpd_tctx
ThreadVars * tv
DetectEngineCtx * de_ctx
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define PASS
Pass the test.
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
AppProto AppLayerExpectationHandle(Flow *f, uint8_t flags)
void AppLayerExpectationSetup(void)
struct Thresholds ctx
void StreamTcpFreeConfig(bool quiet)
Definition stream-tcp.c:859
void StreamTcpInitConfig(bool)
To initialize the stream global configuration data.
Definition stream-tcp.c:488
struct AppLayerProtoDetectAliases_ * next
AppLayerProtoDetectPMCtx ctx_pm[2]
The app layer protocol detection context.
AppLayerProtoDetectProbingParser * ctx_pp
AppLayerProtoDetectCtxIpproto ctx_ipp[FLOW_PROTO_DEFAULT]
SpmGlobalThreadCtx * spm_global_thread_ctx
AppLayerProtoDetectPMSignature * head
AppLayerProtoDetectPMSignature ** map
struct AppLayerProtoDetectPMSignature_ * next
AppLayerProtoDetectPPTestDataPort * port
AppLayerProtoDetectPPTestDataElement * toserver_element
AppLayerProtoDetectPPTestDataElement * toclient_element
struct AppLayerProtoDetectProbingParserElement_ * next
AppLayerProtoDetectProbingParserElement * dp
AppLayerProtoDetectProbingParserElement * sp
struct AppLayerProtoDetectProbingParserPort_ * next
struct AppLayerProtoDetectProbingParser_ * next
AppLayerProtoDetectProbingParserPort * port
The app layer protocol detection thread context.
MpmThreadCtx mpm_tctx[FLOW_PROTO_DEFAULT][2]
main detection engine ctx
Definition detect.h:932
uint8_t flags
Definition detect.h:934
Signature * sig_list
Definition detect.h:941
Port structure for detection engine.
Definition detect.h:220
uint16_t port
Definition detect.h:221
uint16_t port2
Definition detect.h:222
struct DetectPort_ * next
Definition detect.h:234
Flow data structure.
Definition flow.h:356
AppProto alproto_ts
Definition flow.h:451
AppProto alproto_tc
Definition flow.h:452
uint8_t proto
Definition flow.h:378
AppProto alproto_expect
Definition flow.h:459
AppProto alproto
application level protocol
Definition flow.h:450
void * alstate
Definition flow.h:479
uint32_t probing_parser_toclient_alproto_masks
Definition flow.h:419
uint16_t protodetect_dp
Definition flow.h:427
AppProto alproto_orig
Definition flow.h:456
void * protoctx
Definition flow.h:441
AppLayerParserState * alparser
Definition flow.h:478
uint8_t protomap
Definition flow.h:445
uint32_t probing_parser_toserver_alproto_masks
Definition flow.h:418
uint32_t pattern_cnt
Definition util-mpm.h:102
uint16_t maxdepth
Definition util-mpm.h:99
uint8_t mpm_type
Definition util-mpm.h:95
int(* Prepare)(MpmConfig *, struct MpmCtx_ *)
Definition util-mpm.h:175
uint32_t(* Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, const uint8_t *, uint32_t)
Definition util-mpm.h:178
void(* DestroyCtx)(struct MpmCtx_ *)
Definition util-mpm.h:154
uint8_t flowflags
Definition decode.h:532
struct Flow_ * flow
Definition decode.h:546
uint32_t flags
Definition decode.h:544
structure for storing potential rule matches
char * val
Definition conf.h:39
Signature container.
Definition detect.h:668
Per thread variable structure.
Definition threadvars.h:58
#define SWAP_VARS(type, a, b)
#define BUG_ON(x)
#define SigIntId
#define MIN(x, y)
#define PatIntId
#define BIT_U32(n)
int RunmodeIsUnittests(void)
Definition suricata.c:270
uint32_t cnt
int SCLogDebugEnabled(void)
Returns whether debug messages are enabled to be logged or not.
Definition util-debug.c:767
#define SCEnter(...)
Definition util-debug.h:277
#define FatalError(...)
Definition util-debug.h:510
#define SCReturnUInt(x)
Definition util-debug.h:283
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCReturnInt(x)
Definition util-debug.h:281
#define SCReturnCT(x, type)
Definition util-debug.h:291
#define SCReturnPtr(x, type)
Definition util-debug.h:293
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
#define SCReturn
Definition util-debug.h:279
#define SCMalloc(sz)
Definition util-mem.h:47
#define SCFree(p)
Definition util-mem.h:61
#define SCRealloc(ptr, sz)
Definition util-mem.h:50
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define SCMemcmp(a, b, c)
MpmTableElmt mpm_table[MPM_TABLE_SIZE]
Definition util-mpm.c:47
int MpmAddPatternCS(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags)
Definition util-mpm.c:249
void MpmDestroyThreadCtx(MpmThreadCtx *mpm_thread_ctx, const uint16_t matcher)
Definition util-mpm.c:202
int MpmAddPatternCI(MpmCtx *mpm_ctx, const uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags)
Definition util-mpm.c:258
void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t matcher)
Definition util-mpm.c:195
void MpmInitCtx(MpmCtx *mpm_ctx, uint8_t matcher)
Definition util-mpm.c:209
#define likely(expr)
#define unlikely(expr)
int PmqSetup(PrefilterRuleStore *pmq)
Setup a pmq.
void PmqReset(PrefilterRuleStore *pmq)
Reset a Pmq for reusage. Meant to be called after a single search.
void PmqFree(PrefilterRuleStore *pmq)
Cleanup and free a Pmq.
SpmThreadCtx * SpmMakeThreadCtx(const SpmGlobalThreadCtx *global_thread_ctx)
Definition util-spm.c:153
uint8_t SinglePatternMatchDefaultMatcher(void)
Returns the single pattern matcher algorithm to be used, based on the spm-algo setting in yaml.
Definition util-spm.c:68
void SpmDestroyGlobalThreadCtx(SpmGlobalThreadCtx *global_thread_ctx)
Definition util-spm.c:144
SpmGlobalThreadCtx * SpmInitGlobalThreadCtx(uint8_t matcher)
Definition util-spm.c:138
void SpmDestroyThreadCtx(SpmThreadCtx *thread_ctx)
Definition util-spm.c:163
SpmCtx * SpmInitCtx(const uint8_t *needle, uint16_t needle_len, int nocase, SpmGlobalThreadCtx *global_thread_ctx)
Definition util-spm.c:173
void SpmDestroyCtx(SpmCtx *ctx)
Definition util-spm.c:183
uint8_t * SpmScan(const SpmCtx *ctx, SpmThreadCtx *thread_ctx, const uint8_t *haystack, uint32_t haystack_len)
Definition util-spm.c:193
uint64_t offset
void UTHFreePackets(Packet **p, int numpkts)
UTHFreePackets: function to release the allocated data from UTHBuildPacket and the packet itself.
Packet * UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint8_t ipproto)
UTHBuildPacket is a wrapper that build packets with default ip and port fields.
Packet * UTHBuildPacketSrcDstPorts(uint8_t *payload, uint16_t payload_len, uint8_t ipproto, uint16_t sport, uint16_t dport)
UTHBuildPacketSrcDstPorts is a wrapper that build packets specifying src and dst ports and defaulting...
void UTHFreeFlow(Flow *flow)
Flow * UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
#define DEBUG_VALIDATE_BUG_ON(exp)