]> git.ipfire.org Git - people/ms/suricata.git/blame - src/detect-http-header.c
core: Remove unneeded consts
[people/ms/suricata.git] / src / detect-http-header.c
CommitLineData
9a5c666b 1/* Copyright (C) 2007-2021 Open Information Security Foundation
ce019275
WM
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
60a99915
EL
18/**
19 * \ingroup httplayer
20 *
21 * @{
22 */
23
24
ab02ab9e 25/**
ce019275 26 * \file
ab02ab9e
PR
27 *
28 * \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
ce019275 29 *
fc46f216 30 * Implements support for http_header keyword.
ab02ab9e
PR
31 */
32
33#include "suricata-common.h"
34#include "threads.h"
35#include "decode.h"
36
37#include "detect.h"
38#include "detect-parse.h"
39#include "detect-engine.h"
40#include "detect-engine-mpm.h"
0e4235cc 41#include "detect-engine-state.h"
2bb0cae0
VJ
42#include "detect-engine-prefilter.h"
43#include "detect-engine-content-inspection.h"
ab02ab9e 44#include "detect-content.h"
c61c68fd 45#include "detect-pcre.h"
ab02ab9e 46
ab02ab9e 47#include "util-debug.h"
70b32f73 48#include "util-print.h"
2bb0cae0 49#include "util-memcmp.h"
ab02ab9e
PR
50
51#include "app-layer.h"
429c6388 52#include "app-layer-parser.h"
ab02ab9e 53
ab02ab9e
PR
54#include "app-layer-htp.h"
55#include "detect-http-header.h"
f2fc5a25 56#include "detect-http-header-common.h"
ab02ab9e 57
ab1200fb 58static int DetectHttpHeaderSetup(DetectEngineCtx *, Signature *, const char *);
b9bcd4e1 59#ifdef UNITTESTS
e7d5e845 60static void DetectHttpHeaderRegisterTests(void);
b9bcd4e1 61#endif
e7d5e845 62static int g_http_header_buffer_id = 0;
f2fc5a25 63static int g_keyword_thread_id = 0;
ab02ab9e 64
f2fc5a25 65#define BUFFER_SIZE_STEP 1024
9a5c666b 66static HttpHeaderThreadDataConfig g_td_config = { BUFFER_SIZE_STEP };
2bb0cae0 67
9a5c666b
VJ
68static uint8_t *GetBufferForTX(
69 htp_tx_t *tx, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, uint32_t *buffer_len)
2bb0cae0 70{
2bb0cae0
VJ
71 *buffer_len = 0;
72
f2fc5a25 73 HttpHeaderThreadData *hdr_td = NULL;
9a5c666b
VJ
74 HttpHeaderBuffer *buf =
75 HttpHeaderGetBufferSpace(det_ctx, f, flags, g_keyword_thread_id, &hdr_td);
f2fc5a25
VJ
76 if (unlikely(buf == NULL)) {
77 return NULL;
2bb0cae0
VJ
78 }
79
80 htp_table_t *headers;
81 if (flags & STREAM_TOSERVER) {
707f0272
PA
82 if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, tx, flags) <=
83 HTP_REQUEST_HEADERS)
f2fc5a25 84 return NULL;
2bb0cae0
VJ
85 headers = tx->request_headers;
86 } else {
707f0272
PA
87 if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, tx, flags) <=
88 HTP_RESPONSE_HEADERS)
f2fc5a25 89 return NULL;
2bb0cae0
VJ
90 headers = tx->response_headers;
91 }
92 if (headers == NULL)
f2fc5a25 93 return NULL;
2bb0cae0 94
2bb0cae0 95 size_t i = 0;
2bb0cae0
VJ
96 size_t no_of_headers = htp_table_size(headers);
97 for (; i < no_of_headers; i++) {
f2fc5a25 98 htp_header_t *h = htp_table_get_index(headers, i, NULL);
2bb0cae0
VJ
99 size_t size1 = bstr_size(h->name);
100 size_t size2 = bstr_size(h->value);
101
102 if (flags & STREAM_TOSERVER) {
103 if (size1 == 6 &&
104 SCMemcmpLowercase("cookie", bstr_ptr(h->name), 6) == 0) {
105 continue;
106 }
107 } else {
108 if (size1 == 10 &&
109 SCMemcmpLowercase("set-cookie", bstr_ptr(h->name), 10) == 0) {
110 continue;
111 }
112 }
113
f2fc5a25
VJ
114 size_t size = size1 + size2 + 4;
115#if 0
116 if (i + 1 == no_of_headers)
117 size += 2;
118#endif
119 if (size + buf->len > buf->size) {
120 if (HttpHeaderExpandBuffer(hdr_td, buf, size) != 0) {
121 return NULL;
2bb0cae0 122 }
2bb0cae0 123 }
2bb0cae0 124
f2fc5a25
VJ
125 memcpy(buf->buffer + buf->len, bstr_ptr(h->name), bstr_size(h->name));
126 buf->len += bstr_size(h->name);
127 buf->buffer[buf->len++] = ':';
128 buf->buffer[buf->len++] = ' ';
129 memcpy(buf->buffer + buf->len, bstr_ptr(h->value), bstr_size(h->value));
130 buf->len += bstr_size(h->value);
131 buf->buffer[buf->len++] = '\r';
132 buf->buffer[buf->len++] = '\n';
133#if 0 // looks like this breaks existing rules
134 if (i + 1 == no_of_headers) {
135 buf->buffer[buf->len++] = '\r';
136 buf->buffer[buf->len++] = '\n';
137 }
138#endif
139 }
2bb0cae0 140
f2fc5a25
VJ
141 *buffer_len = buf->len;
142 return buf->buffer;
2bb0cae0
VJ
143}
144
0b0649d9
PA
145static InspectionBuffer *GetBuffer2ForTX(DetectEngineThreadCtx *det_ctx,
146 const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv,
147 const int list_id)
148{
149 InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
150 if (buffer->inspect == NULL) {
151 uint32_t b_len = 0;
152 const uint8_t *b = NULL;
153
154 if (rs_http2_tx_get_headers(txv, flow_flags, &b, &b_len) != 1)
155 return NULL;
156 if (b == NULL || b_len == 0)
157 return NULL;
158
159 InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len);
160 InspectionBufferApplyTransforms(buffer, transforms);
161 }
162
163 return buffer;
164}
165
5e951a8b
VJ
166/** \internal
167 * \brief custom inspect function to utilize the cached headers
ab02ab9e 168 */
5e951a8b
VJ
169static int DetectEngineInspectBufferHttpHeader(
170 DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
171 const DetectEngineAppInspectionEngine *engine,
172 const Signature *s,
173 Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
ab02ab9e 174{
2bb0cae0 175 SCEnter();
ab02ab9e 176
5e951a8b
VJ
177 const int list_id = engine->sm_list;
178 InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
179 if (buffer->inspect == NULL) {
180 SCLogDebug("setting up inspect buffer %d", list_id);
7b98c007 181
5e951a8b
VJ
182 /* if prefilter didn't already run, we need to consider transformations */
183 const DetectEngineTransforms *transforms = NULL;
184 if (!engine->mpm) {
185 transforms = engine->v2.transforms;
186 }
2bb0cae0 187
5e951a8b 188 uint32_t rawdata_len = 0;
9a5c666b 189 uint8_t *rawdata = GetBufferForTX(txv, det_ctx, f, flags, &rawdata_len);
5e951a8b
VJ
190 if (rawdata_len == 0) {
191 SCLogDebug("no data");
192 goto end;
193 }
194 /* setup buffer and apply transforms */
13cebb18 195 InspectionBufferSetup(det_ctx, list_id, buffer, rawdata, rawdata_len);
5e951a8b 196 InspectionBufferApplyTransforms(buffer, transforms);
2bb0cae0 197 }
eb19eb3f 198
5e951a8b
VJ
199 const uint32_t data_len = buffer->inspect_len;
200 const uint8_t *data = buffer->inspect;
201 const uint64_t offset = buffer->inspect_offset;
e7d5e845 202
5e951a8b
VJ
203 det_ctx->discontinue_matching = 0;
204 det_ctx->buffer_offset = 0;
205 det_ctx->inspection_recursion_counter = 0;
2bb0cae0 206
5e951a8b
VJ
207 /* Inspect all the uricontents fetched on each
208 * transaction at the app layer */
32fb7d77
VJ
209 int r = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd,
210 NULL, f, (uint8_t *)data, data_len, offset,
211 DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE);
5e951a8b
VJ
212 SCLogDebug("r = %d", r);
213 if (r == 1) {
214 return DETECT_ENGINE_INSPECT_SIG_MATCH;
215 }
216end:
217 if (flags & STREAM_TOSERVER) {
707f0272
PA
218 if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, txv, flags) >
219 HTP_REQUEST_HEADERS)
5e951a8b
VJ
220 return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
221 } else {
707f0272
PA
222 if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, txv, flags) >
223 HTP_RESPONSE_HEADERS)
5e951a8b 224 return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
2bb0cae0 225 }
5e951a8b 226 return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
2bb0cae0 227}
15dcac92 228
5e951a8b
VJ
229typedef struct PrefilterMpmHttpHeaderCtx {
230 int list_id;
231 const MpmCtx *mpm_ctx;
232 const DetectEngineTransforms *transforms;
233} PrefilterMpmHttpHeaderCtx;
ab02ab9e 234
5e951a8b 235/** \brief Generic Mpm prefilter callback
cda664a8 236 *
2bb0cae0
VJ
237 * \param det_ctx detection engine thread ctx
238 * \param p packet to inspect
239 * \param f flow to inspect
240 * \param txv tx to inspect
241 * \param pectx inspection context
cda664a8 242 */
5e951a8b 243static void PrefilterMpmHttpHeader(DetectEngineThreadCtx *det_ctx,
2bb0cae0
VJ
244 const void *pectx,
245 Packet *p, Flow *f, void *txv,
246 const uint64_t idx, const uint8_t flags)
cda664a8 247{
2bb0cae0
VJ
248 SCEnter();
249
5e951a8b
VJ
250 const PrefilterMpmHttpHeaderCtx *ctx = pectx;
251 const MpmCtx *mpm_ctx = ctx->mpm_ctx;
252 SCLogDebug("running on list %d", ctx->list_id);
253
254 const int list_id = ctx->list_id;
255 InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
256 if (buffer->inspect == NULL) {
257 uint32_t rawdata_len = 0;
9a5c666b 258 uint8_t *rawdata = GetBufferForTX(txv, det_ctx, f, flags, &rawdata_len);
5e951a8b
VJ
259 if (rawdata_len == 0)
260 return;
261
262 /* setup buffer and apply transforms */
13cebb18 263 InspectionBufferSetup(det_ctx, list_id, buffer, rawdata, rawdata_len);
5e951a8b
VJ
264 InspectionBufferApplyTransforms(buffer, ctx->transforms);
265 }
2bb0cae0 266
5e951a8b
VJ
267 const uint32_t data_len = buffer->inspect_len;
268 const uint8_t *data = buffer->inspect;
2bb0cae0 269
5e951a8b
VJ
270 SCLogDebug("mpm'ing buffer:");
271 //PrintRawDataFp(stdout, data, data_len);
2bb0cae0 272
5e951a8b 273 if (data != NULL && data_len >= mpm_ctx->minlen) {
2bb0cae0 274 (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx,
5e951a8b 275 &det_ctx->mtcu, &det_ctx->pmq, data, data_len);
2bb0cae0
VJ
276 }
277}
15dcac92 278
5e951a8b 279static void PrefilterMpmHttpTrailer(DetectEngineThreadCtx *det_ctx,
2bb0cae0
VJ
280 const void *pectx,
281 Packet *p, Flow *f, void *txv,
282 const uint64_t idx, const uint8_t flags)
283{
284 SCEnter();
285
5e951a8b 286 htp_tx_t *tx = txv;
2bb0cae0
VJ
287 const HtpTxUserData *htud = (const HtpTxUserData *)htp_tx_get_user_data(tx);
288 /* if the request wasn't flagged as having a trailer, we skip */
5e951a8b
VJ
289 if (htud && (
290 ((flags & STREAM_TOSERVER) && !htud->request_has_trailers) ||
291 ((flags & STREAM_TOCLIENT) && !htud->response_has_trailers))) {
292 SCReturn;
2bb0cae0 293 }
5e951a8b
VJ
294 PrefilterMpmHttpHeader(det_ctx, pectx, p, f, txv, idx, flags);
295 SCReturn;
296}
297
298static void PrefilterMpmHttpHeaderFree(void *ptr)
299{
300 SCFree(ptr);
2bb0cae0 301}
15dcac92 302
5e951a8b
VJ
303static int PrefilterMpmHttpHeaderRequestRegister(DetectEngineCtx *de_ctx,
304 SigGroupHead *sgh, MpmCtx *mpm_ctx,
4dff903b 305 const DetectBufferMpmRegistery *mpm_reg, int list_id)
2bb0cae0
VJ
306{
307 SCEnter();
308
5e951a8b
VJ
309 /* header */
310 PrefilterMpmHttpHeaderCtx *pectx = SCCalloc(1, sizeof(*pectx));
311 if (pectx == NULL)
312 return -1;
313 pectx->list_id = list_id;
314 pectx->mpm_ctx = mpm_ctx;
4dff903b 315 pectx->transforms = &mpm_reg->transforms;
5e951a8b
VJ
316
317 int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpHeader,
4dff903b 318 mpm_reg->app_v2.alproto, HTP_REQUEST_HEADERS,
5e951a8b
VJ
319 pectx, PrefilterMpmHttpHeaderFree, mpm_reg->pname);
320 if (r != 0) {
321 SCFree(pectx);
2bb0cae0 322 return r;
5e951a8b
VJ
323 }
324
325 /* trailer */
326 pectx = SCCalloc(1, sizeof(*pectx));
327 if (pectx == NULL)
328 return -1;
329 pectx->list_id = list_id;
330 pectx->mpm_ctx = mpm_ctx;
4dff903b 331 pectx->transforms = &mpm_reg->transforms;
5e951a8b
VJ
332
333 r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpTrailer,
4dff903b 334 mpm_reg->app_v2.alproto, HTP_REQUEST_TRAILER,
5e951a8b
VJ
335 pectx, PrefilterMpmHttpHeaderFree, mpm_reg->pname);
336 if (r != 0) {
337 SCFree(pectx);
338 }
339 return r;
2bb0cae0
VJ
340}
341
5e951a8b
VJ
342static int PrefilterMpmHttpHeaderResponseRegister(DetectEngineCtx *de_ctx,
343 SigGroupHead *sgh, MpmCtx *mpm_ctx,
4dff903b 344 const DetectBufferMpmRegistery *mpm_reg, int list_id)
2bb0cae0 345{
5e951a8b 346 SCEnter();
2bb0cae0 347
5e951a8b
VJ
348 /* header */
349 PrefilterMpmHttpHeaderCtx *pectx = SCCalloc(1, sizeof(*pectx));
350 if (pectx == NULL)
351 return -1;
352 pectx->list_id = list_id;
353 pectx->mpm_ctx = mpm_ctx;
4dff903b 354 pectx->transforms = &mpm_reg->transforms;
5e951a8b
VJ
355
356 int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpHeader,
4dff903b 357 mpm_reg->app_v2.alproto, HTP_RESPONSE_HEADERS,
5e951a8b
VJ
358 pectx, PrefilterMpmHttpHeaderFree, mpm_reg->pname);
359 if (r != 0) {
360 SCFree(pectx);
361 return r;
362 }
2bb0cae0 363
5e951a8b
VJ
364 /* trailer */
365 pectx = SCCalloc(1, sizeof(*pectx));
366 if (pectx == NULL)
367 return -1;
368 pectx->list_id = list_id;
369 pectx->mpm_ctx = mpm_ctx;
4dff903b 370 pectx->transforms = &mpm_reg->transforms;
5e951a8b
VJ
371
372 r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpTrailer,
4dff903b 373 mpm_reg->app_v2.alproto, HTP_RESPONSE_TRAILER,
5e951a8b
VJ
374 pectx, PrefilterMpmHttpHeaderFree, mpm_reg->pname);
375 if (r != 0) {
376 SCFree(pectx);
2bb0cae0 377 }
5e951a8b 378 return r;
2bb0cae0
VJ
379}
380
ab02ab9e
PR
381/**
382 * \brief The setup function for the http_header keyword for a signature.
383 *
384 * \param de_ctx Pointer to the detection engine context.
385 * \param s Pointer to signature for the current Signature being parsed
386 * from the rules.
387 * \param m Pointer to the head of the SigMatchs for the current rule
388 * being parsed.
389 * \param arg Pointer to the string holding the keyword value.
390 *
6648d1fa
AS
391 * \retval 0 On success.
392 * \retval -1 On failure.
ab02ab9e 393 */
ab1200fb 394static int DetectHttpHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
ab02ab9e 395{
707f0272
PA
396 return DetectEngineContentModifierBufferSetup(
397 de_ctx, s, arg, DETECT_AL_HTTP_HEADER, g_http_header_buffer_id, ALPROTO_HTTP1);
ab02ab9e
PR
398}
399
85697671
VJ
400/**
401 * \brief this function setup the http.header keyword used in the rule
402 *
403 * \param de_ctx Pointer to the Detection Engine Context
404 * \param s Pointer to the Signature to which the current keyword belongs
405 * \param str Should hold an empty string always
406 *
407 * \retval 0 On success
408 */
409static int DetectHttpHeaderSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str)
410{
411 if (DetectBufferSetActiveList(s, g_http_header_buffer_id) < 0)
412 return -1;
0b0649d9 413 if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0)
85697671
VJ
414 return -1;
415 return 0;
416}
417
2bb0cae0
VJ
418/**
419 * \brief Registers the keyword handlers for the "http_header" keyword.
420 */
421void DetectHttpHeaderRegister(void)
422{
85697671 423 /* http_header content modifier */
2bb0cae0 424 sigmatch_table[DETECT_AL_HTTP_HEADER].name = "http_header";
d801c3e5 425 sigmatch_table[DETECT_AL_HTTP_HEADER].desc = "content modifier to match only on the HTTP header-buffer";
26bcc975 426 sigmatch_table[DETECT_AL_HTTP_HEADER].url = "/rules/http-keywords.html#http-header-and-http-raw-header";
2bb0cae0 427 sigmatch_table[DETECT_AL_HTTP_HEADER].Setup = DetectHttpHeaderSetup;
b9bcd4e1 428#ifdef UNITTESTS
2bb0cae0 429 sigmatch_table[DETECT_AL_HTTP_HEADER].RegisterTests = DetectHttpHeaderRegisterTests;
b9bcd4e1 430#endif
2bb0cae0 431 sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_NOOPT ;
85697671
VJ
432 sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_INFO_CONTENT_MODIFIER;
433 sigmatch_table[DETECT_AL_HTTP_HEADER].alternative = DETECT_HTTP_HEADER;
434
435 /* http.header sticky buffer */
436 sigmatch_table[DETECT_HTTP_HEADER].name = "http.header";
d801c3e5 437 sigmatch_table[DETECT_HTTP_HEADER].desc = "sticky buffer to match on the normalized HTTP header-buffer";
26bcc975 438 sigmatch_table[DETECT_HTTP_HEADER].url = "/rules/http-keywords.html#http-header-and-http-raw-header";
85697671
VJ
439 sigmatch_table[DETECT_HTTP_HEADER].Setup = DetectHttpHeaderSetupSticky;
440 sigmatch_table[DETECT_HTTP_HEADER].flags |= SIGMATCH_NOOPT;
441 sigmatch_table[DETECT_HTTP_HEADER].flags |= SIGMATCH_INFO_STICKY_BUFFER;
2bb0cae0 442
707f0272
PA
443 DetectAppLayerInspectEngineRegister2("http_header", ALPROTO_HTTP1, SIG_FLAG_TOSERVER,
444 HTP_REQUEST_HEADERS, DetectEngineInspectBufferHttpHeader, NULL);
5e951a8b 445 DetectAppLayerMpmRegister2("http_header", SIG_FLAG_TOSERVER, 2,
707f0272 446 PrefilterMpmHttpHeaderRequestRegister, NULL, ALPROTO_HTTP1,
5e951a8b 447 0); /* not used, registered twice: HEADERS/TRAILER */
2bb0cae0 448
707f0272
PA
449 DetectAppLayerInspectEngineRegister2("http_header", ALPROTO_HTTP1, SIG_FLAG_TOCLIENT,
450 HTP_RESPONSE_HEADERS, DetectEngineInspectBufferHttpHeader, NULL);
5e951a8b 451 DetectAppLayerMpmRegister2("http_header", SIG_FLAG_TOCLIENT, 2,
707f0272 452 PrefilterMpmHttpHeaderResponseRegister, NULL, ALPROTO_HTTP1,
5e951a8b 453 0); /* not used, registered twice: HEADERS/TRAILER */
2bb0cae0 454
0b0649d9
PA
455 DetectAppLayerInspectEngineRegister2("http_header", ALPROTO_HTTP2, SIG_FLAG_TOSERVER,
456 HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetBuffer2ForTX);
457 DetectAppLayerMpmRegister2("http_header", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,
458 GetBuffer2ForTX, ALPROTO_HTTP2, HTTP2StateDataClient);
459
460 DetectAppLayerInspectEngineRegister2("http_header", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT,
461 HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetBuffer2ForTX);
462 DetectAppLayerMpmRegister2("http_header", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister,
463 GetBuffer2ForTX, ALPROTO_HTTP2, HTTP2StateDataServer);
464
2bb0cae0
VJ
465 DetectBufferTypeSetDescriptionByName("http_header",
466 "http headers");
467
2bb0cae0 468 g_http_header_buffer_id = DetectBufferTypeGetByName("http_header");
f2fc5a25
VJ
469
470 g_keyword_thread_id = DetectRegisterThreadCtxGlobalFuncs("http_header",
471 HttpHeaderThreadDataInit, &g_td_config, HttpHeaderThreadDataFree);
2bb0cae0
VJ
472}
473
ab02ab9e
PR
474/************************************Unittests*********************************/
475
476#ifdef UNITTESTS
b9bcd4e1
VJ
477#include "tests/detect-http-header.c"
478#endif
ab02ab9e 479
60a99915
EL
480/**
481 * @}
482 */