From 74d4a89ae81a6bf1cfbb0da73777e26064a1b8f3 Mon Sep 17 00:00:00 2001 From: Heinz Gies Date: Tue, 10 Sep 2019 13:15:42 +0200 Subject: [PATCH] Fix RSV bit to be autobahn compliant --- actix-http/src/ws/codec.rs | 11 ++++++++++- actix-http/src/ws/frame.rs | 38 ++++++++++++++++++++++++++++---------- actix-http/src/ws/mod.rs | 3 +++ 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/actix-http/src/ws/codec.rs b/actix-http/src/ws/codec.rs index f21e6ff1d..99edfd773 100644 --- a/actix-http/src/ws/codec.rs +++ b/actix-http/src/ws/codec.rs @@ -101,12 +101,21 @@ impl Decoder for Codec { fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { match Parser::parse(src, self.server, self.max_size) { - Ok(Some((finished, opcode, payload))) => { + Ok(Some((finished, rsv, opcode, payload))) => { // continuation is not supported if !finished { return Err(ProtocolError::NoContinuation); } + // Since this is the default codec we have no extension + // and should fail if rsv is set. + // In an async context this will cause a NON-STRICT + // autoban complience since we might terminate + // before receiving the prior message. + if rsv != 0 { + return Err(ProtocolError::RSVSet); + } + match opcode { OpCode::Continue => Err(ProtocolError::NoContinuation), OpCode::Bad => Err(ProtocolError::BadOpCode), diff --git a/actix-http/src/ws/frame.rs b/actix-http/src/ws/frame.rs index 46e9f36db..a461847e6 100644 --- a/actix-http/src/ws/frame.rs +++ b/actix-http/src/ws/frame.rs @@ -17,7 +17,8 @@ impl Parser { src: &[u8], server: bool, max_size: usize, - ) -> Result)>, ProtocolError> { + ) -> Result)>, ProtocolError> + { let chunk_len = src.len(); let mut idx = 2; @@ -28,6 +29,7 @@ impl Parser { let first = src[0]; let second = src[1]; let finished = first & 0x80 != 0; + let rsv: u8 = first & 0x70 >> 4; // check masking let masked = second & 0x80 != 0; @@ -86,7 +88,7 @@ impl Parser { None }; - Ok(Some((idx, finished, opcode, length, mask))) + Ok(Some((idx, finished, rsv, opcode, length, mask))) } /// Parse the input stream into a frame. @@ -94,9 +96,9 @@ impl Parser { src: &mut BytesMut, server: bool, max_size: usize, - ) -> Result)>, ProtocolError> { + ) -> Result)>, ProtocolError> { // try to parse ws frame metadata - let (idx, finished, opcode, length, mask) = + let (idx, finished, rsv, opcode, length, mask) = match Parser::parse_metadata(src, server, max_size)? { None => return Ok(None), Some(res) => res, @@ -112,7 +114,7 @@ impl Parser { // no need for body if length == 0 { - return Ok(Some((finished, opcode, None))); + return Ok(Some((finished, rsv, opcode, None))); } let mut data = src.split_to(length); @@ -124,7 +126,7 @@ impl Parser { } OpCode::Close if length > 125 => { debug!("Received close frame with payload length exceeding 125. Morphing to protocol close frame."); - return Ok(Some((true, OpCode::Close, None))); + return Ok(Some((true, rsv, OpCode::Close, None))); } _ => (), } @@ -134,7 +136,7 @@ impl Parser { apply_mask(&mut data, mask); } - Ok(Some((finished, opcode, Some(data)))) + Ok(Some((finished, rsv, opcode, Some(data)))) } /// Parse the payload of a close frame. @@ -223,12 +225,13 @@ mod tests { struct F { finished: bool, + rsv: u8, opcode: OpCode, payload: Bytes, } fn is_none( - frm: &Result)>, ProtocolError>, + frm: &Result)>, ProtocolError>, ) -> bool { match *frm { Ok(None) => true, @@ -237,11 +240,12 @@ mod tests { } fn extract( - frm: Result)>, ProtocolError>, + frm: Result)>, ProtocolError>, ) -> F { match frm { - Ok(Some((finished, opcode, payload))) => F { + Ok(Some((finished, rsv, opcode, payload))) => F { finished, + rsv, opcode, payload: payload .map(|b| b.freeze()) @@ -344,6 +348,20 @@ mod tests { } } + #[test] + fn test_parse_rsv() { + let mut buf = BytesMut::from(&[0b0111_0001u8, 0b0000_0001u8][..]); + buf.extend(&[1u8]); + + assert!(Parser::parse(&mut buf, true, 1024).is_err()); + + let frame = extract(Parser::parse(&mut buf, false, 1024)); + assert!(!frame.finished); + assert_eq!(frame.rsv, 7); + assert_eq!(frame.opcode, OpCode::Text); + assert_eq!(frame.payload, Bytes::from(vec![1u8])); + } + #[test] fn test_ping_frame() { let mut buf = BytesMut::new(); diff --git a/actix-http/src/ws/mod.rs b/actix-http/src/ws/mod.rs index 891d5110d..5f9d654f9 100644 --- a/actix-http/src/ws/mod.rs +++ b/actix-http/src/ws/mod.rs @@ -50,6 +50,9 @@ pub enum ProtocolError { /// Bad utf-8 encoding #[display(fmt = "Bad utf-8 encoding.")] BadEncoding, + /// Continuation is not supported + #[display(fmt = "RSV set without extensions.")] + RSVSet, /// Io error #[display(fmt = "io error: {}", _0)] Io(io::Error),