Coverage Report

Created: 2025-12-31 06:43

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
4.83k
pub fn parse_protocol_version(i: &[u8]) -> IResult<&[u8], ProtocolVersion> {
119
4.83k
    let (i, _) = tag("RFB ")(i)?;
120
3.40k
    let (i, major) = map_res(take(3_usize), str::from_utf8)(i)?;
121
3.16k
    let (i, _) = tag(".")(i)?;
122
2.77k
    let (i, minor) = map_res(take(3_usize), str::from_utf8)(i)?;
123
2.43k
    let (i, _) = tag("\n")(i)?;
124
2.14k
    Ok((
125
2.14k
        i,
126
2.14k
        ProtocolVersion {
127
2.14k
            major: major.to_string(),
128
2.14k
            minor: minor.to_string(),
129
2.14k
        },
130
2.14k
    ))
131
4.83k
}
132
133
1.17k
pub fn parse_supported_security_types(i: &[u8]) -> IResult<&[u8], SupportedSecurityTypes> {
134
1.17k
    let (i, number_of_types) = be_u8(i)?;
135
1.17k
    let (i, types) = take(number_of_types as usize)(i)?;
136
696
    Ok((
137
696
        i,
138
696
        SupportedSecurityTypes {
139
696
            number_of_types,
140
696
            types: types.to_vec(),
141
696
        },
142
696
    ))
143
1.17k
}
144
145
473
pub fn parse_server_security_type(i: &[u8]) -> IResult<&[u8], ServerSecurityType> {
146
473
    let (i, security_type) = be_u32(i)?;
147
151
    Ok((i, ServerSecurityType { security_type }))
148
473
}
149
150
525
pub fn parse_vnc_auth(i: &[u8]) -> IResult<&[u8], VncAuth> {
151
525
    let (i, secret) = take(16_usize)(i)?;
152
133
    Ok((
153
133
        i,
154
133
        VncAuth {
155
133
            secret: secret.to_vec(),
156
133
        },
157
133
    ))
158
525
}
159
160
471
pub fn parse_security_type_selection(i: &[u8]) -> IResult<&[u8], SecurityTypeSelection> {
161
471
    let (i, security_type) = be_u8(i)?;
162
471
    Ok((i, SecurityTypeSelection { security_type }))
163
471
}
164
165
222
pub fn parse_security_result(i: &[u8]) -> IResult<&[u8], SecurityResult> {
166
222
    let (i, status) = be_u32(i)?;
167
28
    Ok((i, SecurityResult { status }))
168
222
}
169
170
2.82k
pub fn parse_failure_reason(i: &[u8]) -> IResult<&[u8], FailureReason> {
171
2.82k
    let (i, reason_length) = be_u32(i)?;
172
2.61k
    let (i, reason_string) = map_res(take(reason_length as usize), str::from_utf8)(i)?;
173
2.12k
    Ok((
174
2.12k
        i,
175
2.12k
        FailureReason {
176
2.12k
            reason_string: reason_string.to_string(),
177
2.12k
        },
178
2.12k
    ))
179
2.82k
}
180
181
448
pub fn parse_client_init(i: &[u8]) -> IResult<&[u8], ClientInit> {
182
448
    let (i, shared) = be_u8(i)?;
183
448
    Ok((i, ClientInit { shared }))
184
448
}
185
186
6.11k
pub fn parse_pixel_format(i: &[u8]) -> IResult<&[u8], PixelFormat> {
187
6.11k
    let (i, bits_per_pixel) = be_u8(i)?;
188
5.78k
    let (i, depth) = be_u8(i)?;
189
5.57k
    let (i, big_endian_flag) = be_u8(i)?;
190
5.38k
    let (i, true_colour_flag) = be_u8(i)?;
191
5.18k
    let (i, red_max) = be_u16(i)?;
192
4.70k
    let (i, green_max) = be_u16(i)?;
193
3.01k
    let (i, blue_max) = be_u16(i)?;
194
2.79k
    let (i, red_shift) = be_u8(i)?;
195
2.30k
    let (i, green_shift) = be_u8(i)?;
196
2.10k
    let (i, blue_shift) = be_u8(i)?;
197
1.88k
    let (i, _) = take(3_usize)(i)?;
198
1.69k
    let format = PixelFormat {
199
1.69k
        bits_per_pixel,
200
1.69k
        depth,
201
1.69k
        big_endian_flag,
202
1.69k
        true_colour_flag,
203
1.69k
        red_max,
204
1.69k
        green_max,
205
1.69k
        blue_max,
206
1.69k
        red_shift,
207
1.69k
        green_shift,
208
1.69k
        blue_shift,
209
1.69k
    };
210
1.69k
    Ok((i, format))
211
6.11k
}
212
213
6.63k
pub fn parse_server_init(i: &[u8]) -> IResult<&[u8], ServerInit> {
214
6.63k
    let (i, width) = be_u16(i)?;
215
6.43k
    let (i, height) = be_u16(i)?;
216
6.11k
    let (i, pixel_format) = parse_pixel_format(i)?;
217
1.69k
    let (i, name_length) = be_u32(i)?;
218
693
    let (i, name) = take(name_length as usize)(i)?;
219
176
    let init = ServerInit {
220
176
        width,
221
176
        height,
222
176
        pixel_format,
223
176
        name_length,
224
176
        name: name.to_vec(),
225
176
    };
226
176
    Ok((i, init))
227
6.63k
}
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
}