suricata
detect-flowvar.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2020 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18/**
19 * \file
20 *
21 * \author Victor Julien <victor@inliniac.net>
22 *
23 * Simple flowvar content match part of the detection engine.
24 */
25
26#include "suricata-common.h"
27#include "decode.h"
28
29#include "detect.h"
30#include "detect-parse.h"
31
32#include "detect-content.h"
33#include "threads.h"
34#include "flow.h"
35#include "flow-var.h"
36#include "pkt-var.h"
37#include "detect-flowvar.h"
38
39#include "util-spm.h"
40#include "util-var-name.h"
41#include "util-debug.h"
42#include "util-print.h"
43
44#define PARSE_REGEX "(.*),(.*)"
45static DetectParseRegex parse_regex;
46
48 const Signature *, const SigMatchCtx *);
49static int DetectFlowvarSetup (DetectEngineCtx *, Signature *, const char *);
50static int DetectFlowvarPostMatch(DetectEngineThreadCtx *det_ctx,
51 Packet *p, const Signature *s, const SigMatchCtx *ctx);
52static void DetectFlowvarDataFree(DetectEngineCtx *, void *ptr);
53
55{
58 sigmatch_table[DETECT_FLOWVAR].Setup = DetectFlowvarSetup;
59 sigmatch_table[DETECT_FLOWVAR].Free = DetectFlowvarDataFree;
60
61 /* post-match for flowvar storage */
62 sigmatch_table[DETECT_FLOWVAR_POSTMATCH].name = "__flowvar__postmatch__";
63 sigmatch_table[DETECT_FLOWVAR_POSTMATCH].Match = DetectFlowvarPostMatch;
65 sigmatch_table[DETECT_FLOWVAR_POSTMATCH].Free = DetectFlowvarDataFree;
66
68}
69
70/**
71 * \brief this function will SCFree memory associated with DetectFlowvarData
72 *
73 * \param cd pointer to DetectContentData
74 */
75static void DetectFlowvarDataFree(DetectEngineCtx *de_ctx, void *ptr)
76{
77 if (ptr == NULL)
79
81 /* leave unregistration to pcre keyword */
82 if (!fd->post_match)
84
85 if (fd->name)
86 SCFree(fd->name);
87 if (fd->content)
88 SCFree(fd->content);
89
90 SCFree(fd);
91}
92
93/*
94 * returns 0: no match
95 * 1: match
96 * -1: error
97 */
98
100 const Signature *s, const SigMatchCtx *ctx)
101{
102 int ret = 0;
104
105 FlowVar *fv = FlowVarGet(p->flow, fd->idx);
106 if (fv != NULL) {
107 uint8_t *ptr = SpmSearch(fv->data.fv_str.value,
109 fd->content, fd->content_len);
110 if (ptr != NULL)
111 ret = 1;
112 }
113
114 return ret;
115}
116
117static int DetectFlowvarSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
118{
119 DetectFlowvarData *fd = NULL;
120 char varname[64], varcontent[64];
121 int res = 0;
122 size_t pcre2len;
123 uint8_t *content = NULL;
124 uint16_t contentlen = 0;
125 uint32_t contentflags = s->init_data->negated ? DETECT_CONTENT_NEGATED : 0;
126 pcre2_match_data *match = NULL;
127
128 int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0);
129 if (ret != 3) {
130 SCLogError("\"%s\" is not a valid setting for flowvar.", rawstr);
131 if (match) {
132 pcre2_match_data_free(match);
133 }
134 return -1;
135 }
136
137 pcre2len = sizeof(varname);
138 res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)varname, &pcre2len);
139 if (res < 0) {
140 pcre2_match_data_free(match);
141 SCLogError("pcre2_substring_copy_bynumber failed");
142 return -1;
143 }
144
145 pcre2len = sizeof(varcontent);
146 res = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)varcontent, &pcre2len);
147 pcre2_match_data_free(match);
148 if (res < 0) {
149 SCLogError("pcre2_substring_copy_bynumber failed");
150 return -1;
151 }
152
153 int varcontent_index = 0;
154 if (strlen(varcontent) >= 2) {
155 if (varcontent[0] == '"')
156 varcontent_index++;
157 if (varcontent[strlen(varcontent)-1] == '"')
158 varcontent[strlen(varcontent)-1] = '\0';
159 }
160 SCLogDebug("varcontent %s", &varcontent[varcontent_index]);
161
162 res = DetectContentDataParse("flowvar", &varcontent[varcontent_index], &content, &contentlen);
163 if (res == -1)
164 goto error;
165
166 fd = SCCalloc(1, sizeof(DetectFlowvarData));
167 if (unlikely(fd == NULL))
168 goto error;
169
170 fd->content = SCMalloc(contentlen);
171 if (unlikely(fd->content == NULL))
172 goto error;
173
174 memcpy(fd->content, content, contentlen);
175 fd->content_len = contentlen;
176 fd->flags = contentflags;
177
178 fd->name = SCStrdup(varname);
179 if (unlikely(fd->name == NULL))
180 goto error;
182
183 /* Okay so far so good, lets get this into a SigMatch
184 * and put it in the Signature. */
185
188 goto error;
189 }
190
191 SCFree(content);
192 return 0;
193
194error:
195 if (fd != NULL)
196 DetectFlowvarDataFree(de_ctx, fd);
197 if (content != NULL)
198 SCFree(content);
199 return -1;
200}
201
202/** \brief Store flowvar in det_ctx so we can exec it post-match */
203int DetectVarStoreMatchKeyValue(DetectEngineThreadCtx *det_ctx, uint8_t *key, uint16_t key_len,
204 uint8_t *buffer, uint16_t len, uint16_t type)
205{
206 DetectVarList *fs = SCCalloc(1, sizeof(*fs));
207 if (unlikely(fs == NULL))
208 return -1;
209
210 fs->len = len;
211 fs->type = type;
212 fs->buffer = buffer;
213 fs->key = key;
214 fs->key_len = key_len;
215
216 fs->next = det_ctx->varlist;
217 det_ctx->varlist = fs;
218 return 0;
219}
220
221/** \brief Store flowvar in det_ctx so we can exec it post-match */
223 DetectEngineThreadCtx *det_ctx, uint32_t idx, uint8_t *buffer, uint16_t len, uint16_t type)
224{
225 DetectVarList *fs = det_ctx->varlist;
226
227 /* first check if we have had a previous match for this idx */
228 for ( ; fs != NULL; fs = fs->next) {
229 if (fs->idx == idx) {
230 /* we're replacing the older store */
231 SCFree(fs->buffer);
232 fs->buffer = NULL;
233 break;
234 }
235 }
236
237 if (fs == NULL) {
238 fs = SCCalloc(1, sizeof(*fs));
239 if (unlikely(fs == NULL))
240 return -1;
241
242 fs->idx = idx;
243
244 fs->next = det_ctx->varlist;
245 det_ctx->varlist = fs;
246 }
247
248 fs->len = len;
249 fs->type = type;
250 fs->buffer = buffer;
251 return 0;
252}
253
254/** \brief Setup a post-match for flowvar storage
255 * We're piggyback riding the DetectFlowvarData struct
256 */
258{
259 DetectFlowvarData *fv = NULL;
260
261 fv = SCCalloc(1, sizeof(DetectFlowvarData));
262 if (unlikely(fv == NULL))
263 goto error;
264
265 /* we only need the idx */
266 fv->idx = idx;
267 fv->post_match = true;
268
270 DETECT_SM_LIST_POSTMATCH) == NULL) {
271 goto error;
272 }
273 return 0;
274error:
275 if (fv != NULL)
276 DetectFlowvarDataFree(de_ctx, fv);
277 return -1;
278}
279
280/** \internal
281 * \brief post-match func to store flowvars in the flow
282 * \param sm sigmatch containing the idx to store
283 * \retval 1 or -1 in case of error
284 */
285static int DetectFlowvarPostMatch(
286 DetectEngineThreadCtx *det_ctx,
287 Packet *p, const Signature *s, const SigMatchCtx *ctx)
288{
289 DetectVarList *fs, *prev;
290 const DetectFlowvarData *fd;
291
292 if (det_ctx->varlist == NULL)
293 return 1;
294
295 fd = (const DetectFlowvarData *)ctx;
296
297 prev = NULL;
298 fs = det_ctx->varlist;
299 while (fs != NULL) {
300 if (fd->idx == 0 || fd->idx == fs->idx) {
301 SCLogDebug("adding to the flow %u:", fs->idx);
302 //PrintRawDataFp(stdout, fs->buffer, fs->len);
303
304 if (fs->type == DETECT_VAR_TYPE_FLOW_POSTMATCH && p && p->flow) {
305 FlowVarAddIdValue(p->flow, fs->idx, fs->buffer, fs->len);
306 /* memory at fs->buffer is now the responsibility of
307 * the flowvar code. */
308 } else if (fs->type == DETECT_VAR_TYPE_PKT_POSTMATCH && fs->key && p) {
309 /* pkt key/value */
310 if (PktVarAddKeyValue(p, (uint8_t *)fs->key, fs->key_len,
311 (uint8_t *)fs->buffer, fs->len) == -1)
312 {
313 SCFree(fs->key);
314 SCFree(fs->buffer);
315 /* the rest of fs is freed below */
316 }
317 } else if (fs->type == DETECT_VAR_TYPE_PKT_POSTMATCH && p) {
318 if (PktVarAdd(p, fs->idx, fs->buffer, fs->len) == -1) {
319 SCFree(fs->buffer);
320 /* the rest of fs is freed below */
321 }
322 }
323
324 if (fs == det_ctx->varlist) {
325 det_ctx->varlist = fs->next;
326 SCFree(fs);
327 fs = det_ctx->varlist;
328 } else {
329 prev->next = fs->next;
330 SCFree(fs);
331 fs = prev->next;
332 }
333 } else {
334 prev = fs;
335 fs = fs->next;
336 }
337 }
338 return 1;
339}
340
341/** \brief Handle flowvar candidate list in det_ctx: clean up the list
342 *
343 * Only called from DetectVarProcessList() when varlist is not NULL.
344 */
346{
348
349 do {
350 next = fs->next;
351
352 if (fs->key) {
353 SCFree(fs->key);
354 }
355 SCFree(fs->buffer);
356 SCFree(fs);
357 fs = next;
358 } while (fs != NULL);
359}
uint8_t len
struct HtpBodyChunk_ * next
uint16_t type
int DetectContentDataParse(const char *keyword, const char *contentstr, uint8_t **pstr, uint16_t *plen)
Parse a content string, ie "abc|DE|fgh".
#define DETECT_CONTENT_NEGATED
@ DETECT_FLOWVAR_POSTMATCH
int DetectFlowvarMatch(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
int DetectVarStoreMatchKeyValue(DetectEngineThreadCtx *det_ctx, uint8_t *key, uint16_t key_len, uint8_t *buffer, uint16_t len, uint16_t type)
Store flowvar in det_ctx so we can exec it post-match.
int DetectVarStoreMatch(DetectEngineThreadCtx *det_ctx, uint32_t idx, uint8_t *buffer, uint16_t len, uint16_t type)
Store flowvar in det_ctx so we can exec it post-match.
void DetectFlowvarRegister(void)
void DetectVarProcessListInternal(DetectVarList *fs, Flow *f, Packet *p)
Handle flowvar candidate list in det_ctx: clean up the list.
int DetectFlowvarPostMatchSetup(DetectEngineCtx *de_ctx, Signature *s, uint32_t idx)
Setup a post-match for flowvar storage We're piggyback riding the DetectFlowvarData struct.
#define PARSE_REGEX
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str, int start_offset, int options)
SigMatch * SCSigMatchAppendSMToList(DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
Append a SigMatch to the list type.
SigTableElmt * sigmatch_table
#define DETECT_VAR_TYPE_FLOW_POSTMATCH
Definition detect.h:822
#define DETECT_VAR_TYPE_PKT_POSTMATCH
Definition detect.h:823
@ DETECT_SM_LIST_MATCH
Definition detect.h:117
@ DETECT_SM_LIST_POSTMATCH
Definition detect.h:127
FlowVar * FlowVarGet(Flow *f, uint32_t idx)
get the flowvar with index 'idx' from the flow
Definition flow-var.c:84
void FlowVarAddIdValue(Flow *f, uint32_t idx, uint8_t *value, uint16_t size)
Definition flow-var.c:120
DetectEngineCtx * de_ctx
struct Thresholds ctx
int PktVarAddKeyValue(Packet *p, uint8_t *key, uint16_t ksize, uint8_t *value, uint16_t size)
add a key-value pktvar to the pkt
Definition pkt-var.c:56
int PktVarAdd(Packet *p, uint32_t id, uint8_t *value, uint16_t size)
add a key-value pktvar to the pkt
Definition pkt-var.c:86
main detection engine ctx
Definition detect.h:932
DetectVarList * varlist
Definition detect.h:1354
uint16_t type
Definition detect.h:828
uint8_t * key
Definition detect.h:833
uint8_t * buffer
Definition detect.h:834
struct DetectVarList_ * next
Definition detect.h:836
uint16_t key_len
Definition detect.h:832
uint16_t len
Definition detect.h:831
uint32_t idx
Definition detect.h:830
uint16_t value_len
Definition flow-var.h:41
uint8_t * value
Definition flow-var.h:40
FlowVarTypeStr fv_str
Definition flow-var.h:64
union FlowVar_::@124 data
Flow data structure.
Definition flow.h:356
struct Flow_ * flow
Definition decode.h:546
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition detect.h:351
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition detect.h:1441
void(* Free)(DetectEngineCtx *, void *)
Definition detect.h:1446
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition detect.h:1421
const char * name
Definition detect.h:1459
Signature container.
Definition detect.h:668
SignatureInitData * init_data
Definition detect.h:747
#define SCLogDebug(...)
Definition util-debug.h:275
#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 SCCalloc(nm, sz)
Definition util-mem.h:53
#define SCStrdup(s)
Definition util-mem.h:56
#define unlikely(expr)
#define SpmSearch(text, textlen, needle, needlelen)
Definition util-spm.h:99
void VarNameStoreUnregister(const uint32_t id, const enum VarTypes type)
uint32_t VarNameStoreRegister(const char *name, const enum VarTypes type)
@ VAR_TYPE_FLOW_VAR
Definition util-var.h:39