/src/suricata8/src/detect-mark.c
Line | Count | Source |
1 | | /* Copyright (C) 2011-2021 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 Eric Leblond <eric@regit.org> |
22 | | * |
23 | | * Implements the mark keyword. Based on detect-gid |
24 | | * by Breno Silva <breno.silva@gmail.com> |
25 | | */ |
26 | | |
27 | | #include "suricata-common.h" |
28 | | #include "suricata.h" |
29 | | #include "decode.h" |
30 | | #include "detect.h" |
31 | | #include "flow-var.h" |
32 | | #include "decode-events.h" |
33 | | |
34 | | #include "detect-mark.h" |
35 | | #include "detect-parse.h" |
36 | | |
37 | | #include "util-unittest.h" |
38 | | #include "util-byte.h" |
39 | | #include "util-debug.h" |
40 | | |
41 | 79 | #define PARSE_REGEX "([0x]*[0-9a-f]+)/([0x]*[0-9a-f]+)" |
42 | | |
43 | | static DetectParseRegex parse_regex; |
44 | | |
45 | | static int DetectMarkSetup (DetectEngineCtx *, Signature *, const char *); |
46 | | static int DetectMarkPacket(DetectEngineThreadCtx *det_ctx, Packet *p, |
47 | | const Signature *s, const SigMatchCtx *ctx); |
48 | | void DetectMarkDataFree(DetectEngineCtx *, void *ptr); |
49 | | #if defined UNITTESTS && defined NFQ |
50 | | static void MarkRegisterTests(void); |
51 | | #endif |
52 | | |
53 | | /** |
54 | | * \brief Registration function for nfq_set_mark: keyword |
55 | | */ |
56 | | |
57 | | void DetectMarkRegister (void) |
58 | 79 | { |
59 | 79 | sigmatch_table[DETECT_MARK].name = "nfq_set_mark"; |
60 | 79 | sigmatch_table[DETECT_MARK].Match = DetectMarkPacket; |
61 | 79 | sigmatch_table[DETECT_MARK].Setup = DetectMarkSetup; |
62 | 79 | sigmatch_table[DETECT_MARK].Free = DetectMarkDataFree; |
63 | | #if defined UNITTESTS && defined NFQ |
64 | | sigmatch_table[DETECT_MARK].RegisterTests = MarkRegisterTests; |
65 | | #endif |
66 | 79 | DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); |
67 | 79 | } |
68 | | |
69 | | #ifdef NFQ |
70 | | /** |
71 | | * \internal |
72 | | * \brief This function is used to parse mark options passed via mark: keyword |
73 | | * |
74 | | * \param rawstr Pointer to the user provided mark options |
75 | | * |
76 | | * \retval 0 on success |
77 | | * \retval < 0 on failure |
78 | | */ |
79 | | static void * DetectMarkParse (const char *rawstr) |
80 | | { |
81 | | int res = 0; |
82 | | size_t pcre2_len; |
83 | | const char *str_ptr = NULL; |
84 | | char *ptr = NULL; |
85 | | uint32_t mark; |
86 | | uint32_t mask; |
87 | | DetectMarkData *data; |
88 | | |
89 | | pcre2_match_data *match = NULL; |
90 | | int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0); |
91 | | if (ret < 1) { |
92 | | SCLogError("pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr); |
93 | | pcre2_match_data_free(match); |
94 | | return NULL; |
95 | | } |
96 | | |
97 | | res = pcre2_substring_get_bynumber(match, 1, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len); |
98 | | if (res < 0) { |
99 | | SCLogError("pcre2_substring_get_bynumber failed"); |
100 | | goto error; |
101 | | } |
102 | | |
103 | | ptr = (char *)str_ptr; |
104 | | |
105 | | if (ptr == NULL) |
106 | | goto error; |
107 | | |
108 | | if (ByteExtractStringUint32(&mark, 0, strlen(ptr), ptr) <= 0) { |
109 | | SCLogError("invalid input as arg to nfq_set_mark keyword"); |
110 | | pcre2_substring_free((PCRE2_UCHAR8 *)ptr); |
111 | | goto error; |
112 | | } |
113 | | |
114 | | res = pcre2_substring_get_bynumber(match, 2, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len); |
115 | | if (res < 0) { |
116 | | SCLogError("pcre2_substring_get_bynumber failed"); |
117 | | goto error; |
118 | | } |
119 | | |
120 | | pcre2_substring_free((PCRE2_UCHAR8 *)ptr); |
121 | | ptr = (char *)str_ptr; |
122 | | |
123 | | if (ptr == NULL) { |
124 | | data = SCMalloc(sizeof(DetectMarkData)); |
125 | | if (unlikely(data == NULL)) { |
126 | | goto error; |
127 | | } |
128 | | data->mark = mark; |
129 | | data->mask = 0xffff; |
130 | | pcre2_match_data_free(match); |
131 | | return data; |
132 | | } |
133 | | |
134 | | if (ByteExtractStringUint32(&mask, 0, strlen(ptr), ptr) <= 0) { |
135 | | SCLogError("invalid input as arg to nfq_set_mark keyword"); |
136 | | pcre2_substring_free((PCRE2_UCHAR8 *)ptr); |
137 | | goto error; |
138 | | } |
139 | | |
140 | | SCLogDebug("Rule will set mark 0x%x with mask 0x%x", mark, mask); |
141 | | pcre2_substring_free((PCRE2_UCHAR8 *)ptr); |
142 | | |
143 | | data = SCMalloc(sizeof(DetectMarkData)); |
144 | | if (unlikely(data == NULL)) { |
145 | | goto error; |
146 | | } |
147 | | data->mark = mark; |
148 | | data->mask = mask; |
149 | | pcre2_match_data_free(match); |
150 | | return data; |
151 | | |
152 | | error: |
153 | | if (match) { |
154 | | pcre2_match_data_free(match); |
155 | | } |
156 | | return NULL; |
157 | | } |
158 | | |
159 | | #endif /* NFQ */ |
160 | | |
161 | | /** |
162 | | * \internal |
163 | | * \brief this function is used to add the parsed mark into the current signature |
164 | | * |
165 | | * \param de_ctx pointer to the Detection Engine Context |
166 | | * \param s pointer to the Current Signature |
167 | | * \param rawstr pointer to the user provided mark options |
168 | | * |
169 | | * \retval 0 on Success |
170 | | * \retval -1 on Failure |
171 | | */ |
172 | | static int DetectMarkSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) |
173 | 428 | { |
174 | 428 | #ifndef NFQ |
175 | 428 | return 0; |
176 | | #else |
177 | | DetectMarkData *data = DetectMarkParse(rawstr); |
178 | | if (data == NULL) { |
179 | | return -1; |
180 | | } |
181 | | |
182 | | /* Append it to the list of post match, so the mark is set if the |
183 | | * full signature matches. */ |
184 | | if (SCSigMatchAppendSMToList( |
185 | | de_ctx, s, DETECT_MARK, (SigMatchCtx *)data, DETECT_SM_LIST_POSTMATCH) == NULL) { |
186 | | DetectMarkDataFree(de_ctx, data); |
187 | | return -1; |
188 | | } |
189 | | return 0; |
190 | | #endif |
191 | 428 | } |
192 | | |
193 | | void DetectMarkDataFree(DetectEngineCtx *de_ctx, void *ptr) |
194 | 0 | { |
195 | 0 | DetectMarkData *data = (DetectMarkData *)ptr; |
196 | 0 | SCFree(data); |
197 | 0 | } |
198 | | |
199 | | |
200 | | static int DetectMarkPacket(DetectEngineThreadCtx *det_ctx, Packet *p, |
201 | | const Signature *s, const SigMatchCtx *ctx) |
202 | 0 | { |
203 | | #ifdef NFQ |
204 | | const DetectMarkData *nf_data = (const DetectMarkData *)ctx; |
205 | | if (nf_data->mask) { |
206 | | if (PacketIsNotTunnel(p)) { |
207 | | /* for a non-tunnel packet we don't need a lock, |
208 | | * and if we're here we can't turn into a tunnel |
209 | | * packet anymore. */ |
210 | | |
211 | | /* coverity[missing_lock] */ |
212 | | p->nfq_v.mark = (nf_data->mark & nf_data->mask) |
213 | | | (p->nfq_v.mark & ~(nf_data->mask)); |
214 | | /* coverity[missing_lock] */ |
215 | | p->nfq_v.mark_modified = true; |
216 | | } else { |
217 | | /* real tunnels may have multiple flows inside them, so marking |
218 | | * might 'mark' too much. Rebuilt packets from IP fragments |
219 | | * are fine. */ |
220 | | if (p->flags & PKT_REBUILT_FRAGMENT) { |
221 | | Packet *tp = p->root ? p->root : p; |
222 | | SCSpinLock(&tp->persistent.tunnel_lock); |
223 | | tp->nfq_v.mark = (nf_data->mark & nf_data->mask) |
224 | | | (tp->nfq_v.mark & ~(nf_data->mask)); |
225 | | tp->nfq_v.mark_modified = true; |
226 | | SCSpinUnlock(&tp->persistent.tunnel_lock); |
227 | | } |
228 | | } |
229 | | } |
230 | | #endif |
231 | 0 | return 1; |
232 | 0 | } |
233 | | |
234 | | /* |
235 | | * ONLY TESTS BELOW THIS COMMENT |
236 | | */ |
237 | | |
238 | | #if defined UNITTESTS && defined NFQ |
239 | | /** |
240 | | * \test MarkTestParse01 is a test for a valid mark value |
241 | | * |
242 | | */ |
243 | | static int MarkTestParse01 (void) |
244 | | { |
245 | | DetectMarkData *data; |
246 | | |
247 | | data = DetectMarkParse("1/1"); |
248 | | |
249 | | FAIL_IF_NULL(data); |
250 | | FAIL_IF(data->mark != 1); |
251 | | FAIL_IF(data->mask != 1); |
252 | | |
253 | | DetectMarkDataFree(NULL, data); |
254 | | PASS; |
255 | | } |
256 | | |
257 | | /** |
258 | | * \test MarkTestParse02 is a test for an invalid mark value |
259 | | * |
260 | | */ |
261 | | static int MarkTestParse02 (void) |
262 | | { |
263 | | DetectMarkData *data; |
264 | | |
265 | | data = DetectMarkParse("4"); |
266 | | |
267 | | FAIL_IF_NOT_NULL(data); |
268 | | |
269 | | DetectMarkDataFree(NULL, data); |
270 | | PASS; |
271 | | } |
272 | | |
273 | | /** |
274 | | * \test MarkTestParse03 is a test for a valid mark value |
275 | | * |
276 | | */ |
277 | | static int MarkTestParse03 (void) |
278 | | { |
279 | | DetectMarkData *data; |
280 | | |
281 | | data = DetectMarkParse("0x10/0xff"); |
282 | | FAIL_IF(data->mark != 0x10); |
283 | | FAIL_IF(data->mask != 0xff); |
284 | | |
285 | | FAIL_IF_NULL(data); |
286 | | |
287 | | DetectMarkDataFree(NULL, data); |
288 | | PASS; |
289 | | } |
290 | | |
291 | | /** |
292 | | * \test MarkTestParse04 is a test for a invalid mark value |
293 | | * |
294 | | */ |
295 | | static int MarkTestParse04 (void) |
296 | | { |
297 | | DetectMarkData *data; |
298 | | |
299 | | data = DetectMarkParse("0x1g/0xff"); |
300 | | |
301 | | FAIL_IF_NOT_NULL(data); |
302 | | |
303 | | DetectMarkDataFree(NULL, data); |
304 | | PASS; |
305 | | } |
306 | | |
307 | | /** |
308 | | * \brief this function registers unit tests for Mark |
309 | | */ |
310 | | static void MarkRegisterTests(void) |
311 | | { |
312 | | UtRegisterTest("MarkTestParse01", MarkTestParse01); |
313 | | UtRegisterTest("MarkTestParse02", MarkTestParse02); |
314 | | UtRegisterTest("MarkTestParse03", MarkTestParse03); |
315 | | UtRegisterTest("MarkTestParse04", MarkTestParse04); |
316 | | } |
317 | | #endif /* UNITTESTS */ |