/src/suricata7/rust/src/rfb/rfb.rs
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2020-2023 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 | | // Sascha Steinbiss <sascha.steinbiss@dcso.de> |
20 | | |
21 | | use super::parser; |
22 | | use crate::applayer; |
23 | | use crate::applayer::*; |
24 | | use crate::core::{AppProto, Flow, ALPROTO_UNKNOWN, IPPROTO_TCP}; |
25 | | use crate::frames::*; |
26 | | use nom7::Err; |
27 | | use std; |
28 | | use std::ffi::CString; |
29 | | |
30 | | static mut ALPROTO_RFB: AppProto = ALPROTO_UNKNOWN; |
31 | | |
32 | 96 | #[derive(FromPrimitive, Debug, AppLayerEvent)] Unexecuted instantiation: <suricata::rfb::rfb::RFBEvent as num_traits::cast::FromPrimitive>::from_i64 Unexecuted instantiation: <suricata::rfb::rfb::RFBEvent as num_traits::cast::FromPrimitive>::from_u64 <suricata::rfb::rfb::RFBEvent as suricata::applayer::AppLayerEvent>::from_id Line | Count | Source | 32 | 16 | #[derive(FromPrimitive, Debug, AppLayerEvent)] |
<suricata::rfb::rfb::RFBEvent as suricata::applayer::AppLayerEvent>::as_i32 Line | Count | Source | 32 | 30 | #[derive(FromPrimitive, Debug, AppLayerEvent)] |
<suricata::rfb::rfb::RFBEvent as suricata::applayer::AppLayerEvent>::to_cstring Line | Count | Source | 32 | 16 | #[derive(FromPrimitive, Debug, AppLayerEvent)] |
<suricata::rfb::rfb::RFBEvent as suricata::applayer::AppLayerEvent>::from_string Line | Count | Source | 32 | 34 | #[derive(FromPrimitive, Debug, AppLayerEvent)] |
<suricata::rfb::rfb::RFBEvent as suricata::applayer::AppLayerEvent>::get_event_info Line | Count | Source | 32 | 34 | #[derive(FromPrimitive, Debug, AppLayerEvent)] |
<suricata::rfb::rfb::RFBEvent as suricata::applayer::AppLayerEvent>::get_event_info_by_id Line | Count | Source | 32 | 16 | #[derive(FromPrimitive, Debug, AppLayerEvent)] |
|
33 | | pub enum RFBEvent { |
34 | | UnimplementedSecurityType, |
35 | | UnknownSecurityResult, |
36 | | MalformedMessage, |
37 | | ConfusedState, |
38 | | } |
39 | | |
40 | 9 | #[derive(AppLayerFrameType)] Unexecuted instantiation: <suricata::rfb::rfb::RFBFrameType as suricata::applayer::AppLayerFrameType>::from_u8 <suricata::rfb::rfb::RFBFrameType as suricata::applayer::AppLayerFrameType>::as_u8 Line | Count | Source | 40 | 6 | #[derive(AppLayerFrameType)] |
Unexecuted instantiation: <suricata::rfb::rfb::RFBFrameType as suricata::applayer::AppLayerFrameType>::to_cstring <suricata::rfb::rfb::RFBFrameType as suricata::applayer::AppLayerFrameType>::from_str Line | Count | Source | 40 | 9 | #[derive(AppLayerFrameType)] |
|
41 | | pub enum RFBFrameType { |
42 | | Pdu, |
43 | | } |
44 | | pub struct RFBTransaction { |
45 | | tx_id: u64, |
46 | | pub complete: bool, |
47 | | pub chosen_security_type: Option<u32>, |
48 | | |
49 | | pub tc_server_protocol_version: Option<parser::ProtocolVersion>, |
50 | | pub ts_client_protocol_version: Option<parser::ProtocolVersion>, |
51 | | pub tc_supported_security_types: Option<parser::SupportedSecurityTypes>, |
52 | | pub ts_security_type_selection: Option<parser::SecurityTypeSelection>, |
53 | | pub tc_server_security_type: Option<parser::ServerSecurityType>, |
54 | | pub tc_vnc_challenge: Option<parser::VncAuth>, |
55 | | pub ts_vnc_response: Option<parser::VncAuth>, |
56 | | pub ts_client_init: Option<parser::ClientInit>, |
57 | | pub tc_security_result: Option<parser::SecurityResult>, |
58 | | pub tc_failure_reason: Option<parser::FailureReason>, |
59 | | pub tc_server_init: Option<parser::ServerInit>, |
60 | | |
61 | | tx_data: applayer::AppLayerTxData, |
62 | | } |
63 | | |
64 | | impl Transaction for RFBTransaction { |
65 | 25.0k | fn id(&self) -> u64 { |
66 | 25.0k | self.tx_id |
67 | 25.0k | } |
68 | | } |
69 | | |
70 | | impl Default for RFBTransaction { |
71 | 0 | fn default() -> Self { |
72 | 0 | Self::new() |
73 | 0 | } |
74 | | } |
75 | | |
76 | | impl RFBTransaction { |
77 | 1.25k | pub fn new() -> Self { |
78 | 1.25k | Self { |
79 | 1.25k | tx_id: 0, |
80 | 1.25k | complete: false, |
81 | 1.25k | chosen_security_type: None, |
82 | 1.25k | |
83 | 1.25k | tc_server_protocol_version: None, |
84 | 1.25k | ts_client_protocol_version: None, |
85 | 1.25k | tc_supported_security_types: None, |
86 | 1.25k | ts_security_type_selection: None, |
87 | 1.25k | tc_server_security_type: None, |
88 | 1.25k | tc_vnc_challenge: None, |
89 | 1.25k | ts_vnc_response: None, |
90 | 1.25k | ts_client_init: None, |
91 | 1.25k | tc_security_result: None, |
92 | 1.25k | tc_failure_reason: None, |
93 | 1.25k | tc_server_init: None, |
94 | 1.25k | |
95 | 1.25k | tx_data: applayer::AppLayerTxData::new(), |
96 | 1.25k | } |
97 | 1.25k | } |
98 | | |
99 | 436 | fn set_event(&mut self, event: RFBEvent) { |
100 | 436 | self.tx_data.set_event(event as u8); |
101 | 436 | } |
102 | | } |
103 | | |
104 | | pub struct RFBState { |
105 | | state_data: AppLayerStateData, |
106 | | tx_id: u64, |
107 | | transactions: Vec<RFBTransaction>, |
108 | | state: parser::RFBGlobalState, |
109 | | } |
110 | | |
111 | | impl State<RFBTransaction> for RFBState { |
112 | 20.4k | fn get_transaction_count(&self) -> usize { |
113 | 20.4k | self.transactions.len() |
114 | 20.4k | } |
115 | | |
116 | 12.5k | fn get_transaction_by_index(&self, index: usize) -> Option<&RFBTransaction> { |
117 | 12.5k | self.transactions.get(index) |
118 | 12.5k | } |
119 | | } |
120 | | |
121 | | impl Default for RFBState { |
122 | 0 | fn default() -> Self { |
123 | 0 | Self::new() |
124 | 0 | } |
125 | | } |
126 | | |
127 | | impl RFBState { |
128 | 1.57k | pub fn new() -> Self { |
129 | 1.57k | Self { |
130 | 1.57k | state_data: AppLayerStateData::new(), |
131 | 1.57k | tx_id: 0, |
132 | 1.57k | transactions: Vec::new(), |
133 | 1.57k | state: parser::RFBGlobalState::TCServerProtocolVersion, |
134 | 1.57k | } |
135 | 1.57k | } |
136 | | |
137 | | // Free a transaction by ID. |
138 | 44 | fn free_tx(&mut self, tx_id: u64) { |
139 | 44 | let len = self.transactions.len(); |
140 | 44 | let mut found = false; |
141 | 44 | let mut index = 0; |
142 | 44 | for i in 0..len { |
143 | 44 | let tx = &self.transactions[i]; |
144 | 44 | if tx.tx_id == tx_id + 1 { |
145 | 44 | found = true; |
146 | 44 | index = i; |
147 | 44 | break; |
148 | 0 | } |
149 | | } |
150 | 44 | if found { |
151 | 44 | self.transactions.remove(index); |
152 | 44 | } |
153 | 44 | } |
154 | | |
155 | 18 | pub fn get_tx(&mut self, tx_id: u64) -> Option<&RFBTransaction> { |
156 | 18 | self.transactions.iter().find(|tx| tx.tx_id == tx_id + 1) |
157 | 18 | } |
158 | | |
159 | 1.25k | fn new_tx(&mut self) -> RFBTransaction { |
160 | 1.25k | let mut tx = RFBTransaction::new(); |
161 | 1.25k | self.tx_id += 1; |
162 | 1.25k | tx.tx_id = self.tx_id; |
163 | 1.25k | return tx; |
164 | 1.25k | } |
165 | | |
166 | 6.47k | fn get_current_tx(&mut self) -> Option<&mut RFBTransaction> { |
167 | 6.47k | let tx_id = self.tx_id; |
168 | 6.47k | let r = self.transactions.iter_mut().find(|tx| tx.tx_id == tx_id); |
169 | 6.47k | if let Some(tx) = r { |
170 | 6.31k | tx.tx_data.updated_tc = true; |
171 | 6.31k | tx.tx_data.updated_ts = true; |
172 | 6.31k | return Some(tx); |
173 | 159 | } |
174 | 159 | return None; |
175 | 6.47k | } |
176 | | |
177 | 4.65k | fn parse_request(&mut self, flow: *const Flow, stream_slice: StreamSlice) -> AppLayerResult { |
178 | 4.65k | let input = stream_slice.as_slice(); |
179 | 4.65k | |
180 | 4.65k | // We're not interested in empty requests. |
181 | 4.65k | if input.is_empty() { |
182 | 0 | return AppLayerResult::ok(); |
183 | 4.65k | } |
184 | 4.65k | |
185 | 4.65k | let mut current = input; |
186 | 4.65k | let mut consumed = 0; |
187 | | SCLogDebug!("request_state {}, input_len {}", self.state, input.len()); |
188 | | loop { |
189 | 6.63k | if current.is_empty() { |
190 | 1.45k | return AppLayerResult::ok(); |
191 | 5.18k | } |
192 | 5.18k | match self.state { |
193 | | parser::RFBGlobalState::TSClientProtocolVersion => { |
194 | 1.53k | match parser::parse_protocol_version(current) { |
195 | 1.00k | Ok((rem, request)) => { |
196 | 1.00k | consumed += current.len() - rem.len(); |
197 | 1.00k | let _pdu = Frame::new( |
198 | 1.00k | flow, |
199 | 1.00k | &stream_slice, |
200 | 1.00k | current, |
201 | 1.00k | consumed as i64, |
202 | 1.00k | RFBFrameType::Pdu as u8, |
203 | 1.00k | ); |
204 | 1.00k | |
205 | 1.00k | current = rem; |
206 | 1.00k | |
207 | 1.00k | if request.major == "003" && request.minor == "003" { |
208 | 184 | // in version 3.3 the server decided security type |
209 | 184 | self.state = parser::RFBGlobalState::TCServerSecurityType; |
210 | 823 | } else { |
211 | 823 | self.state = parser::RFBGlobalState::TCSupportedSecurityTypes; |
212 | 823 | } |
213 | | |
214 | 1.00k | if let Some(current_transaction) = self.get_current_tx() { |
215 | 1.00k | current_transaction.ts_client_protocol_version = Some(request); |
216 | 1.00k | } else { |
217 | 0 | debug_validate_fail!( |
218 | 0 | "no transaction set at protocol selection stage" |
219 | | ); |
220 | | } |
221 | | } |
222 | | Err(Err::Incomplete(_)) => { |
223 | 523 | return AppLayerResult::incomplete( |
224 | 523 | consumed as u32, |
225 | 523 | (current.len() + 1) as u32, |
226 | 523 | ); |
227 | | } |
228 | | Err(_) => { |
229 | | // We even failed to parse the protocol version. |
230 | 5 | return AppLayerResult::err(); |
231 | | } |
232 | | } |
233 | | } |
234 | | parser::RFBGlobalState::TSSecurityTypeSelection => { |
235 | 468 | match parser::parse_security_type_selection(current) { |
236 | 468 | Ok((rem, request)) => { |
237 | 468 | consumed += current.len() - rem.len(); |
238 | 468 | let _pdu = Frame::new( |
239 | 468 | flow, |
240 | 468 | &stream_slice, |
241 | 468 | current, |
242 | 468 | consumed as i64, |
243 | 468 | RFBFrameType::Pdu as u8, |
244 | 468 | ); |
245 | 468 | |
246 | 468 | current = rem; |
247 | 468 | |
248 | 468 | let chosen_security_type = request.security_type; |
249 | | |
250 | 468 | if let Some(current_transaction) = self.get_current_tx() { |
251 | 468 | current_transaction.ts_security_type_selection = Some(request); |
252 | 468 | current_transaction.chosen_security_type = |
253 | 468 | Some(chosen_security_type as u32); |
254 | 468 | } else { |
255 | 0 | debug_validate_fail!("no transaction set at security type stage"); |
256 | | } |
257 | | |
258 | 468 | match chosen_security_type { |
259 | 7 | 2 => self.state = parser::RFBGlobalState::TCVncChallenge, |
260 | 455 | 1 => self.state = parser::RFBGlobalState::TSClientInit, |
261 | | _ => { |
262 | 6 | if let Some(current_transaction) = self.get_current_tx() { |
263 | 6 | current_transaction |
264 | 6 | .set_event(RFBEvent::UnimplementedSecurityType); |
265 | 6 | } |
266 | | // We have just have seen a security type we don't know about. |
267 | | // This is not bad per se, it might just mean this is a |
268 | | // proprietary one not in the spec. |
269 | | // Continue the flow but stop trying to map the protocol. |
270 | 6 | self.state = parser::RFBGlobalState::Skip; |
271 | 6 | return AppLayerResult::ok(); |
272 | | } |
273 | | } |
274 | | } |
275 | | Err(Err::Incomplete(_)) => { |
276 | 0 | return AppLayerResult::incomplete( |
277 | 0 | consumed as u32, |
278 | 0 | (current.len() + 1) as u32, |
279 | 0 | ); |
280 | | } |
281 | | Err(_) => { |
282 | 0 | if let Some(current_transaction) = self.get_current_tx() { |
283 | 0 | current_transaction.set_event(RFBEvent::MalformedMessage); |
284 | 0 | current_transaction.complete = true; |
285 | 0 | } |
286 | | // We failed to parse the security type. |
287 | | // Continue the flow but stop trying to map the protocol. |
288 | 0 | self.state = parser::RFBGlobalState::Skip; |
289 | 0 | return AppLayerResult::ok(); |
290 | | } |
291 | | } |
292 | | } |
293 | 295 | parser::RFBGlobalState::TSVncResponse => match parser::parse_vnc_auth(current) { |
294 | 58 | Ok((rem, request)) => { |
295 | 58 | consumed += current.len() - rem.len(); |
296 | 58 | let _pdu = Frame::new( |
297 | 58 | flow, |
298 | 58 | &stream_slice, |
299 | 58 | current, |
300 | 58 | consumed as i64, |
301 | 58 | RFBFrameType::Pdu as u8, |
302 | 58 | ); |
303 | 58 | |
304 | 58 | current = rem; |
305 | 58 | |
306 | 58 | self.state = parser::RFBGlobalState::TCSecurityResult; |
307 | | |
308 | 58 | if let Some(current_transaction) = self.get_current_tx() { |
309 | 58 | current_transaction.ts_vnc_response = Some(request); |
310 | 58 | } else { |
311 | 0 | debug_validate_fail!("no transaction set at security result stage"); |
312 | | } |
313 | | } |
314 | | Err(Err::Incomplete(_)) => { |
315 | 237 | return AppLayerResult::incomplete( |
316 | 237 | consumed as u32, |
317 | 237 | (current.len() + 1) as u32, |
318 | 237 | ); |
319 | | } |
320 | | Err(_) => { |
321 | 0 | if let Some(current_transaction) = self.get_current_tx() { |
322 | 0 | current_transaction.set_event(RFBEvent::MalformedMessage); |
323 | 0 | current_transaction.complete = true; |
324 | 0 | } |
325 | | // Continue the flow but stop trying to map the protocol. |
326 | 0 | self.state = parser::RFBGlobalState::Skip; |
327 | 0 | return AppLayerResult::ok(); |
328 | | } |
329 | | }, |
330 | 456 | parser::RFBGlobalState::TSClientInit => match parser::parse_client_init(current) { |
331 | 456 | Ok((rem, request)) => { |
332 | 456 | consumed += current.len() - rem.len(); |
333 | 456 | let _pdu = Frame::new( |
334 | 456 | flow, |
335 | 456 | &stream_slice, |
336 | 456 | current, |
337 | 456 | consumed as i64, |
338 | 456 | RFBFrameType::Pdu as u8, |
339 | 456 | ); |
340 | 456 | |
341 | 456 | current = rem; |
342 | 456 | |
343 | 456 | self.state = parser::RFBGlobalState::TCServerInit; |
344 | | |
345 | 456 | if let Some(current_transaction) = self.get_current_tx() { |
346 | 456 | current_transaction.ts_client_init = Some(request); |
347 | 456 | } else { |
348 | 0 | debug_validate_fail!("no transaction set at client init stage"); |
349 | | } |
350 | | } |
351 | | Err(Err::Incomplete(_)) => { |
352 | 0 | return AppLayerResult::incomplete( |
353 | 0 | consumed as u32, |
354 | 0 | (current.len() + 1) as u32, |
355 | 0 | ); |
356 | | } |
357 | | Err(_) => { |
358 | 0 | if let Some(current_transaction) = self.get_current_tx() { |
359 | 0 | current_transaction.set_event(RFBEvent::MalformedMessage); |
360 | 0 | current_transaction.complete = true; |
361 | 0 | } |
362 | | // We failed to parse the client init. |
363 | | // Continue the flow but stop trying to map the protocol. |
364 | 0 | self.state = parser::RFBGlobalState::Skip; |
365 | 0 | return AppLayerResult::ok(); |
366 | | } |
367 | | }, |
368 | | parser::RFBGlobalState::Skip => { |
369 | | // End of parseable handshake reached, skip rest of traffic |
370 | 2.18k | return AppLayerResult::ok(); |
371 | | } |
372 | | _ => { |
373 | | // We have gotten out of sync with the expected state flow. |
374 | | // This could happen since we use a global state (i.e. that |
375 | | // is used for both directions), but if traffic can not be |
376 | | // parsed as expected elsewhere, we might not have advanced |
377 | | // a state for one direction but received data in the |
378 | | // "unexpected" direction, causing the parser to end up |
379 | | // here. Let's stop trying to parse the traffic but still |
380 | | // accept it. |
381 | | SCLogDebug!("Invalid state for request: {}", self.state); |
382 | 241 | if let Some(current_transaction) = self.get_current_tx() { |
383 | 82 | current_transaction.set_event(RFBEvent::ConfusedState); |
384 | 82 | current_transaction.complete = true; |
385 | 159 | } |
386 | 241 | self.state = parser::RFBGlobalState::Skip; |
387 | 241 | return AppLayerResult::ok(); |
388 | | } |
389 | | } |
390 | | } |
391 | 4.65k | } |
392 | | |
393 | 15.1k | fn parse_response(&mut self, flow: *const Flow, stream_slice: StreamSlice) -> AppLayerResult { |
394 | 15.1k | let input = stream_slice.as_slice(); |
395 | 15.1k | // We're not interested in empty responses. |
396 | 15.1k | if input.is_empty() { |
397 | 0 | return AppLayerResult::ok(); |
398 | 15.1k | } |
399 | 15.1k | |
400 | 15.1k | let mut current = input; |
401 | 15.1k | let mut consumed = 0; |
402 | | SCLogDebug!( |
403 | | "response_state {}, response_len {}", |
404 | | self.state, |
405 | | input.len() |
406 | | ); |
407 | | loop { |
408 | 17.5k | if current.is_empty() { |
409 | 1.63k | return AppLayerResult::ok(); |
410 | 15.9k | } |
411 | 15.9k | match self.state { |
412 | | parser::RFBGlobalState::TCServerProtocolVersion => { |
413 | 3.24k | match parser::parse_protocol_version(current) { |
414 | 1.25k | Ok((rem, request)) => { |
415 | 1.25k | consumed += current.len() - rem.len(); |
416 | 1.25k | let _pdu = Frame::new( |
417 | 1.25k | flow, |
418 | 1.25k | &stream_slice, |
419 | 1.25k | current, |
420 | 1.25k | consumed as i64, |
421 | 1.25k | RFBFrameType::Pdu as u8, |
422 | 1.25k | ); |
423 | 1.25k | |
424 | 1.25k | current = rem; |
425 | 1.25k | |
426 | 1.25k | self.state = parser::RFBGlobalState::TSClientProtocolVersion; |
427 | 1.25k | let tx = self.new_tx(); |
428 | 1.25k | self.transactions.push(tx); |
429 | | |
430 | 1.25k | if let Some(current_transaction) = self.get_current_tx() { |
431 | 1.25k | current_transaction.tc_server_protocol_version = Some(request); |
432 | 1.25k | } else { |
433 | 0 | debug_validate_fail!("no transaction set but we just set one"); |
434 | | } |
435 | | } |
436 | | Err(Err::Incomplete(_)) => { |
437 | 1.90k | return AppLayerResult::incomplete( |
438 | 1.90k | consumed as u32, |
439 | 1.90k | (current.len() + 1) as u32, |
440 | 1.90k | ); |
441 | | } |
442 | | Err(_) => { |
443 | | // We even failed to parse the protocol version. |
444 | 85 | return AppLayerResult::err(); |
445 | | } |
446 | | } |
447 | | } |
448 | | parser::RFBGlobalState::TCSupportedSecurityTypes => { |
449 | 1.18k | match parser::parse_supported_security_types(current) { |
450 | 732 | Ok((rem, request)) => { |
451 | 732 | consumed += current.len() - rem.len(); |
452 | 732 | let _pdu = Frame::new( |
453 | 732 | flow, |
454 | 732 | &stream_slice, |
455 | 732 | current, |
456 | 732 | consumed as i64, |
457 | 732 | RFBFrameType::Pdu as u8, |
458 | 732 | ); |
459 | 732 | |
460 | 732 | current = rem; |
461 | 732 | |
462 | 732 | SCLogDebug!( |
463 | 732 | "supported_security_types: {}, types: {}", |
464 | 732 | request.number_of_types, |
465 | 732 | request |
466 | 732 | .types |
467 | 732 | .iter() |
468 | 732 | .map(ToString::to_string) |
469 | 732 | .map(|v| v + " ") |
470 | 732 | .collect::<String>() |
471 | 732 | ); |
472 | 732 | |
473 | 732 | self.state = parser::RFBGlobalState::TSSecurityTypeSelection; |
474 | 732 | if request.number_of_types == 0 { |
475 | 229 | self.state = parser::RFBGlobalState::TCFailureReason; |
476 | 503 | } |
477 | | |
478 | 732 | if let Some(current_transaction) = self.get_current_tx() { |
479 | 732 | current_transaction.tc_supported_security_types = Some(request); |
480 | 732 | } else { |
481 | 0 | debug_validate_fail!("no transaction set at security type stage"); |
482 | | } |
483 | | } |
484 | | Err(Err::Incomplete(_)) => { |
485 | 448 | return AppLayerResult::incomplete( |
486 | 448 | consumed as u32, |
487 | 448 | (current.len() + 1) as u32, |
488 | 448 | ); |
489 | | } |
490 | | Err(_) => { |
491 | 0 | if let Some(current_transaction) = self.get_current_tx() { |
492 | 0 | current_transaction.set_event(RFBEvent::MalformedMessage); |
493 | 0 | current_transaction.complete = true; |
494 | 0 | } |
495 | | // Continue the flow but stop trying to map the protocol. |
496 | 0 | self.state = parser::RFBGlobalState::Skip; |
497 | 0 | return AppLayerResult::ok(); |
498 | | } |
499 | | } |
500 | | } |
501 | | parser::RFBGlobalState::TCServerSecurityType => { |
502 | | // In RFB 3.3, the server decides the authentication type |
503 | 490 | match parser::parse_server_security_type(current) { |
504 | 167 | Ok((rem, request)) => { |
505 | 167 | consumed += current.len() - rem.len(); |
506 | 167 | let _pdu = Frame::new( |
507 | 167 | flow, |
508 | 167 | &stream_slice, |
509 | 167 | current, |
510 | 167 | consumed as i64, |
511 | 167 | RFBFrameType::Pdu as u8, |
512 | 167 | ); |
513 | 167 | |
514 | 167 | current = rem; |
515 | 167 | |
516 | 167 | let chosen_security_type = request.security_type; |
517 | 167 | SCLogDebug!("chosen_security_type: {}", chosen_security_type); |
518 | 167 | match chosen_security_type { |
519 | 22 | 0 => self.state = parser::RFBGlobalState::TCFailureReason, |
520 | 0 | 1 => self.state = parser::RFBGlobalState::TSClientInit, |
521 | 106 | 2 => self.state = parser::RFBGlobalState::TCVncChallenge, |
522 | | _ => { |
523 | 39 | if let Some(current_transaction) = self.get_current_tx() { |
524 | 39 | current_transaction |
525 | 39 | .set_event(RFBEvent::UnimplementedSecurityType); |
526 | 39 | current_transaction.complete = true; |
527 | 39 | } else { |
528 | 0 | debug_validate_fail!( |
529 | 0 | "no transaction set at security type stage" |
530 | | ); |
531 | | } |
532 | | // We have just have seen a security type we don't know about. |
533 | | // This is not bad per se, it might just mean this is a |
534 | | // proprietary one not in the spec. |
535 | | // Continue the flow but stop trying to map the protocol. |
536 | 39 | self.state = parser::RFBGlobalState::Skip; |
537 | 39 | return AppLayerResult::ok(); |
538 | | } |
539 | | } |
540 | | |
541 | 128 | if let Some(current_transaction) = self.get_current_tx() { |
542 | 128 | current_transaction.tc_server_security_type = Some(request); |
543 | 128 | current_transaction.chosen_security_type = |
544 | 128 | Some(chosen_security_type); |
545 | 128 | } else { |
546 | 0 | debug_validate_fail!("no transaction set at security type stage"); |
547 | | } |
548 | | } |
549 | | Err(Err::Incomplete(_)) => { |
550 | 323 | return AppLayerResult::incomplete( |
551 | 323 | consumed as u32, |
552 | 323 | (current.len() + 1) as u32, |
553 | 323 | ); |
554 | | } |
555 | | Err(_) => { |
556 | 0 | if let Some(current_transaction) = self.get_current_tx() { |
557 | 0 | current_transaction.set_event(RFBEvent::MalformedMessage); |
558 | 0 | current_transaction.complete = true; |
559 | 0 | } |
560 | | // Continue the flow but stop trying to map the protocol. |
561 | 0 | self.state = parser::RFBGlobalState::Skip; |
562 | 0 | return AppLayerResult::ok(); |
563 | | } |
564 | | } |
565 | | } |
566 | 320 | parser::RFBGlobalState::TCVncChallenge => match parser::parse_vnc_auth(current) { |
567 | 100 | Ok((rem, request)) => { |
568 | 100 | consumed += current.len() - rem.len(); |
569 | 100 | let _pdu = Frame::new( |
570 | 100 | flow, |
571 | 100 | &stream_slice, |
572 | 100 | current, |
573 | 100 | consumed as i64, |
574 | 100 | RFBFrameType::Pdu as u8, |
575 | 100 | ); |
576 | 100 | |
577 | 100 | current = rem; |
578 | 100 | |
579 | 100 | self.state = parser::RFBGlobalState::TSVncResponse; |
580 | | |
581 | 100 | if let Some(current_transaction) = self.get_current_tx() { |
582 | 100 | current_transaction.tc_vnc_challenge = Some(request); |
583 | 100 | } else { |
584 | 0 | debug_validate_fail!("no transaction set at auth stage"); |
585 | | } |
586 | | } |
587 | | Err(Err::Incomplete(_)) => { |
588 | 220 | return AppLayerResult::incomplete( |
589 | 220 | consumed as u32, |
590 | 220 | (current.len() + 1) as u32, |
591 | 220 | ); |
592 | | } |
593 | | Err(_) => { |
594 | 0 | if let Some(current_transaction) = self.get_current_tx() { |
595 | 0 | current_transaction.set_event(RFBEvent::MalformedMessage); |
596 | 0 | current_transaction.complete = true; |
597 | 0 | } |
598 | | // Continue the flow but stop trying to map the protocol. |
599 | 0 | self.state = parser::RFBGlobalState::Skip; |
600 | 0 | return AppLayerResult::ok(); |
601 | | } |
602 | | }, |
603 | | parser::RFBGlobalState::TCSecurityResult => { |
604 | 247 | match parser::parse_security_result(current) { |
605 | 29 | Ok((rem, request)) => { |
606 | 29 | consumed += current.len() - rem.len(); |
607 | 29 | let _pdu = Frame::new( |
608 | 29 | flow, |
609 | 29 | &stream_slice, |
610 | 29 | current, |
611 | 29 | consumed as i64, |
612 | 29 | RFBFrameType::Pdu as u8, |
613 | 29 | ); |
614 | 29 | |
615 | 29 | current = rem; |
616 | 29 | |
617 | 29 | if request.status == 0 { |
618 | 16 | self.state = parser::RFBGlobalState::TSClientInit; |
619 | | |
620 | 16 | if let Some(current_transaction) = self.get_current_tx() { |
621 | 16 | current_transaction.tc_security_result = Some(request); |
622 | 16 | } else { |
623 | 0 | debug_validate_fail!( |
624 | 0 | "no transaction set at security result stage" |
625 | | ); |
626 | | } |
627 | 13 | } else if request.status == 1 { |
628 | 7 | self.state = parser::RFBGlobalState::TCFailureReason; |
629 | 7 | } else { |
630 | 6 | if let Some(current_transaction) = self.get_current_tx() { |
631 | 6 | current_transaction.set_event(RFBEvent::UnknownSecurityResult); |
632 | 6 | current_transaction.complete = true; |
633 | 6 | } |
634 | | // Continue the flow but stop trying to map the protocol. |
635 | 6 | self.state = parser::RFBGlobalState::Skip; |
636 | 6 | return AppLayerResult::ok(); |
637 | | } |
638 | | } |
639 | | Err(Err::Incomplete(_)) => { |
640 | 218 | return AppLayerResult::incomplete( |
641 | 218 | consumed as u32, |
642 | 218 | (current.len() + 1) as u32, |
643 | 218 | ); |
644 | | } |
645 | | Err(_) => { |
646 | 0 | if let Some(current_transaction) = self.get_current_tx() { |
647 | 0 | current_transaction.set_event(RFBEvent::MalformedMessage); |
648 | 0 | current_transaction.complete = true; |
649 | 0 | } |
650 | | // Continue the flow but stop trying to map the protocol. |
651 | 0 | self.state = parser::RFBGlobalState::Skip; |
652 | 0 | return AppLayerResult::ok(); |
653 | | } |
654 | | } |
655 | | } |
656 | | parser::RFBGlobalState::TCFailureReason => { |
657 | 4.67k | match parser::parse_failure_reason(current) { |
658 | 1.46k | Ok((_rem, request)) => { |
659 | 1.46k | if let Some(current_transaction) = self.get_current_tx() { |
660 | 1.46k | current_transaction.tc_failure_reason = Some(request); |
661 | 1.46k | } else { |
662 | 0 | debug_validate_fail!("no transaction set at failure reason stage"); |
663 | | } |
664 | 1.46k | return AppLayerResult::ok(); |
665 | | } |
666 | | Err(Err::Incomplete(_)) => { |
667 | 3.19k | return AppLayerResult::incomplete( |
668 | 3.19k | consumed as u32, |
669 | 3.19k | (current.len() + 1) as u32, |
670 | 3.19k | ); |
671 | | } |
672 | | Err(_) => { |
673 | 16 | if let Some(current_transaction) = self.get_current_tx() { |
674 | 16 | current_transaction.set_event(RFBEvent::MalformedMessage); |
675 | 16 | current_transaction.complete = true; |
676 | 16 | } |
677 | | // Continue the flow but stop trying to map the protocol. |
678 | 16 | self.state = parser::RFBGlobalState::Skip; |
679 | 16 | return AppLayerResult::ok(); |
680 | | } |
681 | | } |
682 | | } |
683 | | parser::RFBGlobalState::TCServerInit => { |
684 | 3.37k | match parser::parse_server_init(current) { |
685 | 196 | Ok((rem, request)) => { |
686 | 196 | consumed += current.len() - rem.len(); |
687 | 196 | let _pdu = Frame::new( |
688 | 196 | flow, |
689 | 196 | &stream_slice, |
690 | 196 | current, |
691 | 196 | consumed as i64, |
692 | 196 | RFBFrameType::Pdu as u8, |
693 | 196 | ); |
694 | 196 | |
695 | 196 | current = rem; |
696 | 196 | |
697 | 196 | self.state = parser::RFBGlobalState::Skip; |
698 | | |
699 | 196 | if let Some(current_transaction) = self.get_current_tx() { |
700 | 196 | current_transaction.tc_server_init = Some(request); |
701 | 196 | // connection initialization is complete and parsed |
702 | 196 | current_transaction.complete = true; |
703 | 196 | } else { |
704 | 0 | debug_validate_fail!("no transaction set at server init stage"); |
705 | | } |
706 | | } |
707 | | Err(Err::Incomplete(_)) => { |
708 | 3.18k | return AppLayerResult::incomplete( |
709 | 3.18k | consumed as u32, |
710 | 3.18k | (current.len() + 1) as u32, |
711 | 3.18k | ); |
712 | | } |
713 | | Err(_) => { |
714 | 0 | if let Some(current_transaction) = self.get_current_tx() { |
715 | 0 | current_transaction.set_event(RFBEvent::MalformedMessage); |
716 | 0 | current_transaction.complete = true; |
717 | 0 | } |
718 | | // Continue the flow but stop trying to map the protocol. |
719 | 0 | self.state = parser::RFBGlobalState::Skip; |
720 | 0 | return AppLayerResult::ok(); |
721 | | } |
722 | | } |
723 | | } |
724 | | parser::RFBGlobalState::Skip => { |
725 | | //todo implement RFB messages, for now we stop here |
726 | 2.13k | return AppLayerResult::ok(); |
727 | | } |
728 | | _ => { |
729 | | // We have gotten out of sync with the expected state flow. |
730 | | // This could happen since we use a global state (i.e. that |
731 | | // is used for both directions), but if traffic can not be |
732 | | // parsed as expected elsewhere, we might not have advanced |
733 | | // a state for one direction but received data in the |
734 | | // "unexpected" direction, causing the parser to end up |
735 | | // here. Let's stop trying to parse the traffic but still |
736 | | // accept it. |
737 | | SCLogDebug!("Invalid state for response: {}", self.state); |
738 | 287 | if let Some(current_transaction) = self.get_current_tx() { |
739 | 287 | current_transaction.set_event(RFBEvent::ConfusedState); |
740 | 287 | current_transaction.complete = true; |
741 | 287 | } |
742 | 287 | self.state = parser::RFBGlobalState::Skip; |
743 | 287 | return AppLayerResult::ok(); |
744 | | } |
745 | | } |
746 | | } |
747 | 15.1k | } |
748 | | } |
749 | | |
750 | | // C exports. |
751 | | |
752 | | #[no_mangle] |
753 | 1.57k | pub extern "C" fn rs_rfb_state_new( |
754 | 1.57k | _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, |
755 | 1.57k | ) -> *mut std::os::raw::c_void { |
756 | 1.57k | let state = RFBState::new(); |
757 | 1.57k | let boxed = Box::new(state); |
758 | 1.57k | return Box::into_raw(boxed) as *mut _; |
759 | 1.57k | } |
760 | | |
761 | | #[no_mangle] |
762 | 1.57k | pub extern "C" fn rs_rfb_state_free(state: *mut std::os::raw::c_void) { |
763 | 1.57k | // Just unbox... |
764 | 1.57k | std::mem::drop(unsafe { Box::from_raw(state as *mut RFBState) }); |
765 | 1.57k | } |
766 | | |
767 | | #[no_mangle] |
768 | 44 | pub unsafe extern "C" fn rs_rfb_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { |
769 | 44 | let state = cast_pointer!(state, RFBState); |
770 | 44 | state.free_tx(tx_id); |
771 | 44 | } |
772 | | |
773 | | #[no_mangle] |
774 | 4.65k | pub unsafe extern "C" fn rs_rfb_parse_request( |
775 | 4.65k | flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, |
776 | 4.65k | stream_slice: StreamSlice, _data: *const std::os::raw::c_void, |
777 | 4.65k | ) -> AppLayerResult { |
778 | 4.65k | let state = cast_pointer!(state, RFBState); |
779 | 4.65k | return state.parse_request(flow, stream_slice); |
780 | 4.65k | } |
781 | | |
782 | | #[no_mangle] |
783 | 15.1k | pub unsafe extern "C" fn rs_rfb_parse_response( |
784 | 15.1k | flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, |
785 | 15.1k | stream_slice: StreamSlice, _data: *const std::os::raw::c_void, |
786 | 15.1k | ) -> AppLayerResult { |
787 | 15.1k | let state = cast_pointer!(state, RFBState); |
788 | 15.1k | return state.parse_response(flow, stream_slice); |
789 | 15.1k | } |
790 | | |
791 | | #[no_mangle] |
792 | 18 | pub unsafe extern "C" fn rs_rfb_state_get_tx( |
793 | 18 | state: *mut std::os::raw::c_void, tx_id: u64, |
794 | 18 | ) -> *mut std::os::raw::c_void { |
795 | 18 | let state = cast_pointer!(state, RFBState); |
796 | 18 | match state.get_tx(tx_id) { |
797 | 0 | Some(tx) => { |
798 | 0 | return tx as *const _ as *mut _; |
799 | | } |
800 | | None => { |
801 | 18 | return std::ptr::null_mut(); |
802 | | } |
803 | | } |
804 | 18 | } |
805 | | |
806 | | #[no_mangle] |
807 | 59.9k | pub unsafe extern "C" fn rs_rfb_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { |
808 | 59.9k | let state = cast_pointer!(state, RFBState); |
809 | 59.9k | return state.tx_id; |
810 | 59.9k | } |
811 | | |
812 | | #[no_mangle] |
813 | 12.5k | pub unsafe extern "C" fn rs_rfb_tx_get_alstate_progress( |
814 | 12.5k | tx: *mut std::os::raw::c_void, _direction: u8, |
815 | 12.5k | ) -> std::os::raw::c_int { |
816 | 12.5k | let tx = cast_pointer!(tx, RFBTransaction); |
817 | 12.5k | if tx.complete { |
818 | 126 | return 1; |
819 | 12.4k | } |
820 | 12.4k | return 0; |
821 | 12.5k | } |
822 | | |
823 | | // Parser name as a C style string. |
824 | | const PARSER_NAME: &[u8] = b"rfb\0"; |
825 | | |
826 | | export_tx_data_get!(rs_rfb_get_tx_data, RFBTransaction); |
827 | | export_state_data_get!(rs_rfb_get_state_data, RFBState); |
828 | | |
829 | | #[no_mangle] |
830 | 34 | pub unsafe extern "C" fn rs_rfb_register_parser() { |
831 | 34 | let parser = RustParser { |
832 | 34 | name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char, |
833 | 34 | default_port: std::ptr::null(), |
834 | 34 | ipproto: IPPROTO_TCP, |
835 | 34 | probe_ts: None, |
836 | 34 | probe_tc: None, |
837 | 34 | min_depth: 0, |
838 | 34 | max_depth: 16, |
839 | 34 | state_new: rs_rfb_state_new, |
840 | 34 | state_free: rs_rfb_state_free, |
841 | 34 | tx_free: rs_rfb_state_tx_free, |
842 | 34 | parse_ts: rs_rfb_parse_request, |
843 | 34 | parse_tc: rs_rfb_parse_response, |
844 | 34 | get_tx_count: rs_rfb_state_get_tx_count, |
845 | 34 | get_tx: rs_rfb_state_get_tx, |
846 | 34 | tx_comp_st_ts: 1, |
847 | 34 | tx_comp_st_tc: 1, |
848 | 34 | tx_get_progress: rs_rfb_tx_get_alstate_progress, |
849 | 34 | get_eventinfo: Some(RFBEvent::get_event_info), |
850 | 34 | get_eventinfo_byid: Some(RFBEvent::get_event_info_by_id), |
851 | 34 | localstorage_new: None, |
852 | 34 | localstorage_free: None, |
853 | 34 | get_tx_files: None, |
854 | 34 | get_tx_iterator: Some(applayer::state_get_tx_iterator::<RFBState, RFBTransaction>), |
855 | 34 | get_tx_data: rs_rfb_get_tx_data, |
856 | 34 | get_state_data: rs_rfb_get_state_data, |
857 | 34 | apply_tx_config: None, |
858 | 34 | flags: 0, |
859 | 34 | truncate: None, |
860 | 34 | get_frame_id_by_name: Some(RFBFrameType::ffi_id_from_name), |
861 | 34 | get_frame_name_by_id: Some(RFBFrameType::ffi_name_from_id), |
862 | 34 | }; |
863 | 34 | |
864 | 34 | let ip_proto_str = CString::new("tcp").unwrap(); |
865 | 34 | |
866 | 34 | if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { |
867 | 34 | let alproto = AppLayerRegisterProtocolDetection(&parser, 1); |
868 | 34 | ALPROTO_RFB = alproto; |
869 | 34 | if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { |
870 | 34 | let _ = AppLayerRegisterParser(&parser, alproto); |
871 | 34 | } |
872 | | SCLogDebug!("Rust rfb parser registered."); |
873 | 0 | } else { |
874 | 0 | SCLogDebug!("Protocol detector and parser disabled for RFB."); |
875 | 0 | } |
876 | 34 | } |
877 | | |
878 | | #[cfg(test)] |
879 | | mod test { |
880 | | use super::*; |
881 | | use crate::core::STREAM_START; |
882 | | |
883 | | #[test] |
884 | | fn test_error_state() { |
885 | | let mut state = RFBState::new(); |
886 | | |
887 | | let buf: &[u8] = &[ |
888 | | 0x05, 0x00, 0x03, 0x20, 0x20, 0x18, 0x00, 0x01, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, |
889 | | 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x61, 0x6e, 0x65, 0x61, |
890 | | 0x67, 0x6c, 0x65, 0x73, 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, |
891 | | 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, |
892 | | ]; |
893 | | let r = state.parse_response( |
894 | | std::ptr::null(), |
895 | | StreamSlice::from_slice(buf, STREAM_START, 0), |
896 | | ); |
897 | | |
898 | | assert_eq!( |
899 | | r, |
900 | | AppLayerResult { |
901 | | status: -1, |
902 | | consumed: 0, |
903 | | needed: 0 |
904 | | } |
905 | | ); |
906 | | } |
907 | | |
908 | | // Test the state machine for RFB protocol |
909 | | // Passes an initial buffer with initial RFBState = TCServerProtocolVersion |
910 | | // Tests various client and server RFBStates as the buffer is parsed using parse_request and parse_response functions |
911 | | #[test] |
912 | | fn test_rfb_state_machine() { |
913 | | let mut init_state = RFBState::new(); |
914 | | |
915 | | let buf: &[u8] = &[ |
916 | | 0x52, 0x46, 0x42, 0x20, 0x30, 0x30, 0x33, 0x2e, 0x30, 0x30, 0x38, 0x0a, |
917 | | 0x01, /* Number of security types: 1 */ |
918 | | 0x02, /* Security type: VNC (2) */ |
919 | | 0x02, /* Security type selected: VNC (2) */ |
920 | | 0x54, 0x7b, 0x7a, 0x6f, 0x36, 0xa1, 0x54, 0xdb, 0x03, 0xa2, 0x57, 0x5c, 0x6f, 0x2a, |
921 | | 0x4e, |
922 | | 0xc5, /* 16 byte Authentication challenge: 547b7a6f36a154db03a2575c6f2a4ec5 */ |
923 | | 0x00, 0x00, 0x00, 0x00, /* Authentication result: OK */ |
924 | | 0x00, /* Share desktop flag: False */ |
925 | | 0x05, 0x00, 0x03, 0x20, 0x20, 0x18, 0x00, 0x01, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, |
926 | | 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x61, 0x6e, 0x65, 0x61, |
927 | | 0x67, 0x6c, 0x65, 0x73, 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, |
928 | | 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, |
929 | | 0x6e, /* Server framebuffer parameters */ |
930 | | ]; |
931 | | |
932 | | //The buffer values correspond to Server Protocol version: 003.008 |
933 | | // Same buffer is used for both functions due to similar values in request and response |
934 | | init_state.parse_response( |
935 | | std::ptr::null(), |
936 | | StreamSlice::from_slice(&buf[0..12], STREAM_START, 0), |
937 | | ); |
938 | | let mut ok_state = parser::RFBGlobalState::TSClientProtocolVersion; |
939 | | assert_eq!(init_state.state, ok_state); |
940 | | |
941 | | //The buffer values correspond to Client Protocol version: 003.008 |
942 | | init_state.parse_request( |
943 | | std::ptr::null(), |
944 | | StreamSlice::from_slice(&buf[0..12], STREAM_START, 0), |
945 | | ); |
946 | | ok_state = parser::RFBGlobalState::TCSupportedSecurityTypes; |
947 | | assert_eq!(init_state.state, ok_state); |
948 | | |
949 | | init_state.parse_response( |
950 | | std::ptr::null(), |
951 | | StreamSlice::from_slice(&buf[12..14], STREAM_START, 0), |
952 | | ); |
953 | | ok_state = parser::RFBGlobalState::TSSecurityTypeSelection; |
954 | | assert_eq!(init_state.state, ok_state); |
955 | | |
956 | | init_state.parse_request( |
957 | | std::ptr::null(), |
958 | | StreamSlice::from_slice(&buf[14..15], STREAM_START, 0), |
959 | | ); |
960 | | ok_state = parser::RFBGlobalState::TCVncChallenge; |
961 | | assert_eq!(init_state.state, ok_state); |
962 | | |
963 | | //The buffer values correspond to Server Authentication challenge: 547b7a6f36a154db03a2575c6f2a4ec5 |
964 | | // Same buffer is used for both functions due to similar values in request and response |
965 | | init_state.parse_response( |
966 | | std::ptr::null(), |
967 | | StreamSlice::from_slice(&buf[15..31], STREAM_START, 0), |
968 | | ); |
969 | | ok_state = parser::RFBGlobalState::TSVncResponse; |
970 | | assert_eq!(init_state.state, ok_state); |
971 | | |
972 | | //The buffer values correspond to Client Authentication response: 547b7a6f36a154db03a2575c6f2a4ec5 |
973 | | init_state.parse_request( |
974 | | std::ptr::null(), |
975 | | StreamSlice::from_slice(&buf[15..31], STREAM_START, 0), |
976 | | ); |
977 | | ok_state = parser::RFBGlobalState::TCSecurityResult; |
978 | | assert_eq!(init_state.state, ok_state); |
979 | | |
980 | | init_state.parse_response( |
981 | | std::ptr::null(), |
982 | | StreamSlice::from_slice(&buf[31..35], STREAM_START, 0), |
983 | | ); |
984 | | ok_state = parser::RFBGlobalState::TSClientInit; |
985 | | assert_eq!(init_state.state, ok_state); |
986 | | |
987 | | init_state.parse_request( |
988 | | std::ptr::null(), |
989 | | StreamSlice::from_slice(&buf[35..36], STREAM_START, 0), |
990 | | ); |
991 | | ok_state = parser::RFBGlobalState::TCServerInit; |
992 | | assert_eq!(init_state.state, ok_state); |
993 | | |
994 | | init_state.parse_response( |
995 | | std::ptr::null(), |
996 | | StreamSlice::from_slice(&buf[36..90], STREAM_START, 0), |
997 | | ); |
998 | | ok_state = parser::RFBGlobalState::Skip; |
999 | | assert_eq!(init_state.state, ok_state); |
1000 | | } |
1001 | | } |