Coverage Report

Created: 2026-09-06 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/rust/src/detect/transforms/casechange.rs
Line
Count
Source
1
/* Copyright (C) 2024 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
use crate::detect::SIGMATCH_NOOPT;
19
use suricata_sys::sys::{
20
    DetectEngineCtx, DetectEngineThreadCtx, InspectionBuffer, SCDetectHelperTransformRegister,
21
    SCDetectSignatureAddTransform, SCInspectionBufferCheckAndExpand, SCInspectionBufferTruncate,
22
    SCTransformTableElmt, Signature,
23
};
24
25
use std::os::raw::{c_int, c_void};
26
use std::ptr;
27
28
static mut G_TRANSFORM_TOLOWER_ID: c_int = 0;
29
static mut G_TRANSFORM_TOUPPER_ID: c_int = 0;
30
31
6
unsafe extern "C" fn tolower_setup(
32
6
    _de: *mut DetectEngineCtx, s: *mut Signature, _raw: *const std::os::raw::c_char,
33
6
) -> c_int {
34
6
    return SCDetectSignatureAddTransform(s, G_TRANSFORM_TOLOWER_ID, ptr::null_mut());
35
6
}
36
37
0
fn tolower_transform_do(input: &[u8], output: &mut [u8]) {
38
0
    for (i, o) in input.iter().zip(output.iter_mut()) {
39
0
        *o = (*i).to_ascii_lowercase();
40
0
    }
41
0
}
42
43
0
unsafe extern "C" fn tolower_transform(
44
0
    _det: *mut DetectEngineThreadCtx, buffer: *mut InspectionBuffer, _ctx: *mut c_void,
45
0
) {
46
0
    let input = (*buffer).inspect;
47
0
    let input_len = (*buffer).inspect_len;
48
0
    if input.is_null() || input_len == 0 {
49
0
        return;
50
0
    }
51
0
    let input = build_slice!(input, input_len as usize);
52
53
0
    let output = SCInspectionBufferCheckAndExpand(buffer, input_len);
54
0
    if output.is_null() {
55
        // allocation failure
56
0
        return;
57
0
    }
58
0
    let output = std::slice::from_raw_parts_mut(output, input_len as usize);
59
60
0
    tolower_transform_do(input, output);
61
62
0
    SCInspectionBufferTruncate(buffer, input_len);
63
0
}
64
65
5
unsafe extern "C" fn tolower_validate(content: *const u8, len: u16, _ctx: *mut c_void) -> bool {
66
5
    let input = build_slice!(content, len as usize);
67
225
    for &c in input {
68
221
        if c.is_ascii_uppercase() {
69
1
            return false;
70
220
        }
71
    }
72
4
    return true;
73
5
}
74
75
#[no_mangle]
76
39
pub unsafe extern "C" fn DetectTransformToLowerRegister() {
77
39
    let kw = SCTransformTableElmt {
78
39
        name: b"to_lowercase\0".as_ptr() as *const libc::c_char,
79
39
        desc: b"convert buffer to lowercase\0".as_ptr() as *const libc::c_char,
80
39
        url: b"/rules/transforms.html#to_lowercase\0".as_ptr() as *const libc::c_char,
81
39
        Setup: Some(tolower_setup),
82
39
        flags: SIGMATCH_NOOPT,
83
39
        Transform: Some(tolower_transform),
84
39
        Free: None,
85
39
        TransformValidate: Some(tolower_validate),
86
39
        TransformId: None,
87
39
    };
88
39
    G_TRANSFORM_TOLOWER_ID = SCDetectHelperTransformRegister(&kw);
89
39
    if G_TRANSFORM_TOLOWER_ID < 0 {
90
0
        SCLogWarning!("Failed registering transform tolower");
91
39
    }
92
39
}
93
94
3
unsafe extern "C" fn toupper_setup(
95
3
    _de: *mut DetectEngineCtx, s: *mut Signature, _raw: *const std::os::raw::c_char,
96
3
) -> c_int {
97
3
    return SCDetectSignatureAddTransform(s, G_TRANSFORM_TOUPPER_ID, ptr::null_mut());
98
3
}
99
100
0
fn toupper_transform_do(input: &[u8], output: &mut [u8]) {
101
0
    for (i, o) in input.iter().zip(output.iter_mut()) {
102
0
        *o = (*i).to_ascii_uppercase();
103
0
    }
104
0
}
105
106
0
unsafe extern "C" fn toupper_transform(
107
0
    _det: *mut DetectEngineThreadCtx, buffer: *mut InspectionBuffer, _ctx: *mut c_void,
108
0
) {
109
0
    let input = (*buffer).inspect;
110
0
    let input_len = (*buffer).inspect_len;
111
0
    if input.is_null() || input_len == 0 {
112
0
        return;
113
0
    }
114
0
    let input = build_slice!(input, input_len as usize);
115
116
0
    let output = SCInspectionBufferCheckAndExpand(buffer, input_len);
117
0
    if output.is_null() {
118
        // allocation failure
119
0
        return;
120
0
    }
121
0
    let output = std::slice::from_raw_parts_mut(output, input_len as usize);
122
123
0
    toupper_transform_do(input, output);
124
125
0
    SCInspectionBufferTruncate(buffer, input_len);
126
0
}
127
128
3
unsafe extern "C" fn toupper_validate(content: *const u8, len: u16, _ctx: *mut c_void) -> bool {
129
3
    let input = build_slice!(content, len as usize);
130
38
    for &c in input {
131
37
        if c.is_ascii_lowercase() {
132
2
            return false;
133
35
        }
134
    }
135
1
    return true;
136
3
}
137
138
#[no_mangle]
139
39
pub unsafe extern "C" fn DetectTransformToUpperRegister() {
140
39
    let kw = SCTransformTableElmt {
141
39
        name: b"to_uppercase\0".as_ptr() as *const libc::c_char,
142
39
        desc: b"convert buffer to uppercase\0".as_ptr() as *const libc::c_char,
143
39
        url: b"/rules/transforms.html#to_uppercase\0".as_ptr() as *const libc::c_char,
144
39
        Setup: Some(toupper_setup),
145
39
        flags: SIGMATCH_NOOPT,
146
39
        Transform: Some(toupper_transform),
147
39
        Free: None,
148
39
        TransformValidate: Some(toupper_validate),
149
39
        TransformId: None,
150
39
    };
151
39
    G_TRANSFORM_TOUPPER_ID = SCDetectHelperTransformRegister(&kw);
152
39
    if G_TRANSFORM_TOUPPER_ID < 0 {
153
0
        SCLogWarning!("Failed registering transform toupper");
154
39
    }
155
39
}
156
157
#[cfg(test)]
158
mod tests {
159
    use super::*;
160
161
    #[test]
162
    fn test_tolower_transform() {
163
        let buf = b" A b C D ";
164
        let mut out = vec![0; buf.len()];
165
        tolower_transform_do(buf, &mut out);
166
        assert_eq!(out, b" a b c d ");
167
    }
168
169
    #[test]
170
    fn test_toupper_transform() {
171
        let buf = b" A b C D ";
172
        let mut out = vec![0; buf.len()];
173
        toupper_transform_do(buf, &mut out);
174
        assert_eq!(out, b" A B C D ");
175
    }
176
}