Skip to content

Commit 226f339

Browse files
committed
websocket: handle Sec-WebSocket-Extensions
Optimization to avoid consuming too much memory for decompression
1 parent bf49b2c commit 226f339

File tree

3 files changed

+65
-2
lines changed

3 files changed

+65
-2
lines changed

rust/src/websocket/parser.rs

+12
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,15 @@ pub fn parse_message(i: &[u8], max_pl_size: u32) -> IResult<&[u8], WebSocketPdu>
101101
},
102102
))
103103
}
104+
105+
pub(super) fn parse_cli_max_win(i: &[u8]) -> IResult<&[u8], u8> {
106+
let (i, _space) = space0(i)?;
107+
let (i, _name) = tag("client_max_window_bits=")(i)?;
108+
verify(nomu8, |&v| (9..=15).contains(&v))(i)
109+
}
110+
111+
pub(super) fn parse_srv_max_win(i: &[u8]) -> IResult<&[u8], u8> {
112+
let (i, _space) = space0(i)?;
113+
let (i, _name) = tag("server_max_window_bits=")(i)?;
114+
verify(nomu8, |&v| (9..=15).contains(&v))(i)
115+
}

rust/src/websocket/websocket.rs

+39-2
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,18 @@ impl WebSocketState {
294294
// Input was fully consumed.
295295
return AppLayerResult::ok();
296296
}
297+
298+
fn use_extension(&mut self, hv: &[u8]) {
299+
let iter = hv.split(|c| *c == b';');
300+
for sub in iter {
301+
if let Ok((_, val)) = parser::parse_cli_max_win(sub) {
302+
self.c2s_dec = Some(Decompress::new_with_window_bits(false, val));
303+
}
304+
if let Ok((_, val)) = parser::parse_srv_max_win(sub) {
305+
self.s2c_dec = Some(Decompress::new_with_window_bits(false, val));
306+
}
307+
}
308+
}
297309
}
298310

299311
// C exports.
@@ -316,10 +328,35 @@ pub unsafe extern "C" fn rs_websocket_probing_parser(
316328
return ALPROTO_UNKNOWN;
317329
}
318330

319-
extern "C" fn rs_websocket_state_new(_orig_state: *mut c_void, _orig_proto: AppProto) -> *mut c_void {
331+
// Extern functions operating on HTTP2.
332+
extern "C" {
333+
pub fn Http1GetDataForWebsocket(
334+
orig_state: *mut std::os::raw::c_void, new_state: *mut std::os::raw::c_void,
335+
);
336+
}
337+
338+
#[no_mangle]
339+
pub unsafe extern "C" fn SCWebSocketUseExtension(
340+
state: *mut c_void, input: *const u8, input_len: u32,
341+
) {
342+
if !input.is_null() {
343+
let slice = build_slice!(input, input_len as usize);
344+
let state = cast_pointer!(state, WebSocketState);
345+
state.use_extension(slice);
346+
}
347+
}
348+
349+
extern "C" fn rs_websocket_state_new(orig_state: *mut c_void, orig_proto: AppProto) -> *mut c_void {
320350
let state = WebSocketState::new();
321351
let boxed = Box::new(state);
322-
return Box::into_raw(boxed) as *mut c_void;
352+
let r = Box::into_raw(boxed) as *mut c_void;
353+
if !orig_state.is_null() && orig_proto == ALPROTO_HTTP1 as u16 {
354+
//we could check ALPROTO_HTTP1 == orig_proto
355+
unsafe {
356+
Http1GetDataForWebsocket(orig_state, r);
357+
}
358+
}
359+
return r;
323360
}
324361

325362
unsafe extern "C" fn rs_websocket_state_free(state: *mut c_void) {

src/app-layer-htp.c

+14
Original file line numberDiff line numberDiff line change
@@ -2552,6 +2552,20 @@ void *HtpGetTxForH2(void *alstate)
25522552
return NULL;
25532553
}
25542554

2555+
void Http1GetDataForWebsocket(void *alstate_orig, void *wss)
2556+
{
2557+
// get last transaction
2558+
htp_tx_t *h1tx = HtpGetTxForH2(alstate_orig);
2559+
if (wss == NULL || h1tx == NULL) {
2560+
return;
2561+
}
2562+
const htp_header_t *h = htp_tx_response_header(h1tx, "Sec-WebSocket-Extensions");
2563+
if (h == NULL) {
2564+
return;
2565+
}
2566+
SCWebSocketUseExtension(wss, htp_header_value_ptr(h), (uint32_t)htp_header_value_len(h));
2567+
}
2568+
25552569
static int HTPStateGetEventInfo(
25562570
const char *event_name, uint8_t *event_id, AppLayerEventType *event_type)
25572571
{

0 commit comments

Comments
 (0)