/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 | | } |