suricata
detect-http-header-names.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2017 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  * \ingroup httplayer
20  *
21  * @{
22  */
23 
24 
25 /**
26  * \file
27  *
28  * \author Victor Julien <victor@inliniac.net>
29  *
30  * Implements support http_header_names
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"
41 #include "detect-engine-state.h"
44 #include "detect-content.h"
45 #include "detect-pcre.h"
48 
49 #include "flow.h"
50 #include "flow-var.h"
51 #include "flow-util.h"
52 
53 #include "util-debug.h"
54 #include "util-unittest.h"
55 #include "util-unittest-helper.h"
56 #include "util-spm.h"
57 #include "util-print.h"
58 
59 #include "app-layer.h"
60 #include "app-layer-parser.h"
61 
62 #include "app-layer-htp.h"
63 #include "detect-http-header.h"
64 #include "stream-tcp.h"
65 
66 #include "util-print.h"
67 
68 #define KEYWORD_NAME "http.header_names"
69 #define KEYWORD_NAME_LEGACY "http_header_names"
70 #define KEYWORD_DOC "http-keywords.html#http-header-names"
71 #define BUFFER_NAME "http_header_names"
72 #define BUFFER_DESC "http header names"
73 static int g_buffer_id = 0;
74 static int g_keyword_thread_id = 0;
75 
76 #define BUFFER_TX_STEP 4
77 #define BUFFER_SIZE_STEP 256
79 
80 static uint8_t *GetBufferForTX(htp_tx_t *tx, uint64_t tx_id,
81  DetectEngineThreadCtx *det_ctx,
82  Flow *f, uint8_t flags, uint32_t *buffer_len)
83 {
84  *buffer_len = 0;
85 
86  HttpHeaderThreadData *hdr_td = NULL;
88  tx_id, g_keyword_thread_id, &hdr_td);
89  if (unlikely(buf == NULL)) {
90  return NULL;
91  } else if (buf->len > 0) {
92  /* already filled buf, reuse */
93  *buffer_len = buf->len;
94  return buf->buffer;
95  }
96 
97  htp_table_t *headers;
98  if (flags & STREAM_TOSERVER) {
99  if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <=
100  HTP_REQUEST_HEADERS)
101  return NULL;
102  headers = tx->request_headers;
103  } else {
104  if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <=
105  HTP_RESPONSE_HEADERS)
106  return NULL;
107  headers = tx->response_headers;
108  }
109  if (headers == NULL)
110  return NULL;
111 
112  /* fill the buffer. \r\nName1\r\nName2\r\n\r\n */
113  size_t i = 0;
114  size_t no_of_headers = htp_table_size(headers);
115  for (; i < no_of_headers; i++) {
116  htp_header_t *h = htp_table_get_index(headers, i, NULL);
117  size_t size = bstr_size(h->name) + 2; // for \r\n
118  if (i == 0)
119  size += 2;
120  if (i + 1 == no_of_headers)
121  size += 2;
122 
123  SCLogDebug("size %"PRIuMAX" + buf->len %u vs buf->size %u",
124  (uintmax_t)size, buf->len, buf->size);
125  if (size + buf->len > buf->size) {
126  if (HttpHeaderExpandBuffer(hdr_td, buf, size) != 0) {
127  return NULL;
128  }
129  }
130 
131  /* start with a \r\n */
132  if (i == 0) {
133  buf->buffer[buf->len++] = '\r';
134  buf->buffer[buf->len++] = '\n';
135  }
136 
137  memcpy(buf->buffer + buf->len, bstr_ptr(h->name), bstr_size(h->name));
138  buf->len += bstr_size(h->name);
139  buf->buffer[buf->len++] = '\r';
140  buf->buffer[buf->len++] = '\n';
141 
142  /* end with an extra \r\n */
143  if (i + 1 == no_of_headers) {
144  buf->buffer[buf->len++] = '\r';
145  buf->buffer[buf->len++] = '\n';
146  }
147  }
148 
149  *buffer_len = buf->len;
150  return buf->buffer;
151 }
152 
154  int list_id;
155  const MpmCtx *mpm_ctx;
158 
159 /** \brief HTTP Headers Mpm prefilter callback
160  *
161  * \param det_ctx detection engine thread ctx
162  * \param p packet to inspect
163  * \param f flow to inspect
164  * \param txv tx to inspect
165  * \param pectx inspection context
166  */
167 static void PrefilterTxHttpRequestHeaderNames(DetectEngineThreadCtx *det_ctx,
168  const void *pectx,
169  Packet *p, Flow *f, void *txv,
170  const uint64_t idx, const uint8_t flags)
171 {
172  SCEnter();
173 
174  htp_tx_t *tx = (htp_tx_t *)txv;
175  if (tx->request_headers == NULL)
176  return;
177 
178  const PrefilterMpmHttpHeaderCtx *ctx = pectx;
179  const MpmCtx *mpm_ctx = ctx->mpm_ctx;
180  SCLogDebug("running on list %d", ctx->list_id);
181 
182  const int list_id = ctx->list_id;
183  InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
184  if (buffer->inspect == NULL) {
185  uint32_t rawdata_len = 0;
186  uint8_t *rawdata = GetBufferForTX(txv, idx, det_ctx,
187  f, flags, &rawdata_len);
188  if (rawdata_len == 0)
189  return;
190 
191  /* setup buffer and apply transforms */
192  InspectionBufferSetup(buffer, rawdata, rawdata_len);
194  }
195 
196  const uint32_t data_len = buffer->inspect_len;
197  const uint8_t *data = buffer->inspect;
198 
199  SCLogDebug("mpm'ing buffer:");
200  //PrintRawDataFp(stdout, data, data_len);
201 
202  if (data != NULL && data_len >= mpm_ctx->minlen) {
203  (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx,
204  &det_ctx->mtcu, &det_ctx->pmq, data, data_len);
205  }
206 }
207 
208 static void PrefilterMpmHttpHeaderFree(void *ptr)
209 {
210  SCFree(ptr);
211 }
212 
213 static int PrefilterTxHttpRequestHeaderNamesRegister(DetectEngineCtx *de_ctx,
214  SigGroupHead *sgh, MpmCtx *mpm_ctx,
215  const DetectMpmAppLayerRegistery *mpm_reg, int list_id)
216 {
217  SCEnter();
218 
219  PrefilterMpmHttpHeaderCtx *pectx = SCCalloc(1, sizeof(*pectx));
220  if (pectx == NULL)
221  return -1;
222  pectx->list_id = list_id;
223  pectx->mpm_ctx = mpm_ctx;
224  pectx->transforms = &mpm_reg->v2.transforms;
225 
226  int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxHttpRequestHeaderNames,
227  mpm_reg->v2.alproto, HTP_REQUEST_HEADERS,
228  pectx, PrefilterMpmHttpHeaderFree, mpm_reg->pname);
229  if (r != 0) {
230  SCFree(pectx);
231  return r;
232  }
233 
234  return r;
235 }
236 
237 /** \brief HTTP Headers Mpm prefilter callback
238  *
239  * \param det_ctx detection engine thread ctx
240  * \param p packet to inspect
241  * \param f flow to inspect
242  * \param txv tx to inspect
243  * \param pectx inspection context
244  */
245 static void PrefilterTxHttpResponseHeaderNames(DetectEngineThreadCtx *det_ctx,
246  const void *pectx,
247  Packet *p, Flow *f, void *txv,
248  const uint64_t idx, const uint8_t flags)
249 {
250  SCEnter();
251 
252  htp_tx_t *tx = (htp_tx_t *)txv;
253  if (tx->response_headers == NULL)
254  return;
255 
256  const PrefilterMpmHttpHeaderCtx *ctx = pectx;
257  const MpmCtx *mpm_ctx = ctx->mpm_ctx;
258  SCLogDebug("running on list %d", ctx->list_id);
259 
260  const int list_id = ctx->list_id;
261  InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
262  if (buffer->inspect == NULL) {
263  uint32_t rawdata_len = 0;
264  uint8_t *rawdata = GetBufferForTX(txv, idx, det_ctx,
265  f, flags, &rawdata_len);
266  if (rawdata_len == 0)
267  return;
268 
269  /* setup buffer and apply transforms */
270  InspectionBufferSetup(buffer, rawdata, rawdata_len);
272  }
273 
274  const uint32_t data_len = buffer->inspect_len;
275  const uint8_t *data = buffer->inspect;
276 
277  SCLogDebug("mpm'ing buffer:");
278  //PrintRawDataFp(stdout, data, data_len);
279 
280  if (data != NULL && data_len >= mpm_ctx->minlen) {
281  (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx,
282  &det_ctx->mtcu, &det_ctx->pmq, data, data_len);
283  }
284 }
285 
286 static int PrefilterTxHttpResponseHeaderNamesRegister(DetectEngineCtx *de_ctx,
287  SigGroupHead *sgh, MpmCtx *mpm_ctx,
288  const DetectMpmAppLayerRegistery *mpm_reg, int list_id)
289 {
290  SCEnter();
291 
292  PrefilterMpmHttpHeaderCtx *pectx = SCCalloc(1, sizeof(*pectx));
293  if (pectx == NULL)
294  return -1;
295  pectx->list_id = list_id;
296  pectx->mpm_ctx = mpm_ctx;
297  pectx->transforms = &mpm_reg->v2.transforms;
298 
299  int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxHttpResponseHeaderNames,
300  mpm_reg->v2.alproto, HTP_RESPONSE_HEADERS,
301  pectx, PrefilterMpmHttpHeaderFree, mpm_reg->pname);
302  if (r != 0) {
303  SCFree(pectx);
304  return r;
305  }
306 
307  return r;
308 }
309 
310 static int InspectEngineHttpHeaderNames(
311  DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
312  const DetectEngineAppInspectionEngine *engine,
313  const Signature *s,
314  Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
315 {
316  const int list_id = engine->sm_list;
317  InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
318  if (buffer->inspect == NULL) {
319  SCLogDebug("setting up inspect buffer %d", list_id);
320 
321  /* if prefilter didn't already run, we need to consider transformations */
322  const DetectEngineTransforms *transforms = NULL;
323  if (!engine->mpm) {
324  transforms = engine->v2.transforms;
325  }
326 
327  uint32_t rawdata_len = 0;
328  uint8_t *rawdata = GetBufferForTX(txv, tx_id, det_ctx,
329  f, flags, &rawdata_len);
330  if (rawdata_len == 0) {
331  SCLogDebug("no data");
332  goto end;
333  }
334  /* setup buffer and apply transforms */
335  InspectionBufferSetup(buffer, rawdata, rawdata_len);
336  InspectionBufferApplyTransforms(buffer, transforms);
337  }
338 
339  const uint32_t data_len = buffer->inspect_len;
340  const uint8_t *data = buffer->inspect;
341  const uint64_t offset = buffer->inspect_offset;
342 
343  det_ctx->buffer_offset = 0;
344  det_ctx->discontinue_matching = 0;
345  det_ctx->inspection_recursion_counter = 0;
346  int r = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd,
347  NULL, f, (uint8_t *)data, data_len, offset,
350  if (r == 1)
352 
353  end:
354  if (flags & STREAM_TOSERVER) {
355  if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) > HTP_REQUEST_HEADERS)
357  } else {
358  if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) > HTP_RESPONSE_HEADERS)
360  }
362 }
363 
364 /**
365  * \brief The setup function for the http.header_names keyword for a signature.
366  *
367  * \param de_ctx Pointer to the detection engine context.
368  * \param s Pointer to signature for the current Signature being parsed
369  * from the rules.
370  * \param m Pointer to the head of the SigMatchs for the current rule
371  * being parsed.
372  * \param arg Pointer to the string holding the keyword value.
373  *
374  * \retval 0 On success.
375  * \retval -1 On failure.
376  */
377 static int DetectHttpHeaderNamesSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
378 {
379  if (DetectBufferSetActiveList(s, g_buffer_id) < 0)
380  return -1;
381 
383  return -1;
384 
385  return 0;
386 }
387 
388 /**
389  * \brief Registers the keyword handlers for the "http.header_names" keyword.
390  */
392 {
397  sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].Setup = DetectHttpHeaderNamesSetup;
398 
400 
402  PrefilterTxHttpRequestHeaderNamesRegister, NULL, ALPROTO_HTTP,
403  HTP_REQUEST_HEADERS);
405  PrefilterTxHttpResponseHeaderNamesRegister, NULL, ALPROTO_HTTP,
406  HTP_RESPONSE_HEADERS);
407 
409  ALPROTO_HTTP, SIG_FLAG_TOSERVER, HTP_REQUEST_HEADERS,
410  InspectEngineHttpHeaderNames, NULL);
412  ALPROTO_HTTP, SIG_FLAG_TOCLIENT, HTP_RESPONSE_HEADERS,
413  InspectEngineHttpHeaderNames, NULL);
414 
416  BUFFER_DESC);
417 
418  g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME);
419 
420  g_keyword_thread_id = DetectRegisterThreadCtxGlobalFuncs(KEYWORD_NAME,
422 
423  SCLogDebug("keyword %s registered. Thread id %d. "
424  "Buffer %s registered. Buffer id %d",
425  KEYWORD_NAME, g_keyword_thread_id,
426  BUFFER_NAME, g_buffer_id);
427 }
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1409
uint16_t flags
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1150
#define SCLogDebug(...)
Definition: util-debug.h:335
int DetectSignatureSetAppProto(Signature *s, AppProto alproto)
#define KEYWORD_DOC
uint16_t minlen
Definition: util-mpm.h:99
uint16_t discontinue_matching
Definition: detect.h:1030
void HttpHeaderThreadDataFree(void *data)
int HttpHeaderExpandBuffer(HttpHeaderThreadData *td, HttpHeaderBuffer *buf, uint32_t size)
int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto, void *alstate, uint8_t flags)
get the progress value for a tx/protocol
#define unlikely(expr)
Definition: util-optimize.h:35
int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd, Packet *p, Flow *f, uint8_t *buffer, uint32_t buffer_len, uint32_t stream_start_offset, uint8_t flags, uint8_t inspection_mode)
Run the actual payload match functions.
struct PrefilterMpmHttpHeaderCtx PrefilterMpmHttpHeaderCtx
one time registration of keywords at start up
Definition: detect.h:571
uint64_t offset
#define KEYWORD_NAME
#define BUFFER_DESC
Container for matching data for a signature group.
Definition: detect.h:1299
#define KEYWORD_NAME_LEGACY
uint32_t buffer_offset
Definition: detect.h:995
InspectionBuffer * InspectionBufferGet(DetectEngineThreadCtx *det_ctx, const int list_id)
const char * name
Definition: detect.h:1164
Signature container.
Definition: detect.h:496
void DetectHttpHeaderNamesRegister(void)
Registers the keyword handlers for the "http.header_names" keyword.
struct DetectEngineAppInspectionEngine_::@92 v2
main detection engine ctx
Definition: detect.h:724
const DetectEngineTransforms * transforms
int DetectBufferTypeGetByName(const char *name)
#define SCCalloc(nm, a)
Definition: util-mem.h:197
#define SIG_FLAG_TOCLIENT
Definition: detect.h:242
#define SIGMATCH_INFO_STICKY_BUFFER
Definition: detect.h:1356
#define DETECT_ENGINE_INSPECT_SIG_MATCH
uint64_t inspect_offset
Definition: detect.h:348
#define BUFFER_SIZE_STEP
Data structures and function prototypes for keeping state for the detection engine.
uint8_t mpm_type
Definition: util-mpm.h:90
HttpHeaderBuffer * HttpHeaderGetBufferSpaceForTXID(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, uint64_t tx_id, const int keyword_id, HttpHeaderThreadData **ret_hdr_td)
#define SIG_FLAG_TOSERVER
Definition: detect.h:241
#define SCEnter(...)
Definition: util-debug.h:337
void DetectAppLayerInspectEngineRegister2(const char *name, AppProto alproto, uint32_t dir, int progress, InspectEngineFuncPtr2 Callback2, InspectionBufferGetDataPtr GetData)
register inspect engine at start up time
PrefilterRuleStore pmq
Definition: detect.h:1065
struct DetectMpmAppLayerRegistery_::@93 v2
void * HttpHeaderThreadDataInit(void *data)
const char * desc
Definition: detect.h:1166
const char * alias
Definition: detect.h:1165
#define DETECT_ENGINE_INSPECT_SIG_CANT_MATCH
#define DETECT_ENGINE_INSPECT_SIG_NO_MATCH
MpmTableElmt mpm_table[MPM_TABLE_SIZE]
Definition: util-mpm.h:169
#define SCFree(a)
Definition: util-mem.h:228
uint16_t tx_id
#define BUFFER_TX_STEP
DetectEngineTransforms transforms
Definition: detect.h:589
void InspectionBufferSetup(InspectionBuffer *buffer, const uint8_t *data, const uint32_t data_len)
setup the buffer with our initial data
MpmThreadCtx mtcu
Definition: detect.h:1063
void InspectionBufferApplyTransforms(InspectionBuffer *buffer, const DetectEngineTransforms *transforms)
#define SIGMATCH_NOOPT
Definition: detect.h:1332
const char * url
Definition: detect.h:1167
#define STREAM_TOSERVER
Definition: stream.h:31
int inspection_recursion_counter
Definition: detect.h:1042
#define DETECT_CI_FLAGS_SINGLE
uint32_t inspect_len
Definition: detect.h:349
int DetectBufferSetActiveList(Signature *s, const int list)
const uint8_t * inspect
Definition: detect.h:347
#define DOC_URL
Definition: suricata.h:86
void DetectBufferTypeSetDescriptionByName(const char *name, const char *desc)
uint32_t(* Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, const uint8_t *, uint32_t)
Definition: util-mpm.h:162
int PrefilterAppendTxEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, void(*PrefilterTxFunc)(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f, void *tx, const uint64_t idx, const uint8_t flags), AppProto alproto, int tx_min_progress, void *pectx, void(*FreeFunc)(void *pectx), const char *name)
#define BUFFER_NAME
#define DOC_VERSION
Definition: suricata.h:91
int DetectRegisterThreadCtxGlobalFuncs(const char *name, void *(*InitFunc)(void *), void *data, void(*FreeFunc)(void *))
Register Thread keyword context Funcs (Global)
uint16_t flags
Definition: detect.h:1158
Flow data structure.
Definition: flow.h:325
const DetectEngineTransforms * transforms
Definition: detect.h:420
void DetectAppLayerMpmRegister2(const char *name, int direction, int priority, int(*PrefilterRegister)(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, const DetectMpmAppLayerRegistery *mpm_reg, int list_id), InspectionBufferGetDataPtr GetData, AppProto alproto, int tx_min_progress)
register a MPM engine