Coverage Report

Created: 2026-02-14 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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