1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//! Telnet Protocol (`TELNET`, RFC 854) Layer 7 option negotiation and NVT PCAP-to-`.fasm` decompiler.
//!
//! This module implements the fuzz-safe reverse dissector for RFC 854 `TELNET` Interpret As
//! Command (`0xFF` IAC) option negotiation sequences (`will`, `wont`, `do`, `dont`) and Network
//! Virtual Terminal (`NVT`) ASCII data streams carried over TCP ports `23`, `2323`, `2001`, and
//! `4000`. Printable UTF-8 text is emitted via the `data` modifier, while non-ASCII or binary
//! terminal escape sequences following an IAC command are preserved verbatim as residual payload
//! bytes.
use alloc::string::String;
use alloc::vec::Vec;
use core::fmt::Write as _;
use crate::ast::Protocol;
use crate::reverse::{ProtocolDissection, sd};
use super::{is_valid_raw_string_body, push_str_mod};
/// Dissects an RFC 854 Telnet IAC option negotiation or NVT data stream on TCP port `23`.
pub(crate) fn dissect_telnet(payload: &[u8]) -> Option<ProtocolDissection> {
let mut tokens = String::from("telnet");
let mut offset = 0usize;
if let &[0xFF, cmd @ 0xFB..=0xFE, opt, ..] = payload {
let kw = ["will", "wont", "do", "dont"][(cmd - 0xFB) as usize];
if cmd != 0xFD || opt != 1 || payload.len() > 3 {
let _ = write!(tokens, " {kw} {opt}");
}
offset = 3;
}
let rest = payload.get(offset..)?;
let mut residual = Vec::new();
if offset == 0 || !rest.is_empty() {
if let Ok(s) = core::str::from_utf8(rest)
&& is_valid_raw_string_body(s)
{
push_str_mod(&mut tokens, "data", s);
} else {
if offset == 0 {
tokens.push_str(" data \"\"");
}
residual = rest.to_vec();
}
}
Some(sd(Protocol::Telnet, tokens, residual))
}