/src/suricata7/rust/src/telnet/parser.rs
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2021 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 | | use crate::common::nom7::take_until_and_consume; |
19 | | use nom7::combinator::peek; |
20 | | use nom7::bytes::complete::take; |
21 | | use nom7::{IResult}; |
22 | | use nom7::number::streaming::le_u8; |
23 | | use nom7::bytes::streaming::tag; |
24 | | use nom7::bytes::streaming::{take_until}; |
25 | | |
26 | 1.49M | pub fn peek_message_is_ctl(i: &[u8]) -> IResult<&[u8], bool> { |
27 | 1.49M | let (i, v) = peek(le_u8)(i)?; |
28 | 1.49M | Ok((i, v == b'\xff')) |
29 | 1.49M | } |
30 | | |
31 | | pub enum TelnetMessageType<'a> { |
32 | | Control(&'a [u8]), |
33 | | Data(&'a [u8]), |
34 | | } |
35 | | |
36 | 12.4k | pub fn parse_ctl_suboption<'a>(i: &'a[u8], full: &'a[u8]) -> IResult<&'a[u8], &'a[u8]> { |
37 | 12.4k | let (i, _sc) = le_u8(i)?; |
38 | 11.6k | let tag: &[u8] = b"\xff\xf0"; |
39 | 11.6k | let (i, x) = take_until(tag)(i)?; |
40 | 3.70k | let o = &full[..(x.len()+3)]; |
41 | 3.70k | Ok((i, o)) |
42 | 12.4k | } |
43 | | |
44 | 116k | pub fn parse_ctl_message(oi: &[u8]) -> IResult<&[u8], &[u8]> { |
45 | 116k | let (i, _) = tag(b"\xff")(oi)?; |
46 | 116k | let (i, cmd) = le_u8(i)?; |
47 | 110k | let (i, d) = match cmd { |
48 | 80.2k | 251..=254 => take(3_usize)(oi)?, |
49 | 75.2k | 240..=249 => take(2_usize)(oi)?, |
50 | 12.4k | 250 => parse_ctl_suboption(i, oi)?, |
51 | 65.8k | _ => take(2_usize)(oi)?, // TODO maybe an error or some other special handling |
52 | | }; |
53 | 101k | Ok((i, d)) |
54 | 116k | } |
55 | | |
56 | 1.46M | pub fn parse_message(i: &[u8]) -> IResult<&[u8], TelnetMessageType> { |
57 | 1.46M | let (i, v) = peek(le_u8)(i)?; |
58 | 1.46M | if v == b'\xff' { |
59 | 96.3k | let (i, c) = parse_ctl_message(i)?; |
60 | 85.3k | Ok((i, TelnetMessageType::Control(c))) |
61 | | } else { |
62 | 1.36M | let (i, t) = take_until_and_consume(b"\n")(i)?; |
63 | 1.33M | Ok((i, TelnetMessageType::Data(t))) |
64 | | } |
65 | 1.46M | } |
66 | | |
67 | | // 'login: ', 'Password: ', possibly with leading ctls |
68 | 36.4k | pub fn parse_welcome_message(i: &[u8]) -> IResult<&[u8], TelnetMessageType> { |
69 | 36.4k | let (i, v) = peek(le_u8)(i)?; |
70 | 36.4k | if v == b'\xff' { |
71 | 20.1k | let (i, c) = parse_ctl_message(i)?; |
72 | 16.4k | Ok((i, TelnetMessageType::Control(c))) |
73 | | } else { |
74 | 16.3k | let (i, t) = take_until_and_consume(b": ")(i)?; |
75 | 3.79k | Ok((i, TelnetMessageType::Data(t))) |
76 | | } |
77 | 36.4k | } |