/src/suricata7/src/detect-transform-strip-whitespace.c
Line | Count | Source |
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 | | * Implements the nocase keyword |
24 | | */ |
25 | | |
26 | | #include "suricata-common.h" |
27 | | |
28 | | #include "detect.h" |
29 | | #include "detect-engine.h" |
30 | | #include "detect-engine-prefilter.h" |
31 | | #include "detect-engine-build.h" |
32 | | #include "detect-parse.h" |
33 | | #include "detect-transform-strip-whitespace.h" |
34 | | |
35 | | #include "util-unittest.h" |
36 | | #include "util-print.h" |
37 | | |
38 | | static int DetectTransformStripWhitespaceSetup (DetectEngineCtx *, Signature *, const char *); |
39 | | #ifdef UNITTESTS |
40 | | static void DetectTransformStripWhitespaceRegisterTests(void); |
41 | | #endif |
42 | | static void TransformStripWhitespace(InspectionBuffer *buffer, void *options); |
43 | | static bool TransformStripWhitespaceValidate(const uint8_t *content, uint16_t content_len, void *options); |
44 | | |
45 | | void DetectTransformStripWhitespaceRegister(void) |
46 | 34 | { |
47 | 34 | sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].name = "strip_whitespace"; |
48 | 34 | sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].desc = |
49 | 34 | "modify buffer to strip whitespace before inspection"; |
50 | 34 | sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].url = |
51 | 34 | "/rules/transforms.html#strip-whitespace"; |
52 | 34 | sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].Transform = |
53 | 34 | TransformStripWhitespace; |
54 | 34 | sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].TransformValidate = |
55 | 34 | TransformStripWhitespaceValidate; |
56 | 34 | sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].Setup = |
57 | 34 | DetectTransformStripWhitespaceSetup; |
58 | | #ifdef UNITTESTS |
59 | | sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].RegisterTests = |
60 | | DetectTransformStripWhitespaceRegisterTests; |
61 | | #endif |
62 | 34 | sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].flags |= SIGMATCH_NOOPT; |
63 | 34 | } |
64 | | |
65 | | /** |
66 | | * \internal |
67 | | * \brief Apply the nocase keyword to the last pattern match, either content or uricontent |
68 | | * \param det_ctx detection engine ctx |
69 | | * \param s signature |
70 | | * \param nullstr should be null |
71 | | * \retval 0 ok |
72 | | * \retval -1 failure |
73 | | */ |
74 | | static int DetectTransformStripWhitespaceSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) |
75 | 20.7k | { |
76 | 20.7k | SCEnter(); |
77 | 20.7k | int r = DetectSignatureAddTransform(s, DETECT_TRANSFORM_STRIP_WHITESPACE, NULL); |
78 | 20.7k | SCReturnInt(r); |
79 | 20.7k | } |
80 | | |
81 | | /* |
82 | | * \brief Validate content bytes to see if it's compatible with this transform |
83 | | * \param content Byte array to check for compatibility |
84 | | * \param content_len Number of bytes to check |
85 | | * \param options Ignored |
86 | | * \retval false If the string contains spaces |
87 | | * \retval true Otherwise. |
88 | | */ |
89 | | static bool TransformStripWhitespaceValidate(const uint8_t *content, |
90 | | uint16_t content_len, void *options) |
91 | 14.8k | { |
92 | 14.8k | if (content) { |
93 | 141k | for (uint32_t i = 0; i < content_len; i++) { |
94 | 128k | if (isspace(*content++)) { |
95 | 2.19k | return false; |
96 | 2.19k | } |
97 | 128k | } |
98 | 14.8k | } |
99 | 12.7k | return true; |
100 | 14.8k | } |
101 | | |
102 | | static void TransformStripWhitespace(InspectionBuffer *buffer, void *options) |
103 | 812 | { |
104 | 812 | const uint8_t *input = buffer->inspect; |
105 | 812 | const uint32_t input_len = buffer->inspect_len; |
106 | 812 | if (input_len == 0) { |
107 | 0 | return; |
108 | 0 | } |
109 | | // we can only shrink |
110 | 812 | uint8_t *output = InspectionBufferCheckAndExpand(buffer, input_len); |
111 | 812 | if (output == NULL) { |
112 | 0 | return; |
113 | 0 | } |
114 | 812 | uint8_t *oi = output, *os = output; |
115 | | |
116 | | //PrintRawDataFp(stdout, input, input_len); |
117 | 727k | for (uint32_t i = 0; i < input_len; i++) { |
118 | 726k | if (!isspace(*input)) { |
119 | 702k | *oi++ = *input; |
120 | 702k | } |
121 | 726k | input++; |
122 | 726k | } |
123 | 812 | uint32_t output_size = oi - os; |
124 | | //PrintRawDataFp(stdout, output, output_size); |
125 | | |
126 | 812 | InspectionBufferTruncate(buffer, output_size); |
127 | 812 | } |
128 | | |
129 | | #ifdef UNITTESTS |
130 | | static int TransformDoubleWhitespace(InspectionBuffer *buffer) |
131 | | { |
132 | | const uint8_t *input = buffer->inspect; |
133 | | const uint32_t input_len = buffer->inspect_len; |
134 | | uint8_t output[input_len * 2]; // if all chars are whitespace this fits |
135 | | memset(&output, 0, input_len * 2); |
136 | | uint8_t *oi = output, *os = output; |
137 | | |
138 | | PrintRawDataFp(stdout, input, input_len); |
139 | | for (uint32_t i = 0; i < input_len; i++) { |
140 | | if (isspace(*input)) { |
141 | | *oi++ = *input; |
142 | | } |
143 | | *oi++ = *input; |
144 | | input++; |
145 | | } |
146 | | uint32_t output_size = oi - os; |
147 | | PrintRawDataFp(stdout, output, output_size); |
148 | | |
149 | | InspectionBufferCopy(buffer, os, output_size); |
150 | | return 0; |
151 | | } |
152 | | |
153 | | static int DetectTransformStripWhitespaceTest01(void) |
154 | | { |
155 | | const uint8_t *input = (const uint8_t *)" A B C D "; |
156 | | uint32_t input_len = strlen((char *)input); |
157 | | |
158 | | InspectionBuffer buffer; |
159 | | InspectionBufferInit(&buffer, 8); |
160 | | InspectionBufferSetup(NULL, -1, &buffer, input, input_len); |
161 | | PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); |
162 | | TransformStripWhitespace(&buffer, NULL); |
163 | | PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); |
164 | | InspectionBufferFree(&buffer); |
165 | | PASS; |
166 | | } |
167 | | |
168 | | static int DetectTransformStripWhitespaceTest02(void) |
169 | | { |
170 | | const uint8_t *input = (const uint8_t *)" A B C D "; |
171 | | uint32_t input_len = strlen((char *)input); |
172 | | |
173 | | InspectionBuffer buffer; |
174 | | InspectionBufferInit(&buffer, 8); |
175 | | InspectionBufferSetup(NULL, -1, &buffer, input, input_len); |
176 | | PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); |
177 | | TransformDoubleWhitespace(&buffer); |
178 | | PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); |
179 | | TransformDoubleWhitespace(&buffer); |
180 | | PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); |
181 | | TransformStripWhitespace(&buffer, NULL); |
182 | | PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); |
183 | | InspectionBufferFree(&buffer); |
184 | | PASS; |
185 | | } |
186 | | |
187 | | static int DetectTransformStripWhitespaceTest03(void) |
188 | | { |
189 | | const char rule[] = "alert http any any -> any any (http_request_line; strip_whitespace; content:\"GET/HTTP\"; sid:1;)"; |
190 | | ThreadVars th_v; |
191 | | DetectEngineThreadCtx *det_ctx = NULL; |
192 | | memset(&th_v, 0, sizeof(th_v)); |
193 | | |
194 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
195 | | FAIL_IF_NULL(de_ctx); |
196 | | Signature *s = DetectEngineAppendSig(de_ctx, rule); |
197 | | FAIL_IF_NULL(s); |
198 | | SigGroupBuild(de_ctx); |
199 | | DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); |
200 | | DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); |
201 | | DetectEngineCtxFree(de_ctx); |
202 | | PASS; |
203 | | } |
204 | | |
205 | | static void DetectTransformStripWhitespaceRegisterTests(void) |
206 | | { |
207 | | UtRegisterTest("DetectTransformStripWhitespaceTest01", |
208 | | DetectTransformStripWhitespaceTest01); |
209 | | UtRegisterTest("DetectTransformStripWhitespaceTest02", |
210 | | DetectTransformStripWhitespaceTest02); |
211 | | UtRegisterTest("DetectTransformStripWhitespaceTest03", |
212 | | DetectTransformStripWhitespaceTest03); |
213 | | } |
214 | | #endif |