/src/suricata7/src/detect-transform-compress-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 compress_whitespace transform 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-parse.h" |
32 | | #include "detect-transform-compress-whitespace.h" |
33 | | |
34 | | #include "util-unittest.h" |
35 | | #include "util-print.h" |
36 | | |
37 | | static int DetectTransformCompressWhitespaceSetup (DetectEngineCtx *, Signature *, const char *); |
38 | | #ifdef UNITTESTS |
39 | | static void DetectTransformCompressWhitespaceRegisterTests(void); |
40 | | #endif |
41 | | static void TransformCompressWhitespace(InspectionBuffer *buffer, void *options); |
42 | | static bool TransformCompressWhitespaceValidate( |
43 | | const uint8_t *content, uint16_t content_len, void *options); |
44 | | |
45 | | void DetectTransformCompressWhitespaceRegister(void) |
46 | 34 | { |
47 | 34 | sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].name = "compress_whitespace"; |
48 | 34 | sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].desc = |
49 | 34 | "modify buffer to compress consecutive whitespace characters " |
50 | 34 | "into a single one before inspection"; |
51 | 34 | sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].url = |
52 | 34 | "/rules/transforms.html#compress-whitespace"; |
53 | 34 | sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].Transform = |
54 | 34 | TransformCompressWhitespace; |
55 | 34 | sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].TransformValidate = |
56 | 34 | TransformCompressWhitespaceValidate; |
57 | 34 | sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].Setup = |
58 | 34 | DetectTransformCompressWhitespaceSetup; |
59 | | #ifdef UNITTESTS |
60 | | sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].RegisterTests = |
61 | | DetectTransformCompressWhitespaceRegisterTests; |
62 | | #endif |
63 | 34 | sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].flags |= SIGMATCH_NOOPT; |
64 | 34 | } |
65 | | |
66 | | /** |
67 | | * \internal |
68 | | * \brief Apply the compress_whitespace keyword to the last pattern match |
69 | | * \param det_ctx detection engine ctx |
70 | | * \param s signature |
71 | | * \param nullstr should be null |
72 | | * \retval 0 ok |
73 | | * \retval -1 failure |
74 | | */ |
75 | | static int DetectTransformCompressWhitespaceSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) |
76 | 704 | { |
77 | 704 | SCEnter(); |
78 | 704 | int r = DetectSignatureAddTransform(s, DETECT_TRANSFORM_COMPRESS_WHITESPACE, NULL); |
79 | 704 | SCReturnInt(r); |
80 | 704 | } |
81 | | |
82 | | /* |
83 | | * \brief Validate content bytes to see if it's compatible with this transform |
84 | | * \param content Byte array to check for compatibility |
85 | | * \param content_len Number of bytes to check |
86 | | * \param options Ignored |
87 | | * \retval false If the string contains spaces |
88 | | * \retval true Otherwise. |
89 | | */ |
90 | | static bool TransformCompressWhitespaceValidate( |
91 | | const uint8_t *content, uint16_t content_len, void *options) |
92 | 571 | { |
93 | 571 | if (content) { |
94 | 7.86k | for (uint32_t i = 0; i < content_len; i++) { |
95 | 7.30k | if (!isspace(*content++)) { |
96 | 6.50k | continue; |
97 | 6.50k | } |
98 | 797 | if ((i + 1) < content_len && isspace(*content)) { |
99 | 9 | return false; |
100 | 9 | } |
101 | 797 | } |
102 | 571 | } |
103 | 562 | return true; |
104 | 571 | } |
105 | | |
106 | | static void TransformCompressWhitespace(InspectionBuffer *buffer, void *options) |
107 | 735 | { |
108 | 735 | const uint8_t *input = buffer->inspect; |
109 | 735 | const uint32_t input_len = buffer->inspect_len; |
110 | 735 | if (input_len == 0) { |
111 | 0 | return; |
112 | 0 | } |
113 | | |
114 | | // we can only shrink |
115 | 735 | uint8_t *output = InspectionBufferCheckAndExpand(buffer, input_len); |
116 | 735 | if (output == NULL) { |
117 | 0 | return; |
118 | 0 | } |
119 | 735 | uint8_t *oi = output, *os = output; |
120 | | |
121 | | //PrintRawDataFp(stdout, input, input_len); |
122 | 392k | for (uint32_t i = 0; i < input_len; ) { |
123 | 391k | if (!(isspace(*input))) { |
124 | 378k | *oi++ = *input++; |
125 | 378k | i++; |
126 | 378k | } else { |
127 | 12.9k | *oi++ = *input++; |
128 | 12.9k | i++; |
129 | | |
130 | 19.1k | while (i < input_len && isspace(*input)) { |
131 | 6.14k | input++; |
132 | 6.14k | i++; |
133 | 6.14k | } |
134 | 12.9k | } |
135 | 391k | } |
136 | 735 | uint32_t output_size = oi - os; |
137 | | //PrintRawDataFp(stdout, output, output_size); |
138 | | |
139 | 735 | InspectionBufferTruncate(buffer, output_size); |
140 | 735 | } |
141 | | |
142 | | #ifdef UNITTESTS |
143 | | static int TransformDoubleWhitespace(InspectionBuffer *buffer) |
144 | | { |
145 | | const uint8_t *input = buffer->inspect; |
146 | | const uint32_t input_len = buffer->inspect_len; |
147 | | uint8_t output[input_len * 2]; // if all chars are whitespace this fits |
148 | | memset(&output, 0, input_len * 2); |
149 | | uint8_t *oi = output, *os = output; |
150 | | |
151 | | PrintRawDataFp(stdout, input, input_len); |
152 | | for (uint32_t i = 0; i < input_len; i++) { |
153 | | if (isspace(*input)) { |
154 | | *oi++ = *input; |
155 | | } |
156 | | *oi++ = *input; |
157 | | input++; |
158 | | } |
159 | | uint32_t output_size = oi - os; |
160 | | PrintRawDataFp(stdout, output, output_size); |
161 | | |
162 | | InspectionBufferCopy(buffer, os, output_size); |
163 | | return 0; |
164 | | } |
165 | | |
166 | | static int DetectTransformCompressWhitespaceTest01(void) |
167 | | { |
168 | | const uint8_t *input = (const uint8_t *)" A B C D "; |
169 | | uint32_t input_len = strlen((char *)input); |
170 | | |
171 | | InspectionBuffer buffer; |
172 | | InspectionBufferInit(&buffer, 9); |
173 | | InspectionBufferSetup(NULL, -1, &buffer, input, input_len); |
174 | | PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); |
175 | | TransformCompressWhitespace(&buffer, NULL); |
176 | | PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); |
177 | | InspectionBufferFree(&buffer); |
178 | | PASS; |
179 | | } |
180 | | |
181 | | static int DetectTransformCompressWhitespaceTest02(void) |
182 | | { |
183 | | const uint8_t *input = (const uint8_t *)" A B C D "; |
184 | | uint32_t input_len = strlen((char *)input); |
185 | | |
186 | | InspectionBuffer buffer; |
187 | | InspectionBufferInit(&buffer, 9); |
188 | | InspectionBufferSetup(NULL, -1, &buffer, input, input_len); |
189 | | PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); |
190 | | TransformDoubleWhitespace(&buffer); |
191 | | PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); |
192 | | TransformDoubleWhitespace(&buffer); |
193 | | PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); |
194 | | TransformCompressWhitespace(&buffer, NULL); |
195 | | PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); |
196 | | InspectionBufferFree(&buffer); |
197 | | PASS; |
198 | | } |
199 | | |
200 | | static int DetectTransformCompressWhitespaceTest03(void) |
201 | | { |
202 | | const uint8_t *input = (const uint8_t *)" A B C D "; |
203 | | uint32_t input_len = strlen((char *)input); |
204 | | |
205 | | InspectionBuffer buffer; |
206 | | InspectionBufferInit(&buffer, 10); |
207 | | InspectionBufferSetup(NULL, -1, &buffer, input, input_len); |
208 | | PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); |
209 | | FAIL_IF(TransformCompressWhitespaceValidate(buffer.inspect, buffer.inspect_len, NULL)); |
210 | | PASS; |
211 | | } |
212 | | |
213 | | static int DetectTransformCompressWhitespaceTest04(void) |
214 | | { |
215 | | const uint8_t *input = (const uint8_t *)" A B C D "; |
216 | | uint32_t input_len = strlen((char *)input); |
217 | | |
218 | | InspectionBuffer buffer; |
219 | | InspectionBufferInit(&buffer, 9); |
220 | | InspectionBufferSetup(NULL, -1, &buffer, input, input_len); |
221 | | TransformDoubleWhitespace(&buffer); |
222 | | PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); |
223 | | FAIL_IF(TransformCompressWhitespaceValidate(buffer.inspect, buffer.inspect_len, NULL)); |
224 | | PASS; |
225 | | } |
226 | | |
227 | | static void DetectTransformCompressWhitespaceRegisterTests(void) |
228 | | { |
229 | | UtRegisterTest("DetectTransformCompressWhitespaceTest01", |
230 | | DetectTransformCompressWhitespaceTest01); |
231 | | UtRegisterTest("DetectTransformCompressWhitespaceTest02", |
232 | | DetectTransformCompressWhitespaceTest02); |
233 | | UtRegisterTest( |
234 | | "DetectTransformCompressWhitespaceTest03", DetectTransformCompressWhitespaceTest03); |
235 | | UtRegisterTest( |
236 | | "DetectTransformCompressWhitespaceTest04", DetectTransformCompressWhitespaceTest04); |
237 | | } |
238 | | #endif |