diff --git a/rust/src/dhcp/parser.rs b/rust/src/dhcp/parser.rs index 0d0ee66375..ad42561625 100644 --- a/rust/src/dhcp/parser.rs +++ b/rust/src/dhcp/parser.rs @@ -81,6 +81,7 @@ pub struct DHCPOption { pub code: u8, pub data: Option>, pub option: DHCPOptionWrapper, + pub malformed: bool, } pub fn parse_header(i: &[u8]) -> IResult<&[u8], DHCPHeader> { @@ -135,13 +136,19 @@ pub fn parse_clientid_option(i: &[u8]) -> IResult<&[u8], DHCPOption> { htype: 1, data: data.to_vec(), }), + malformed: false, }, )) } -pub fn parse_address_time_option(i: &[u8]) -> IResult<&[u8], DHCPOption> { - let (i, code) = be_u8(i)?; - let (i, _len) = be_u8(i)?; +pub fn parse_address_time_option(i0: &[u8]) -> IResult<&[u8], DHCPOption> { + let (i, code) = be_u8(i0)?; + let (i, len) = be_u8(i)?; + if len != 4 { + let (i, mut opt) = parse_generic_option(i0)?; + opt.malformed = true; + return Ok((i, opt)); + } let (i, seconds) = be_u32(i)?; Ok(( i, @@ -149,6 +156,7 @@ pub fn parse_address_time_option(i: &[u8]) -> IResult<&[u8], DHCPOption> { code, data: None, option: DHCPOptionWrapper::TimeValue(DHCPOptTimeValue { seconds }), + malformed: false, }, )) } @@ -165,6 +173,7 @@ pub fn parse_generic_option(i: &[u8]) -> IResult<&[u8], DHCPOption> { option: DHCPOptionWrapper::Generic(DHCPOptGeneric { data: data.to_vec(), }), + malformed: false, }, )) } @@ -180,6 +189,7 @@ pub fn parse_option(i: &[u8]) -> IResult<&[u8], DHCPOption> { code: opt, data: None, option: DHCPOptionWrapper::Pad, + malformed: false, }, )), DHCP_OPT_END => { @@ -193,6 +203,7 @@ pub fn parse_option(i: &[u8]) -> IResult<&[u8], DHCPOption> { code, data: Some(data.to_vec()), option: DHCPOptionWrapper::End, + malformed: false, }, )) } @@ -217,11 +228,14 @@ fn find_overload_value(options: &[DHCPOption]) -> u8 { 0 } -fn parse_overloaded_field(field: &[u8], options: &mut Vec) { +fn parse_overloaded_field( + field: &[u8], options: &mut Vec, malformed_options: &mut bool, +) { let mut next = field; while !next.is_empty() { match parse_option(next) { Ok((rem, option)) => { + *malformed_options |= option.malformed; let done = option.code == DHCP_OPT_END; options.push(option); next = rem; @@ -239,11 +253,12 @@ pub fn parse_dhcp(input: &[u8]) -> IResult<&[u8], DHCPMessage> { Ok((rem, header)) => { let mut options = Vec::new(); let mut next = rem; - let malformed_options = false; + let mut malformed_options = false; let mut truncated_options = false; loop { match parse_option(next) { Ok((rem, option)) => { + malformed_options |= option.malformed; let done = option.code == DHCP_OPT_END; options.push(option); next = rem; @@ -259,10 +274,10 @@ pub fn parse_dhcp(input: &[u8]) -> IResult<&[u8], DHCPMessage> { } let overload = find_overload_value(&options); if overload & 0x01 != 0 { - parse_overloaded_field(&header.bootfilename, &mut options); + parse_overloaded_field(&header.bootfilename, &mut options, &mut malformed_options); } if overload & 0x02 != 0 { - parse_overloaded_field(&header.servername, &mut options); + parse_overloaded_field(&header.servername, &mut options, &mut malformed_options); } let message = DHCPMessage {