Coverage Report

Created: 2026-06-30 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/rust/src/rfb/parser.rs
Line
Count
Source
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 nom7::bytes::streaming::tag;
21
use nom7::bytes::streaming::take;
22
use nom7::combinator::map_res;
23
use nom7::number::streaming::*;
24
use nom7::*;
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
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
46
0
        match *self {
47
0
            RFBGlobalState::TCServerProtocolVersion => write!(f, "TCServerProtocolVersion"),
48
0
            RFBGlobalState::TCSupportedSecurityTypes => write!(f, "TCSupportedSecurityTypes"),
49
0
            RFBGlobalState::TCVncChallenge => write!(f, "TCVncChallenge"),
50
0
            RFBGlobalState::TCServerInit => write!(f, "TCServerInit"),
51
0
            RFBGlobalState::TCFailureReason => write!(f, "TCFailureReason"),
52
0
            RFBGlobalState::TSClientProtocolVersion => write!(f, "TSClientProtocolVersion"),
53
0
            RFBGlobalState::TSSecurityTypeSelection => write!(f, "TSSecurityTypeSelection"),
54
0
            RFBGlobalState::TSVncResponse => write!(f, "TSVncResponse"),
55
0
            RFBGlobalState::TCSecurityResult => write!(f, "TCSecurityResult"),
56
0
            RFBGlobalState::TCServerSecurityType => write!(f, "TCServerSecurityType"),
57
0
            RFBGlobalState::TSClientInit => write!(f, "TSClientInit"),
58
0
            RFBGlobalState::Skip => write!(f, "Skip"),
59
        }
60
0
    }
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
pub struct SecurityResult {
82
    pub status: u32,
83
}
84
85
pub struct FailureReason {
86
    pub reason_string: String,
87
}
88
89
pub struct VncAuth {
90
    pub secret: Vec<u8>,
91
}
92
93
pub struct ClientInit {
94
    pub shared: u8,
95
}
96
97
pub struct PixelFormat {
98
    pub bits_per_pixel: u8,
99
    pub depth: u8,
100
    pub big_endian_flag: u8,
101
    pub true_colour_flag: u8,
102
    pub red_max: u16,
103
    pub green_max: u16,
104
    pub blue_max: u16,
105
    pub red_shift: u8,
106
    pub green_shift: u8,
107
    pub blue_shift: u8,
108
}
109
110
pub struct ServerInit {
111
    pub width: u16,
112
    pub height: u16,
113
    pub pixel_format: PixelFormat,
114
    pub name_length: u32,
115
    pub name: Vec<u8>,
116
}
117
118
5.34k
pub fn parse_protocol_version(i: &[u8]) -> IResult<&[u8], ProtocolVersion> {
119
5.34k
    let (i, _) = tag("RFB ")(i)?;
120
3.88k
    let (i, major) = map_res(take(3_usize), str::from_utf8)(i)?;
121
3.62k
    let (i, _) = tag(".")(i)?;
122
3.21k
    let (i, minor) = map_res(take(3_usize), str::from_utf8)(i)?;
123
2.84k
    let (i, _) = tag("\n")(i)?;
124
2.55k
    Ok((
125
2.55k
        i,
126
2.55k
        ProtocolVersion {
127
2.55k
            major: major.to_string(),
128
2.55k
            minor: minor.to_string(),
129
2.55k
        },
130
2.55k
    ))
131
5.34k
}
132
133
2.97k
pub fn parse_supported_security_types(i: &[u8]) -> IResult<&[u8], SupportedSecurityTypes> {
134
2.97k
    let (i, number_of_types) = be_u8(i)?;
135
2.97k
    let (i, types) = take(number_of_types as usize)(i)?;
136
825
    Ok((
137
825
        i,
138
825
        SupportedSecurityTypes {
139
825
            number_of_types,
140
825
            types: types.to_vec(),
141
825
        },
142
825
    ))
143
2.97k
}
144
145
517
pub fn parse_server_security_type(i: &[u8]) -> IResult<&[u8], ServerSecurityType> {
146
517
    let (i, security_type) = be_u32(i)?;
147
190
    Ok((i, ServerSecurityType { security_type }))
148
517
}
149
150
594
pub fn parse_vnc_auth(i: &[u8]) -> IResult<&[u8], VncAuth> {
151
594
    let (i, secret) = take(16_usize)(i)?;
152
188
    Ok((
153
188
        i,
154
188
        VncAuth {
155
188
            secret: secret.to_vec(),
156
188
        },
157
188
    ))
158
594
}
159
160
535
pub fn parse_security_type_selection(i: &[u8]) -> IResult<&[u8], SecurityTypeSelection> {
161
535
    let (i, security_type) = be_u8(i)?;
162
535
    Ok((i, SecurityTypeSelection { security_type }))
163
535
}
164
165
240
pub fn parse_security_result(i: &[u8]) -> IResult<&[u8], SecurityResult> {
166
240
    let (i, status) = be_u32(i)?;
167
42
    Ok((i, SecurityResult { status }))
168
240
}
169
170
8.55k
pub fn parse_failure_reason(i: &[u8]) -> IResult<&[u8], FailureReason> {
171
8.55k
    let (i, reason_length) = be_u32(i)?;
172
7.84k
    let (i, reason_string) = map_res(take(reason_length as usize), str::from_utf8)(i)?;
173
5.33k
    Ok((
174
5.33k
        i,
175
5.33k
        FailureReason {
176
5.33k
            reason_string: reason_string.to_string(),
177
5.33k
        },
178
5.33k
    ))
179
8.55k
}
180
181
515
pub fn parse_client_init(i: &[u8]) -> IResult<&[u8], ClientInit> {
182
515
    let (i, shared) = be_u8(i)?;
183
515
    Ok((i, ClientInit { shared }))
184
515
}
185
186
10.6k
pub fn parse_pixel_format(i: &[u8]) -> IResult<&[u8], PixelFormat> {
187
10.6k
    let (i, bits_per_pixel) = be_u8(i)?;
188
10.2k
    let (i, depth) = be_u8(i)?;
189
10.0k
    let (i, big_endian_flag) = be_u8(i)?;
190
9.82k
    let (i, true_colour_flag) = be_u8(i)?;
191
9.43k
    let (i, red_max) = be_u16(i)?;
192
8.68k
    let (i, green_max) = be_u16(i)?;
193
8.46k
    let (i, blue_max) = be_u16(i)?;
194
8.21k
    let (i, red_shift) = be_u8(i)?;
195
8.00k
    let (i, green_shift) = be_u8(i)?;
196
7.79k
    let (i, blue_shift) = be_u8(i)?;
197
7.27k
    let (i, _) = take(3_usize)(i)?;
198
3.41k
    let format = PixelFormat {
199
3.41k
        bits_per_pixel,
200
3.41k
        depth,
201
3.41k
        big_endian_flag,
202
3.41k
        true_colour_flag,
203
3.41k
        red_max,
204
3.41k
        green_max,
205
3.41k
        blue_max,
206
3.41k
        red_shift,
207
3.41k
        green_shift,
208
3.41k
        blue_shift,
209
3.41k
    };
210
3.41k
    Ok((i, format))
211
10.6k
}
212
213
11.4k
pub fn parse_server_init(i: &[u8]) -> IResult<&[u8], ServerInit> {
214
11.4k
    let (i, width) = be_u16(i)?;
215
11.2k
    let (i, height) = be_u16(i)?;
216
10.6k
    let (i, pixel_format) = parse_pixel_format(i)?;
217
3.41k
    let (i, name_length) = be_u32(i)?;
218
1.98k
    let (i, name) = take(name_length as usize)(i)?;
219
214
    let init = ServerInit {
220
214
        width,
221
214
        height,
222
214
        pixel_format,
223
214
        name_length,
224
214
        name: name.to_vec(),
225
214
    };
226
214
    Ok((i, init))
227
11.4k
}
228
229
#[cfg(test)]
230
mod tests {
231
    use super::*;
232
233
    /// Simple test of some valid data.
234
    #[test]
235
    fn test_parse_version() {
236
        let buf = b"RFB 003.008\n";
237
238
        let result = parse_protocol_version(buf);
239
        match result {
240
            Ok((remainder, message)) => {
241
                // Check the first message.
242
                assert_eq!(message.major, "003");
243
244
                // And we should have 0 bytes left.
245
                assert_eq!(remainder.len(), 0);
246
            }
247
            Err(Err::Incomplete(_)) => {
248
                panic!("Result should not have been incomplete.");
249
            }
250
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
251
                panic!("Result should not be an error: {:?}.", err);
252
            }
253
        }
254
    }
255
256
    #[test]
257
    fn test_parse_server_init() {
258
        let buf = [
259
            0x05, 0x00, 0x03, 0x20, 0x20, 0x18, 0x00, 0x01, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
260
            0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x61, 0x6e, 0x65, 0x61,
261
            0x67, 0x6c, 0x65, 0x73, 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74,
262
            0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
263
        ];
264
265
        let result = parse_server_init(&buf);
266
        match result {
267
            Ok((remainder, message)) => {
268
                // Check the first message.
269
                assert_eq!(message.width, 1280);
270
                assert_eq!(message.height, 800);
271
                assert_eq!(message.pixel_format.bits_per_pixel, 32);
272
273
                // And we should have 0 bytes left.
274
                assert_eq!(remainder.len(), 0);
275
            }
276
            Err(Err::Incomplete(_)) => {
277
                panic!("Result should not have been incomplete.");
278
            }
279
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
280
                panic!("Result should not be an error: {:?}.", err);
281
            }
282
        }
283
    }
284
285
    #[test]
286
    fn test_parse_pixel_format() {
287
        let buf = [
288
            0x20, /* Bits per pixel: 32 */
289
            0x18, /* Depth: 24 */
290
            0x00, /* Big endian flag: False */
291
            0x01, /* True color flag: True */
292
            0x00, 0xff, /* Red maximum: 255 */
293
            0x00, 0xff, /* Green maximum: 255 */
294
            0x00, 0xff, /* Blue maximum: 255 */
295
            0x10, /* Red shift: 16 */
296
            0x08, /* Green shift: 8 */
297
            0x00, /* Blue shift: 0 */
298
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xa0,
299
        ];
300
301
        let result = parse_pixel_format(&buf);
302
        match result {
303
            Ok((remainder, message)) => {
304
                assert_eq!(message.bits_per_pixel, 32);
305
                assert_eq!(message.depth, 24);
306
                assert_eq!(message.big_endian_flag, 0);
307
                assert_eq!(message.true_colour_flag, 1);
308
                assert_eq!(message.red_max, 255);
309
                assert_eq!(message.green_max, 255);
310
                assert_eq!(message.blue_max, 255);
311
                assert_eq!(message.red_shift, 16);
312
                assert_eq!(message.green_shift, 8);
313
                assert_eq!(message.blue_shift, 0);
314
                assert_eq!(remainder.len(), 5);
315
            }
316
            Err(Err::Incomplete(_)) => {
317
                panic!("Result should not have been incomplete.");
318
            }
319
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
320
                panic!("Result should not be an error: {:?}.", err);
321
            }
322
        }
323
    }
324
325
    #[test]
326
    fn test_parse_supported_security_types() {
327
        let buf = [
328
            0x01, /* Number of security types: 1 */
329
            0x02, /* Security type: VNC (2) */
330
            0x00, 0x01, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00,
331
            0x00, 0x00, 0x00, 0x01, 0xa0,
332
        ];
333
334
        let result = parse_supported_security_types(&buf);
335
        match result {
336
            Ok((remainder, message)) => {
337
                assert_eq!(message.number_of_types, 1);
338
                assert_eq!(message.types[0], 2);
339
                assert_eq!(remainder.len(), 19);
340
            }
341
            Err(Err::Incomplete(_)) => {
342
                panic!("Result should not have been incomplete.");
343
            }
344
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
345
                panic!("Result should not be an error: {:?}.", err);
346
            }
347
        }
348
    }
349
350
    #[test]
351
    fn test_parse_vnc_auth() {
352
        let buf = [
353
            0x54, 0x7b, 0x7a, 0x6f, 0x36, 0xa1, 0x54, 0xdb, 0x03, 0xa2, 0x57, 0x5c, 0x6f, 0x2a,
354
            0x4e, 0xc5, /* Authentication challenge: 547b7a6f36a154db03a2575c6f2a4ec5 */
355
            0x00, 0x00, 0x00, 0x01, 0xa0,
356
        ];
357
358
        let result = parse_vnc_auth(&buf);
359
        match result {
360
            Ok((remainder, message)) => {
361
                assert_eq!(
362
                    hex::encode(message.secret),
363
                    "547b7a6f36a154db03a2575c6f2a4ec5"
364
                );
365
                assert_eq!(remainder.len(), 5);
366
            }
367
            Err(Err::Incomplete(_)) => {
368
                panic!("Result should not have been incomplete.");
369
            }
370
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
371
                panic!("Result should not be an error: {:?}.", err);
372
            }
373
        }
374
    }
375
376
    #[test]
377
    fn test_parse_client_init() {
378
        let buf = [
379
            0x00, /*Share desktop flag: False*/
380
            0x7b, 0x7a, 0x6f, 0x36, 0xa1, 0x54, 0xdb, 0x03, 0xa2, 0x57, 0x5c, 0x6f, 0x2a, 0x4e,
381
            0xc5, 0x00, 0x00, 0x00, 0x01, 0xa0,
382
        ];
383
384
        let result = parse_client_init(&buf);
385
        match result {
386
            Ok((remainder, message)) => {
387
                assert_eq!(message.shared, 0);
388
                assert_eq!(remainder.len(), 20);
389
            }
390
            Err(Err::Incomplete(_)) => {
391
                panic!("Result should not have been incomplete.");
392
            }
393
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
394
                panic!("Result should not be an error: {:?}.", err);
395
            }
396
        }
397
    }
398
}