Coverage Report

Created: 2026-11-12 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/rust/src/websocket/parser.rs
Line
Count
Source
1
/* Copyright (C) 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
use nom7::bytes::streaming::take;
19
use nom7::combinator::cond;
20
use nom7::number::streaming::{be_u16, be_u32, be_u64, be_u8};
21
use nom7::IResult;
22
use suricata_derive::EnumStringU8;
23
24
#[derive(Clone, Debug, Default, EnumStringU8)]
25
#[repr(u8)]
26
pub enum WebSocketOpcode {
27
    #[default]
28
    Continuation = 0,
29
    Text = 1,
30
    Binary = 2,
31
    Close = 8,
32
    Ping = 9,
33
    Pong = 10,
34
}
35
36
#[derive(Clone, Debug, Default)]
37
pub struct WebSocketPdu {
38
    pub flags: u8,
39
    pub fin: bool,
40
    pub compress: bool,
41
    pub opcode: u8,
42
    pub mask: Option<u32>,
43
    pub payload: Vec<u8>,
44
    pub to_skip: u64,
45
}
46
47
// cf rfc6455#section-5.2
48
1.94M
pub fn parse_message(i: &[u8], max_pl_size: u32) -> IResult<&[u8], WebSocketPdu> {
49
1.94M
    let (i, flags_op) = be_u8(i)?;
50
1.94M
    let fin = (flags_op & 0x80) != 0;
51
1.94M
    let compress = (flags_op & 0x40) != 0;
52
1.94M
    let flags = flags_op & 0xF0;
53
1.94M
    let opcode = flags_op & 0xF;
54
1.94M
    let (i, mask_plen) = be_u8(i)?;
55
1.93M
    let mask_flag = (mask_plen & 0x80) != 0;
56
1.93M
    let (i, payload_len) = match mask_plen & 0x7F {
57
        126 => {
58
700
            let (i, val) = be_u16(i)?;
59
604
            Ok((i, val.into()))
60
        }
61
5.30k
        127 => be_u64(i),
62
1.92M
        _ => Ok((i, (mask_plen & 0x7F).into())),
63
1.11k
    }?;
64
1.92M
    let (i, xormask) = cond(mask_flag, take(4usize))(i)?;
65
1.92M
    let mask = if mask_flag {
66
26.6k
        let (_, m) = be_u32(xormask.unwrap())?;
67
26.6k
        Some(m)
68
    } else {
69
1.90M
        None
70
    };
71
    // we limit payload_len to u32, so as to build on 32-bit system
72
    // where we cannot take(usize) with a u64
73
1.92M
    let (to_skip, payload_len) = if payload_len < u64::from(max_pl_size) {
74
1.92M
        (0, payload_len as u32)
75
    } else {
76
3.47k
        (payload_len - (max_pl_size as u64), max_pl_size)
77
    };
78
1.92M
    let (i, payload_raw) = take(payload_len)(i)?;
79
1.89M
    let mut payload = payload_raw.to_vec();
80
1.89M
    if let Some(xorkey) = xormask {
81
8.71M
        for i in 0..payload.len() {
82
8.71M
            payload[i] ^= xorkey[i % 4];
83
8.71M
        }
84
1.87M
    }
85
1.89M
    Ok((
86
1.89M
        i,
87
1.89M
        WebSocketPdu {
88
1.89M
            flags,
89
1.89M
            fin,
90
1.89M
            compress,
91
1.89M
            opcode,
92
1.89M
            mask,
93
1.89M
            payload,
94
1.89M
            to_skip,
95
1.89M
        },
96
1.89M
    ))
97
1.94M
}