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

OISF / suricata / 23350122333

20 Mar 2026 03:33PM UTC coverage: 76.492% (-2.8%) from 79.315%
23350122333

Pull #15053

github

web-flow
Merge f5bf69f97 into 6587e363a
Pull Request #15053: Flow queue/v3

113 of 129 new or added lines in 9 files covered. (87.6%)

9534 existing lines in 453 files now uncovered.

256601 of 335461 relevant lines covered (76.49%)

4680806.66 hits per line

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

88.15
/rust/src/rfb/parser.rs
1
/* Copyright (C) 2020-2022 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
// Author: Frank Honza <frank.honza@dcso.de>
19

20
use nom8::bytes::streaming::tag;
21
use nom8::bytes::streaming::take;
22
use nom8::combinator::map_res;
23
use nom8::number::streaming::*;
24
use nom8::{IResult, Parser};
25
use std::fmt;
26
use std::str;
27

28
#[derive(Debug, PartialEq)]
29
pub enum RFBGlobalState {
30
    TCServerProtocolVersion,
31
    TCSupportedSecurityTypes,
32
    TCVncChallenge,
33
    TCServerInit,
34
    TCFailureReason,
35
    TSClientProtocolVersion,
36
    TCServerSecurityType,
37
    TSSecurityTypeSelection,
38
    TSVncResponse,
39
    TCSecurityResult,
40
    TSClientInit,
41
    Skip,
42
}
43

44
impl fmt::Display for RFBGlobalState {
45
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
×
46
        match *self {
×
47
            RFBGlobalState::TCServerProtocolVersion => write!(f, "TCServerProtocolVersion"),
×
48
            RFBGlobalState::TCSupportedSecurityTypes => write!(f, "TCSupportedSecurityTypes"),
×
49
            RFBGlobalState::TCVncChallenge => write!(f, "TCVncChallenge"),
×
50
            RFBGlobalState::TCServerInit => write!(f, "TCServerInit"),
×
51
            RFBGlobalState::TCFailureReason => write!(f, "TCFailureReason"),
×
52
            RFBGlobalState::TSClientProtocolVersion => write!(f, "TSClientProtocolVersion"),
×
53
            RFBGlobalState::TSSecurityTypeSelection => write!(f, "TSSecurityTypeSelection"),
×
54
            RFBGlobalState::TSVncResponse => write!(f, "TSVncResponse"),
×
55
            RFBGlobalState::TCSecurityResult => write!(f, "TCSecurityResult"),
×
56
            RFBGlobalState::TCServerSecurityType => write!(f, "TCServerSecurityType"),
×
57
            RFBGlobalState::TSClientInit => write!(f, "TSClientInit"),
×
58
            RFBGlobalState::Skip => write!(f, "Skip"),
×
59
        }
60
    }
×
61
}
62

63
pub struct ProtocolVersion {
64
    pub major: String,
65
    pub minor: String,
66
}
67

68
pub struct SupportedSecurityTypes {
69
    pub number_of_types: u8,
70
    pub types: Vec<u8>,
71
}
72

73
pub struct SecurityTypeSelection {
74
    pub security_type: u8,
75
}
76

77
pub struct ServerSecurityType {
78
    pub security_type: u32,
79
}
80

81
#[derive(Clone, Debug, Default, EnumStringU32)]
82
#[repr(u32)]
83
pub enum RFBSecurityResultStatus {
84
    #[default]
85
    Ok = 0,
86
    Fail = 1,
87
    TooMany = 2,
88
    Unknown = 3,
89
}
90

91
pub struct SecurityResult {
92
    pub status: u32,
93
}
94

95
pub struct FailureReason {
96
    pub reason_string: String,
97
}
98

99
pub struct VncAuth {
100
    pub secret: Vec<u8>,
101
}
102

103
pub struct ClientInit {
104
    pub shared: u8,
105
}
106

107
pub struct PixelFormat {
108
    pub bits_per_pixel: u8,
109
    pub depth: u8,
110
    pub big_endian_flag: u8,
111
    pub true_colour_flag: u8,
112
    pub red_max: u16,
113
    pub green_max: u16,
114
    pub blue_max: u16,
115
    pub red_shift: u8,
116
    pub green_shift: u8,
117
    pub blue_shift: u8,
118
}
119

120
pub struct ServerInit {
121
    pub width: u16,
122
    pub height: u16,
123
    pub pixel_format: PixelFormat,
124
    pub name_length: u32,
125
    pub name: Vec<u8>,
126
}
127

128
pub fn parse_protocol_version(i: &[u8]) -> IResult<&[u8], ProtocolVersion> {
32✔
129
    let (i, _) = tag("RFB ")(i)?;
32✔
130
    let (i, major) = map_res(take(3_usize), str::from_utf8).parse(i)?;
31✔
131
    let (i, _) = tag(".")(i)?;
31✔
132
    let (i, minor) = map_res(take(3_usize), str::from_utf8).parse(i)?;
31✔
133
    let (i, _) = tag("\n")(i)?;
31✔
134
    Ok((
31✔
135
        i,
31✔
136
        ProtocolVersion {
31✔
137
            major: major.to_string(),
31✔
138
            minor: minor.to_string(),
31✔
139
        },
31✔
140
    ))
31✔
141
}
32✔
142

143
pub fn parse_supported_security_types(i: &[u8]) -> IResult<&[u8], SupportedSecurityTypes> {
14✔
144
    let (i, number_of_types) = be_u8(i)?;
14✔
145
    let (i, types) = take(number_of_types as usize)(i)?;
14✔
146
    Ok((
14✔
147
        i,
14✔
148
        SupportedSecurityTypes {
14✔
149
            number_of_types,
14✔
150
            types: types.to_vec(),
14✔
151
        },
14✔
152
    ))
14✔
153
}
14✔
154

155
pub fn parse_server_security_type(i: &[u8]) -> IResult<&[u8], ServerSecurityType> {
2✔
156
    let (i, security_type) = be_u32(i)?;
2✔
157
    Ok((i, ServerSecurityType { security_type }))
2✔
158
}
2✔
159

160
pub fn parse_vnc_auth(i: &[u8]) -> IResult<&[u8], VncAuth> {
23✔
161
    let (i, secret) = take(16_usize)(i)?;
23✔
162
    Ok((
23✔
163
        i,
23✔
164
        VncAuth {
23✔
165
            secret: secret.to_vec(),
23✔
166
        },
23✔
167
    ))
23✔
168
}
23✔
169

170
pub fn parse_security_type_selection(i: &[u8]) -> IResult<&[u8], SecurityTypeSelection> {
13✔
171
    let (i, security_type) = be_u8(i)?;
13✔
172
    Ok((i, SecurityTypeSelection { security_type }))
13✔
173
}
13✔
174

175
pub fn parse_security_result(i: &[u8]) -> IResult<&[u8], SecurityResult> {
11✔
176
    let (i, status) = be_u32(i)?;
11✔
177
    Ok((i, SecurityResult { status }))
11✔
178
}
11✔
179

UNCOV
180
pub fn parse_failure_reason(i: &[u8]) -> IResult<&[u8], FailureReason> {
×
UNCOV
181
    let (i, reason_length) = be_u32(i)?;
×
UNCOV
182
    let (i, reason_string) = map_res(take(reason_length as usize), str::from_utf8).parse(i)?;
×
183
    Ok((
×
184
        i,
×
185
        FailureReason {
×
186
            reason_string: reason_string.to_string(),
×
187
        },
×
188
    ))
×
UNCOV
189
}
×
190

191
pub fn parse_client_init(i: &[u8]) -> IResult<&[u8], ClientInit> {
14✔
192
    let (i, shared) = be_u8(i)?;
14✔
193
    Ok((i, ClientInit { shared }))
14✔
194
}
14✔
195

196
pub fn parse_pixel_format(i: &[u8]) -> IResult<&[u8], PixelFormat> {
15✔
197
    let (i, bits_per_pixel) = be_u8(i)?;
15✔
198
    let (i, depth) = be_u8(i)?;
15✔
199
    let (i, big_endian_flag) = be_u8(i)?;
15✔
200
    let (i, true_colour_flag) = be_u8(i)?;
15✔
201
    let (i, red_max) = be_u16(i)?;
15✔
202
    let (i, green_max) = be_u16(i)?;
15✔
203
    let (i, blue_max) = be_u16(i)?;
15✔
204
    let (i, red_shift) = be_u8(i)?;
15✔
205
    let (i, green_shift) = be_u8(i)?;
15✔
206
    let (i, blue_shift) = be_u8(i)?;
15✔
207
    let (i, _) = take(3_usize)(i)?;
15✔
208
    let format = PixelFormat {
15✔
209
        bits_per_pixel,
15✔
210
        depth,
15✔
211
        big_endian_flag,
15✔
212
        true_colour_flag,
15✔
213
        red_max,
15✔
214
        green_max,
15✔
215
        blue_max,
15✔
216
        red_shift,
15✔
217
        green_shift,
15✔
218
        blue_shift,
15✔
219
    };
15✔
220
    Ok((i, format))
15✔
221
}
15✔
222

223
pub fn parse_server_init(i: &[u8]) -> IResult<&[u8], ServerInit> {
14✔
224
    let (i, width) = be_u16(i)?;
14✔
225
    let (i, height) = be_u16(i)?;
14✔
226
    let (i, pixel_format) = parse_pixel_format(i)?;
14✔
227
    let (i, name_length) = be_u32(i)?;
14✔
228
    let (i, name) = take(name_length as usize)(i)?;
14✔
229
    let init = ServerInit {
14✔
230
        width,
14✔
231
        height,
14✔
232
        pixel_format,
14✔
233
        name_length,
14✔
234
        name: name.to_vec(),
14✔
235
    };
14✔
236
    Ok((i, init))
14✔
237
}
14✔
238

239
#[cfg(test)]
240
mod tests {
241
    use super::*;
242
    use nom8::Err;
243

244
    /// Simple test of some valid data.
245
    #[test]
246
    fn test_parse_version() {
1✔
247
        let buf = b"RFB 003.008\n";
1✔
248

1✔
249
        let result = parse_protocol_version(buf);
1✔
250
        match result {
251
            Ok((remainder, message)) => {
1✔
252
                // Check the first message.
1✔
253
                assert_eq!(message.major, "003");
1✔
254

255
                // And we should have 0 bytes left.
256
                assert_eq!(remainder.len(), 0);
1✔
257
            }
258
            Err(Err::Incomplete(_)) => {
259
                panic!("Result should not have been incomplete.");
260
            }
261
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
262
                panic!("Result should not be an error: {:?}.", err);
263
            }
264
        }
265
    }
1✔
266

267
    #[test]
268
    fn test_parse_server_init() {
1✔
269
        let buf = [
1✔
270
            0x05, 0x00, 0x03, 0x20, 0x20, 0x18, 0x00, 0x01, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
1✔
271
            0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x61, 0x6e, 0x65, 0x61,
1✔
272
            0x67, 0x6c, 0x65, 0x73, 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74,
1✔
273
            0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
1✔
274
        ];
1✔
275

1✔
276
        let result = parse_server_init(&buf);
1✔
277
        match result {
278
            Ok((remainder, message)) => {
1✔
279
                // Check the first message.
1✔
280
                assert_eq!(message.width, 1280);
1✔
281
                assert_eq!(message.height, 800);
1✔
282
                assert_eq!(message.pixel_format.bits_per_pixel, 32);
1✔
283

284
                // And we should have 0 bytes left.
285
                assert_eq!(remainder.len(), 0);
1✔
286
            }
287
            Err(Err::Incomplete(_)) => {
288
                panic!("Result should not have been incomplete.");
289
            }
290
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
291
                panic!("Result should not be an error: {:?}.", err);
292
            }
293
        }
294
    }
1✔
295

296
    #[test]
297
    fn test_parse_pixel_format() {
1✔
298
        let buf = [
1✔
299
            0x20, /* Bits per pixel: 32 */
1✔
300
            0x18, /* Depth: 24 */
1✔
301
            0x00, /* Big endian flag: False */
1✔
302
            0x01, /* True color flag: True */
1✔
303
            0x00, 0xff, /* Red maximum: 255 */
1✔
304
            0x00, 0xff, /* Green maximum: 255 */
1✔
305
            0x00, 0xff, /* Blue maximum: 255 */
1✔
306
            0x10, /* Red shift: 16 */
1✔
307
            0x08, /* Green shift: 8 */
1✔
308
            0x00, /* Blue shift: 0 */
1✔
309
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xa0,
1✔
310
        ];
1✔
311

1✔
312
        let result = parse_pixel_format(&buf);
1✔
313
        match result {
314
            Ok((remainder, message)) => {
1✔
315
                assert_eq!(message.bits_per_pixel, 32);
1✔
316
                assert_eq!(message.depth, 24);
1✔
317
                assert_eq!(message.big_endian_flag, 0);
1✔
318
                assert_eq!(message.true_colour_flag, 1);
1✔
319
                assert_eq!(message.red_max, 255);
1✔
320
                assert_eq!(message.green_max, 255);
1✔
321
                assert_eq!(message.blue_max, 255);
1✔
322
                assert_eq!(message.red_shift, 16);
1✔
323
                assert_eq!(message.green_shift, 8);
1✔
324
                assert_eq!(message.blue_shift, 0);
1✔
325
                assert_eq!(remainder.len(), 5);
1✔
326
            }
327
            Err(Err::Incomplete(_)) => {
328
                panic!("Result should not have been incomplete.");
329
            }
330
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
331
                panic!("Result should not be an error: {:?}.", err);
332
            }
333
        }
334
    }
1✔
335

336
    #[test]
337
    fn test_parse_supported_security_types() {
1✔
338
        let buf = [
1✔
339
            0x01, /* Number of security types: 1 */
1✔
340
            0x02, /* Security type: VNC (2) */
1✔
341
            0x00, 0x01, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00,
1✔
342
            0x00, 0x00, 0x00, 0x01, 0xa0,
1✔
343
        ];
1✔
344

1✔
345
        let result = parse_supported_security_types(&buf);
1✔
346
        match result {
347
            Ok((remainder, message)) => {
1✔
348
                assert_eq!(message.number_of_types, 1);
1✔
349
                assert_eq!(message.types[0], 2);
1✔
350
                assert_eq!(remainder.len(), 19);
1✔
351
            }
352
            Err(Err::Incomplete(_)) => {
353
                panic!("Result should not have been incomplete.");
354
            }
355
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
356
                panic!("Result should not be an error: {:?}.", err);
357
            }
358
        }
359
    }
1✔
360

361
    #[test]
362
    fn test_parse_vnc_auth() {
1✔
363
        let buf = [
1✔
364
            0x54, 0x7b, 0x7a, 0x6f, 0x36, 0xa1, 0x54, 0xdb, 0x03, 0xa2, 0x57, 0x5c, 0x6f, 0x2a,
1✔
365
            0x4e, 0xc5, /* Authentication challenge: 547b7a6f36a154db03a2575c6f2a4ec5 */
1✔
366
            0x00, 0x00, 0x00, 0x01, 0xa0,
1✔
367
        ];
1✔
368

1✔
369
        let result = parse_vnc_auth(&buf);
1✔
370
        match result {
371
            Ok((remainder, message)) => {
1✔
372
                assert_eq!(
1✔
373
                    hex::encode(message.secret),
1✔
374
                    "547b7a6f36a154db03a2575c6f2a4ec5"
1✔
375
                );
1✔
376
                assert_eq!(remainder.len(), 5);
1✔
377
            }
378
            Err(Err::Incomplete(_)) => {
379
                panic!("Result should not have been incomplete.");
380
            }
381
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
382
                panic!("Result should not be an error: {:?}.", err);
383
            }
384
        }
385
    }
1✔
386

387
    #[test]
388
    fn test_parse_client_init() {
1✔
389
        let buf = [
1✔
390
            0x00, /*Share desktop flag: False*/
1✔
391
            0x7b, 0x7a, 0x6f, 0x36, 0xa1, 0x54, 0xdb, 0x03, 0xa2, 0x57, 0x5c, 0x6f, 0x2a, 0x4e,
1✔
392
            0xc5, 0x00, 0x00, 0x00, 0x01, 0xa0,
1✔
393
        ];
1✔
394

1✔
395
        let result = parse_client_init(&buf);
1✔
396
        match result {
397
            Ok((remainder, message)) => {
1✔
398
                assert_eq!(message.shared, 0);
1✔
399
                assert_eq!(remainder.len(), 20);
1✔
400
            }
401
            Err(Err::Incomplete(_)) => {
402
                panic!("Result should not have been incomplete.");
403
            }
404
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
405
                panic!("Result should not be an error: {:?}.", err);
406
            }
407
        }
408
    }
1✔
409
}
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