From ed7945948ed9effdc26b31edfe27799a9f6abc0d Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Tue, 9 Sep 2014 20:02:03 -0400 Subject: limit messages to 512 bytes still need to avoid actually reading in bytes past 512 in an incoming message --- src/client.rs | 3 +++ src/constants.rs | 2 +- src/message.rs | 37 +++++++++++++++++++++++++------------ 3 files changed, 29 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/client.rs b/src/client.rs index 3903fb7..c8f0d7b 100644 --- a/src/client.rs +++ b/src/client.rs @@ -142,6 +142,9 @@ impl Client { // \n isn't valid inside a message, so this should be fine. if the \n // we find isn't preceded by a \r, this will be caught by the message // parser. + // XXX we should only be reading 512 bytes here, and throwing an error + // otherwise - or else we could end up reading an unbounded amount of + // data into memory let buf = match self.conn().read_until(b'\n') { Ok(b) => b, Err(e) => return Err(IoError(e)), diff --git a/src/constants.rs b/src/constants.rs index ff5e399..b8b905e 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -337,7 +337,7 @@ pub static ERR_NOSERVICEHOST: u16 = 492; pub static RPL_TOPICDATE: u16 = 333; // date the topic was set, in seconds since the epoch pub static ERR_MSGFORBIDDEN: u16 = 505; // freenode blocking privmsg from unreged users -pub static MAX_MESSAGE_LENGTH: i32 = 512; +pub static MAX_MESSAGE_LENGTH: uint = 512; #[test] fn test_message_type () { diff --git a/src/message.rs b/src/message.rs index 5c1c76c..2115552 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,4 +1,4 @@ -use constants::MessageType; +use constants::{MessageType, MAX_MESSAGE_LENGTH}; use std::io; @@ -15,6 +15,10 @@ impl Message { } pub fn parse (msg: &str) -> Result { + if msg.len() > MAX_MESSAGE_LENGTH { + return Err("message too long"); + } + let message_parser = regex!(r"^(?::([^ ]+) )?([A-Z]+|[0-9]{3}) ([^\r\n\0]*)\r\n$"); match message_parser.captures(msg) { Some(captures) => { @@ -50,23 +54,32 @@ impl Message { } pub fn write_protocol_string (&self, w: &mut W) -> io::IoResult<()> { - match self.from { - Some(ref f) => { try!(write!(w, ":{} ", f)) }, - None => {}, - } + let mut buf = [0u8, ..MAX_MESSAGE_LENGTH]; - try!(write!(w, "{}", self.message_type)); + { + let mut bufw = io::BufWriter::new(buf); - for param in self.params.iter() { - if param.as_slice().contains_char(' ') { - try!(write!(w, " :{}", param)); + match self.from { + Some(ref f) => { try!(write!(bufw, ":{} ", f)) }, + None => {}, } - else { - try!(write!(w, " {}", param)); + + try!(write!(bufw, "{}", self.message_type)); + + for param in self.params.iter() { + if param.as_slice().contains_char(' ') { + try!(write!(bufw, " :{}", param)); + } + else { + try!(write!(bufw, " {}", param)); + } } + + try!(write!(bufw, "\r\n")); } - try!(write!(w, "\r\n")); + let len = buf.iter().position(|&c| c == 0).unwrap_or(MAX_MESSAGE_LENGTH); + try!(w.write(buf.slice(0, len))); try!(w.flush()); Ok(()) -- cgit v1.2.3