• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 23374838686

21 Mar 2026 07:29AM UTC coverage: 59.341% (-20.0%) from 79.315%
23374838686

Pull #15075

github

web-flow
Merge 90b4e834f into 6587e363a
Pull Request #15075: Stack 8001 v16.4

38 of 70 new or added lines in 10 files covered. (54.29%)

34165 existing lines in 563 files now uncovered.

119621 of 201584 relevant lines covered (59.34%)

650666.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.0
/rust/src/ssh/detect.rs
1
/* Copyright (C) 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
use super::ssh::{
19
    SCSshEnableHassh, SCSshHasshIsEnabled, SSHConnectionState, SSHTransaction, ALPROTO_SSH,
20
};
21
use crate::core::{STREAM_TOCLIENT, STREAM_TOSERVER};
22
use crate::detect::{helper_keyword_register_sticky_buffer, SigTableElmtStickyBuffer};
23
use crate::direction::Direction;
24
use std::os::raw::{c_int, c_void};
25
use std::ptr;
26
use suricata_sys::sys::{
27
    DetectEngineCtx, SCDetectBufferSetActiveList, SCDetectHelperBufferProgressMpmRegister,
28
    SCDetectHelperKeywordAliasRegister, SCDetectHelperKeywordRegister,
29
    SCDetectRegisterBufferLowerMd5Callbacks, SCDetectSignatureSetAppProto,
30
    SCSigMatchSilentErrorEnabled, SCSigTableAppLiteElmt, Signature,
31
};
32

33
#[no_mangle]
34
pub unsafe extern "C" fn SCSshTxGetProtocol(
37✔
35
    tx: *const c_void, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32,
37✔
36
) -> bool {
37✔
37
    let tx = cast_pointer!(tx, SSHTransaction);
37✔
38
    match direction.into() {
37✔
39
        Direction::ToServer => {
40
            let m = &tx.cli_hdr.protover;
36✔
41
            if !m.is_empty() {
36✔
42
                *buffer = m.as_ptr();
36✔
43
                *buffer_len = m.len() as u32;
36✔
44
                return true;
36✔
UNCOV
45
            }
×
46
        }
47
        Direction::ToClient => {
48
            let m = &tx.srv_hdr.protover;
1✔
49
            if !m.is_empty() {
1✔
50
                *buffer = m.as_ptr();
1✔
51
                *buffer_len = m.len() as u32;
1✔
52
                return true;
1✔
UNCOV
53
            }
×
54
        }
55
    }
UNCOV
56
    *buffer = ptr::null();
×
UNCOV
57
    *buffer_len = 0;
×
UNCOV
58

×
UNCOV
59
    return false;
×
60
}
37✔
61

62
#[no_mangle]
63
pub unsafe extern "C" fn SCSshTxGetSoftware(
3✔
64
    tx: *const c_void, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32,
3✔
65
) -> bool {
3✔
66
    let tx = cast_pointer!(tx, SSHTransaction);
3✔
67
    match direction.into() {
3✔
68
        Direction::ToServer => {
69
            let m = &tx.cli_hdr.swver;
2✔
70
            if !m.is_empty() {
2✔
71
                *buffer = m.as_ptr();
2✔
72
                *buffer_len = m.len() as u32;
2✔
73
                return true;
2✔
UNCOV
74
            }
×
75
        }
76
        Direction::ToClient => {
77
            let m = &tx.srv_hdr.swver;
1✔
78
            if !m.is_empty() {
1✔
79
                *buffer = m.as_ptr();
1✔
80
                *buffer_len = m.len() as u32;
1✔
81
                return true;
1✔
UNCOV
82
            }
×
83
        }
84
    }
UNCOV
85
    *buffer = ptr::null();
×
UNCOV
86
    *buffer_len = 0;
×
UNCOV
87
    return false;
×
88
}
3✔
89

90
#[no_mangle]
91
pub unsafe extern "C" fn SCSshTxGetHassh(
258✔
92
    tx: *const c_void, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32,
258✔
93
) -> bool {
258✔
94
    let tx = cast_pointer!(tx, SSHTransaction);
258✔
95
    match direction.into() {
258✔
96
        Direction::ToServer => {
97
            let m = &tx.cli_hdr.hassh;
131✔
98
            if !m.is_empty() {
131✔
99
                *buffer = m.as_ptr();
51✔
100
                *buffer_len = m.len() as u32;
51✔
101
                return true;
51✔
102
            }
80✔
103
        }
104
        Direction::ToClient => {
105
            let m = &tx.srv_hdr.hassh;
127✔
106
            if !m.is_empty() {
127✔
107
                *buffer = m.as_ptr();
64✔
108
                *buffer_len = m.len() as u32;
64✔
109
                return true;
64✔
110
            }
63✔
111
        }
112
    }
113
    *buffer = ptr::null();
143✔
114
    *buffer_len = 0;
143✔
115

143✔
116
    return false;
143✔
117
}
258✔
118

119
#[no_mangle]
120
pub unsafe extern "C" fn SCSshTxGetHasshString(
240✔
121
    tx: *const c_void, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32,
240✔
122
) -> bool {
240✔
123
    let tx = cast_pointer!(tx, SSHTransaction);
240✔
124
    match direction.into() {
240✔
125
        Direction::ToServer => {
126
            let m = &tx.cli_hdr.hassh_string;
123✔
127
            if !m.is_empty() {
123✔
128
                *buffer = m.as_ptr();
49✔
129
                *buffer_len = m.len() as u32;
49✔
130
                return true;
49✔
131
            }
74✔
132
        }
133
        Direction::ToClient => {
134
            let m = &tx.srv_hdr.hassh_string;
117✔
135
            if !m.is_empty() {
117✔
136
                *buffer = m.as_ptr();
60✔
137
                *buffer_len = m.len() as u32;
60✔
138
                return true;
60✔
139
            }
57✔
140
        }
141
    }
142
    *buffer = ptr::null();
131✔
143
    *buffer_len = 0;
131✔
144

131✔
145
    return false;
131✔
146
}
240✔
147

148
unsafe extern "C" fn ssh_software_setup(
131✔
149
    de: *mut DetectEngineCtx, s: *mut Signature, _raw: *const std::os::raw::c_char,
131✔
150
) -> c_int {
131✔
151
    if SCDetectSignatureSetAppProto(s, ALPROTO_SSH) != 0 {
131✔
152
        return -1;
51✔
153
    }
80✔
154
    if SCDetectBufferSetActiveList(de, s, G_SSH_SOFTWARE_BUFFER_ID) < 0 {
80✔
155
        return -1;
1✔
156
    }
79✔
157
    return 0;
79✔
158
}
131✔
159

160
unsafe extern "C" fn ssh_proto_setup(
141✔
161
    de: *mut DetectEngineCtx, s: *mut Signature, _raw: *const std::os::raw::c_char,
141✔
162
) -> c_int {
141✔
163
    if SCDetectSignatureSetAppProto(s, ALPROTO_SSH) != 0 {
141✔
164
        return -1;
18✔
165
    }
123✔
166
    if SCDetectBufferSetActiveList(de, s, G_SSH_PROTO_BUFFER_ID) < 0 {
123✔
167
        return -1;
×
168
    }
123✔
169
    return 0;
123✔
170
}
141✔
171

172
unsafe extern "C" fn ssh_hassh_string_setup(
3,755✔
173
    de: *mut DetectEngineCtx, s: *mut Signature, _raw: *const std::os::raw::c_char,
3,755✔
174
) -> c_int {
3,755✔
175
    if SCDetectSignatureSetAppProto(s, ALPROTO_SSH) != 0 {
3,755✔
176
        return -1;
770✔
177
    }
2,985✔
178
    if SCDetectBufferSetActiveList(de, s, G_SSH_HASSH_STR_BUFFER_ID) < 0 {
2,985✔
179
        return -1;
372✔
180
    }
2,613✔
181
    /* try to enable Hassh */
2,613✔
182
    SCSshEnableHassh();
2,613✔
183

2,613✔
184
    /* Check if Hassh is disabled */
2,613✔
185
    if !SCSshHasshIsEnabled() {
2,613✔
UNCOV
186
        if !SCSigMatchSilentErrorEnabled(de, DETECT_SSH_HASSH_STRING) {
×
UNCOV
187
            SCLogError!("hassh support is not enabled");
×
188
        }
×
UNCOV
189
        return -2;
×
190
    }
2,613✔
191
    return 0;
2,613✔
192
}
3,755✔
193

194
unsafe extern "C" fn ssh_hassh_server_string_setup(
1,637✔
195
    de: *mut DetectEngineCtx, s: *mut Signature, _raw: *const std::os::raw::c_char,
1,637✔
196
) -> c_int {
1,637✔
197
    if SCDetectSignatureSetAppProto(s, ALPROTO_SSH) != 0 {
1,637✔
198
        return -1;
245✔
199
    }
1,392✔
200
    if SCDetectBufferSetActiveList(de, s, G_SSH_HASSH_SRV_STR_BUFFER_ID) < 0 {
1,392✔
201
        return -1;
1✔
202
    }
1,391✔
203
    /* try to enable Hassh */
1,391✔
204
    SCSshEnableHassh();
1,391✔
205

1,391✔
206
    /* Check if Hassh is disabled */
1,391✔
207
    if !SCSshHasshIsEnabled() {
1,391✔
UNCOV
208
        if !SCSigMatchSilentErrorEnabled(de, DETECT_SSH_HASSH_SERVER_STRING) {
×
UNCOV
209
            SCLogError!("hassh support is not enabled");
×
210
        }
×
UNCOV
211
        return -2;
×
212
    }
1,391✔
213
    return 0;
1,391✔
214
}
1,637✔
215

216
unsafe extern "C" fn ssh_hassh_setup(
10,202✔
217
    de: *mut DetectEngineCtx, s: *mut Signature, _raw: *const std::os::raw::c_char,
10,202✔
218
) -> c_int {
10,202✔
219
    if SCDetectSignatureSetAppProto(s, ALPROTO_SSH) != 0 {
10,202✔
220
        return -1;
491✔
221
    }
9,711✔
222
    if SCDetectBufferSetActiveList(de, s, G_SSH_HASSH_BUFFER_ID) < 0 {
9,711✔
223
        return -1;
12✔
224
    }
9,699✔
225
    /* try to enable Hassh */
9,699✔
226
    SCSshEnableHassh();
9,699✔
227

9,699✔
228
    /* Check if Hassh is disabled */
9,699✔
229
    if !SCSshHasshIsEnabled() {
9,699✔
UNCOV
230
        if !SCSigMatchSilentErrorEnabled(de, DETECT_SSH_HASSH) {
×
UNCOV
231
            SCLogError!("hassh support is not enabled");
×
232
        }
×
UNCOV
233
        return -2;
×
234
    }
9,699✔
235
    return 0;
9,699✔
236
}
10,202✔
237

238
unsafe extern "C" fn ssh_hassh_server_setup(
6,241✔
239
    de: *mut DetectEngineCtx, s: *mut Signature, _raw: *const std::os::raw::c_char,
6,241✔
240
) -> c_int {
6,241✔
241
    if SCDetectSignatureSetAppProto(s, ALPROTO_SSH) != 0 {
6,241✔
242
        return -1;
109✔
243
    }
6,132✔
244
    if SCDetectBufferSetActiveList(de, s, G_SSH_HASSH_SRV_BUFFER_ID) < 0 {
6,132✔
245
        return -1;
184✔
246
    }
5,948✔
247
    /* try to enable Hassh */
5,948✔
248
    SCSshEnableHassh();
5,948✔
249

5,948✔
250
    /* Check if Hassh is disabled */
5,948✔
251
    if !SCSshHasshIsEnabled() {
5,948✔
UNCOV
252
        if !SCSigMatchSilentErrorEnabled(de, DETECT_SSH_HASSH_SERVER) {
×
UNCOV
253
            SCLogError!("hassh support is not enabled");
×
254
        }
×
UNCOV
255
        return -2;
×
256
    }
5,948✔
257
    return 0;
5,948✔
258
}
6,241✔
259

260
unsafe extern "C" fn ssh_software_obsolete_setup(
727✔
261
    _de: *mut DetectEngineCtx, _s: *mut Signature, _raw: *const std::os::raw::c_char,
727✔
262
) -> c_int {
727✔
263
    SCLogError!("ssh.softwareversion is obsolete, use now ssh.software");
727✔
264
    return -1;
727✔
265
}
727✔
266

267
unsafe extern "C" fn ssh_proto_obsolete_setup(
28✔
268
    _de: *mut DetectEngineCtx, _s: *mut Signature, _raw: *const std::os::raw::c_char,
28✔
269
) -> c_int {
28✔
270
    SCLogError!("ssh.softwareversion is obsolete, use now ssh.software");
28✔
271
    return -1;
28✔
272
}
28✔
273

274
static mut G_SSH_SOFTWARE_BUFFER_ID: c_int = 0;
275
static mut G_SSH_PROTO_BUFFER_ID: c_int = 0;
276
static mut G_SSH_HASSH_STR_BUFFER_ID: c_int = 0;
277
static mut G_SSH_HASSH_SRV_STR_BUFFER_ID: c_int = 0;
278
static mut G_SSH_HASSH_BUFFER_ID: c_int = 0;
279
static mut G_SSH_HASSH_SRV_BUFFER_ID: c_int = 0;
280

281
static mut DETECT_SSH_HASSH_STRING: u16 = 0;
282
static mut DETECT_SSH_HASSH_SERVER_STRING: u16 = 0;
283
static mut DETECT_SSH_HASSH: u16 = 0;
284
static mut DETECT_SSH_HASSH_SERVER: u16 = 0;
285

286
#[no_mangle]
287
pub unsafe extern "C" fn SCDetectSshRegister() {
3✔
288
    let kw = SigTableElmtStickyBuffer {
3✔
289
        name: String::from("ssh.software"),
3✔
290
        desc: String::from("ssh.software sticky buffer"),
3✔
291
        url: String::from("/rules/ssh-keywords.html#ssh-software"),
3✔
292
        setup: ssh_software_setup,
3✔
293
    };
3✔
294
    let ssh_software_kw_id = helper_keyword_register_sticky_buffer(&kw);
3✔
295
    G_SSH_SOFTWARE_BUFFER_ID = SCDetectHelperBufferProgressMpmRegister(
3✔
296
        b"ssh_software\0".as_ptr() as *const libc::c_char,
3✔
297
        b"ssh software field\0".as_ptr() as *const libc::c_char,
3✔
298
        ALPROTO_SSH,
3✔
299
        STREAM_TOSERVER | STREAM_TOCLIENT,
3✔
300
        Some(SCSshTxGetSoftware),
3✔
301
        SSHConnectionState::SshStateBannerDone as c_int,
3✔
302
    );
3✔
303
    SCDetectHelperKeywordAliasRegister(
3✔
304
        ssh_software_kw_id,
3✔
305
        b"ssh_software\0".as_ptr() as *const libc::c_char,
3✔
306
    );
3✔
307

3✔
308
    let kw = SCSigTableAppLiteElmt {
3✔
309
        name: b"ssh.softwareversion\0".as_ptr() as *const libc::c_char,
3✔
310
        desc: b"obsolete keyword, use now ssh.software\0".as_ptr() as *const libc::c_char,
3✔
311
        url: std::ptr::null(),
3✔
312
        AppLayerTxMatch: None,
3✔
313
        Setup: Some(ssh_software_obsolete_setup),
3✔
314
        Free: None,
3✔
315
        flags: 0,
3✔
316
    };
3✔
317
    _ = SCDetectHelperKeywordRegister(&kw);
3✔
318

3✔
319
    let kw = SCSigTableAppLiteElmt {
3✔
320
        name: b"ssh.protoversion\0".as_ptr() as *const libc::c_char,
3✔
321
        desc: b"obsolete keyword, use now ssh.proto\0".as_ptr() as *const libc::c_char,
3✔
322
        url: std::ptr::null(),
3✔
323
        AppLayerTxMatch: None,
3✔
324
        Setup: Some(ssh_proto_obsolete_setup),
3✔
325
        Free: None,
3✔
326
        flags: 0,
3✔
327
    };
3✔
328
    _ = SCDetectHelperKeywordRegister(&kw);
3✔
329

3✔
330
    let kw = SigTableElmtStickyBuffer {
3✔
331
        name: String::from("ssh.proto"),
3✔
332
        desc: String::from("ssh.proto sticky buffer"),
3✔
333
        url: String::from("/rules/ssh-keywords.html#ssh-proto"),
3✔
334
        setup: ssh_proto_setup,
3✔
335
    };
3✔
336
    let ssh_proto_kw_id = helper_keyword_register_sticky_buffer(&kw);
3✔
337
    G_SSH_PROTO_BUFFER_ID = SCDetectHelperBufferProgressMpmRegister(
3✔
338
        b"ssh.proto\0".as_ptr() as *const libc::c_char,
3✔
339
        b"ssh protocol version field\0".as_ptr() as *const libc::c_char,
3✔
340
        ALPROTO_SSH,
3✔
341
        STREAM_TOSERVER | STREAM_TOCLIENT,
3✔
342
        Some(SCSshTxGetProtocol),
3✔
343
        SSHConnectionState::SshStateBannerDone as c_int,
3✔
344
    );
3✔
345
    SCDetectHelperKeywordAliasRegister(
3✔
346
        ssh_proto_kw_id,
3✔
347
        b"ssh_proto\0".as_ptr() as *const libc::c_char,
3✔
348
    );
3✔
349

3✔
350
    let kw = SigTableElmtStickyBuffer {
3✔
351
        name: String::from("ssh.hassh.string"),
3✔
352
        desc: String::from("ssh.hassh.string sticky buffer"),
3✔
353
        url: String::from("/rules/ssh-keywords.html#hassh.string"),
3✔
354
        setup: ssh_hassh_string_setup,
3✔
355
    };
3✔
356
    DETECT_SSH_HASSH_STRING = helper_keyword_register_sticky_buffer(&kw);
3✔
357
    G_SSH_HASSH_STR_BUFFER_ID = SCDetectHelperBufferProgressMpmRegister(
3✔
358
        b"ssh.hassh.string\0".as_ptr() as *const libc::c_char,
3✔
359
        b"Ssh Client Key Exchange methods For ssh Clients\0".as_ptr() as *const libc::c_char,
3✔
360
        ALPROTO_SSH,
3✔
361
        STREAM_TOSERVER,
3✔
362
        Some(SCSshTxGetHasshString),
3✔
363
        SSHConnectionState::SshStateBannerDone as c_int,
3✔
364
    );
3✔
365
    SCDetectHelperKeywordAliasRegister(
3✔
366
        DETECT_SSH_HASSH_STRING,
3✔
367
        b"ssh-hassh-string\0".as_ptr() as *const libc::c_char,
3✔
368
    );
3✔
369

3✔
370
    let kw = SigTableElmtStickyBuffer {
3✔
371
        name: String::from("ssh.hassh.server.string"),
3✔
372
        desc: String::from("ssh.hassh.server.string sticky buffer"),
3✔
373
        url: String::from("/rules/ssh-keywords.html#ssh.hassh.server.string"),
3✔
374
        setup: ssh_hassh_server_string_setup,
3✔
375
    };
3✔
376
    DETECT_SSH_HASSH_SERVER_STRING = helper_keyword_register_sticky_buffer(&kw);
3✔
377
    G_SSH_HASSH_SRV_STR_BUFFER_ID = SCDetectHelperBufferProgressMpmRegister(
3✔
378
        b"ssh.hassh.server.string\0".as_ptr() as *const libc::c_char,
3✔
379
        b"Ssh Client Key Exchange methods For ssh Servers\0".as_ptr() as *const libc::c_char,
3✔
380
        ALPROTO_SSH,
3✔
381
        STREAM_TOCLIENT,
3✔
382
        Some(SCSshTxGetHasshString),
3✔
383
        SSHConnectionState::SshStateBannerDone as c_int,
3✔
384
    );
3✔
385
    SCDetectHelperKeywordAliasRegister(
3✔
386
        DETECT_SSH_HASSH_SERVER_STRING,
3✔
387
        b"ssh-hassh-server-string\0".as_ptr() as *const libc::c_char,
3✔
388
    );
3✔
389

3✔
390
    let kw = SigTableElmtStickyBuffer {
3✔
391
        name: String::from("ssh.hassh"),
3✔
392
        desc: String::from("ssh.hassh sticky buffer"),
3✔
393
        url: String::from("/rules/ssh-keywords.html#hassh"),
3✔
394
        setup: ssh_hassh_setup,
3✔
395
    };
3✔
396
    DETECT_SSH_HASSH = helper_keyword_register_sticky_buffer(&kw);
3✔
397
    G_SSH_HASSH_BUFFER_ID = SCDetectHelperBufferProgressMpmRegister(
3✔
398
        b"ssh.hassh\0".as_ptr() as *const libc::c_char,
3✔
399
        b"Ssh Client Fingerprinting For Ssh Clients\0".as_ptr() as *const libc::c_char,
3✔
400
        ALPROTO_SSH,
3✔
401
        STREAM_TOSERVER,
3✔
402
        Some(SCSshTxGetHassh),
3✔
403
        SSHConnectionState::SshStateBannerDone as c_int,
3✔
404
    );
3✔
405
    SCDetectHelperKeywordAliasRegister(
3✔
406
        DETECT_SSH_HASSH,
3✔
407
        b"ssh-hassh\0".as_ptr() as *const libc::c_char,
3✔
408
    );
3✔
409
    SCDetectRegisterBufferLowerMd5Callbacks(b"ssh.hassh\0".as_ptr() as *const libc::c_char);
3✔
410

3✔
411
    let kw = SigTableElmtStickyBuffer {
3✔
412
        name: String::from("ssh.hassh.server"),
3✔
413
        desc: String::from("ssh.hassh.server sticky buffer"),
3✔
414
        url: String::from("/rules/ssh-keywords.html#ssh.hassh.server"),
3✔
415
        setup: ssh_hassh_server_setup,
3✔
416
    };
3✔
417
    DETECT_SSH_HASSH_SERVER = helper_keyword_register_sticky_buffer(&kw);
3✔
418
    G_SSH_HASSH_SRV_BUFFER_ID = SCDetectHelperBufferProgressMpmRegister(
3✔
419
        b"ssh.hassh.server\0".as_ptr() as *const libc::c_char,
3✔
420
        b"Ssh Client Fingerprinting For Ssh Servers\0".as_ptr() as *const libc::c_char,
3✔
421
        ALPROTO_SSH,
3✔
422
        STREAM_TOCLIENT,
3✔
423
        Some(SCSshTxGetHassh),
3✔
424
        SSHConnectionState::SshStateBannerDone as c_int,
3✔
425
    );
3✔
426
    SCDetectHelperKeywordAliasRegister(
3✔
427
        DETECT_SSH_HASSH_SERVER,
3✔
428
        b"ssh-hassh-server\0".as_ptr() as *const libc::c_char,
3✔
429
    );
3✔
430
    SCDetectRegisterBufferLowerMd5Callbacks(b"ssh.hassh.server\0".as_ptr() as *const libc::c_char);
3✔
431
}
3✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc