use crate::common::to_hex;
use core::fmt;
-use nom::number::streaming::{be_u16, be_u32, be_u64, be_u8};
-use nom::*;
+use nom7::bytes::streaming::take;
+use nom7::combinator::{complete, cond, map};
+use nom7::multi::many0;
+use nom7::number::streaming::{be_u16, be_u32, be_u64, be_u8};
+use nom7::{Err, IResult};
use std::collections::HashSet;
// Generic ISAKMP "Container" structs
pub hex_value: Option<String>,
}
-named! {pub parse_isakmp_header<IsakmpHeader>,
- do_parse!(
- init_spi: be_u64 >>
- resp_spi: be_u64 >>
- np: be_u8 >>
- vers: bits!(
- tuple!(take_bits!(4u8),take_bits!(4u8))
- ) >>
- ex: be_u8 >>
- flags: be_u8 >>
- id: be_u32 >>
- l: be_u32 >>
- (
- IsakmpHeader {
- init_spi,
- resp_spi,
- next_payload: np,
- maj_ver: vers.0,
- min_ver: vers.1,
- exch_type: ex,
- flags,
- msg_id: id,
- length: l,
- }
- )
- )
+pub fn parse_isakmp_header(i: &[u8]) -> IResult<&[u8], IsakmpHeader> {
+ let (i, init_spi) = be_u64(i)?;
+ let (i, resp_spi) = be_u64(i)?;
+ let (i, next_payload) = be_u8(i)?;
+ let (i, vers_byte) = be_u8(i)?;
+ let vers = (vers_byte >> 4, vers_byte & 0b1111);
+ let (i, exch_type) = be_u8(i)?;
+ let (i, flags) = be_u8(i)?;
+ let (i, msg_id) = be_u32(i)?;
+ let (i, length) = be_u32(i)?;
+ let hdr =
+ IsakmpHeader {
+ init_spi,
+ resp_spi,
+ next_payload,
+ maj_ver: vers.0,
+ min_ver: vers.1,
+ exch_type,
+ flags,
+ msg_id,
+ length,
+ };
+ Ok((i, hdr))
}
pub fn parse_security_association(i: &[u8]) -> IResult<&[u8], SecurityAssociationPayload> {
- do_parse!(
- i,
- domain_of_interpretation: be_u32
- >> situation: cond!(domain_of_interpretation == 1, take!(4))
- >> data: cond!(
- domain_of_interpretation == 1 && i.len() >= 8,
- take!(i.len() - 8)
- )
- >> (SecurityAssociationPayload {
- domain_of_interpretation,
- situation,
- data
- })
- )
+ let start_i = i;
+ let (i, domain_of_interpretation) = be_u32(i)?;
+ let (i, situation) = cond(domain_of_interpretation == 1, take(4_usize))(i)?;
+ let (i, data) = cond(
+ domain_of_interpretation == 1 && start_i.len() >= 8,
+ |b| take(start_i.len() - 8)(b)
+ )(i)?;
+ Ok((i, SecurityAssociationPayload {
+ domain_of_interpretation,
+ situation,
+ data
+ }))
}
pub fn parse_key_exchange(i: &[u8], length: u16) -> IResult<&[u8], KeyExchangePayload> {
- do_parse!(
- i,
- key_exchange_data: take!(length) >> (KeyExchangePayload { key_exchange_data })
- )
+ let (i, key_exchange_data) = take(length as usize)(i)?;
+ Ok((i, KeyExchangePayload { key_exchange_data }))
}
pub fn parse_proposal(i: &[u8]) -> IResult<&[u8], ProposalPayload> {
- do_parse!(
- i,
- proposal_number: be_u8
- >> proposal_type: be_u8
- >> spi_size: be_u8
- >> number_transforms: be_u8
- >> spi: take!(spi_size)
- >> payload_data:
- cond!(
- (i.len() as i16 - 4) - spi_size as i16 >= 0,
- take!((i.len() as u16 - 4) - spi_size as u16)
- )
- >> (ProposalPayload {
- proposal_number,
- proposal_type,
- spi_size,
- number_transforms,
- spi,
- data: if let Some(_data) = payload_data {
- _data
- } else {
- b""
- }
- })
- )
+ let start_i = i;
+ let (i, proposal_number) = be_u8(i)?;
+ let (i, proposal_type) = be_u8(i)?;
+ let (i, spi_size) = be_u8(i)?;
+ let (i, number_transforms) = be_u8(i)?;
+ let (i, spi) = take(spi_size as usize)(i)?;
+ let (i, payload_data) = cond(
+ (start_i.len() as i16 - 4) - spi_size as i16 >= 0,
+ |b| take((start_i.len() - 4) - spi_size as usize)(b)
+ )(i)?;
+ let payload = ProposalPayload {
+ proposal_number,
+ proposal_type,
+ spi_size,
+ number_transforms,
+ spi,
+ data: payload_data.unwrap_or_default(),
+ };
+ Ok((i, payload))
}
pub fn parse_transform(i: &[u8], length: u16) -> IResult<&[u8], TransformPayload> {
- do_parse!(
- i,
- transform_number: be_u8
- >> transform_type: be_u8
- >> be_u16
- >> payload_data: cond!(length >= 4, take!(length - 4))
- >> (TransformPayload {
- transform_number,
- transform_type,
- sa_attributes: if let Some(_data) = payload_data {
- _data
- } else {
- b""
- }
- })
- )
+ let (i, transform_number) = be_u8(i)?;
+ let (i, transform_type) = be_u8(i)?;
+ let (i, _) = be_u16(i)?;
+ let (i, payload_data) = cond(length >= 4, |b| take(length - 4)(b))(i)?;
+ Ok((i, TransformPayload {
+ transform_number,
+ transform_type,
+ sa_attributes: payload_data.unwrap_or_default(),
+ }))
}
pub fn parse_vendor_id(i: &[u8], length: u16) -> IResult<&[u8], VendorPayload> {
- map!(i, take!(length), |v| VendorPayload { vendor_id: v })
+ map(take(length), |v| VendorPayload { vendor_id: v })(i)
}
fn get_attribute_type(v: u16) -> AttributeType {
}
}
-named! { pub parse_sa_attribute<&[u8], Vec<SaAttribute>>,
- many0!(
- complete!(
- do_parse!(
- format: bits!(tuple!(take_bits!(1u8),take_bits!(15u16))) >>
- attribute_length_or_value: be_u16 >> // depends on format bit: 1 -> value | 0 -> number of following bytes
- numeric_variable_value: cond!(format.0 == 0 && attribute_length_or_value == 4, be_u32) >> // interpret as number
- variable_attribute_value: cond!(format.0 == 0 && attribute_length_or_value != 4, take!(attribute_length_or_value)) >>
- (
- SaAttribute {
- attribute_format: format.0,
- attribute_type: get_attribute_type(format.1),
- attribute_value : match format.1 {
- 1 => get_encryption_algorithm(attribute_length_or_value),
- 2 => get_hash_algorithm(attribute_length_or_value),
- 3 => get_authentication_method(attribute_length_or_value),
- 4 => get_group_description(attribute_length_or_value),
- 11 => match attribute_length_or_value {
- 1 => AttributeValue::LifeTypeSeconds,
- 2 => AttributeValue::LifeTypeKilobytes,
- _ => AttributeValue::Unknown
- }
- _ => AttributeValue::Unknown
- },
- numeric_value: match format.0 {
- 1 => Some(attribute_length_or_value as u32),
- 0 => {
- numeric_variable_value
- },
- _ => None,
- },
- hex_value: match format.0 {
- 0 => {
- variable_attribute_value.map(|_variable_attribute_value| to_hex(_variable_attribute_value))
- }
- _ => None,
- }
- }
- )
- )
- )
- )
+pub fn parse_sa_attribute(i: &[u8]) -> IResult<&[u8], Vec<SaAttribute>> {
+ fn parse_attribute(i: &[u8]) -> IResult<&[u8], SaAttribute> {
+ let (i, b) = be_u16(i)?;
+ let format = (
+ (b >> 15) as u8,
+ b & 0x7f_ff
+ );
+ let (i, attribute_length_or_value) = be_u16(i)?; // depends on format bit) = 1 -> value | 0 -> number of following bytes
+ let (i, numeric_variable_value) = cond(format.0 == 0 && attribute_length_or_value == 4, be_u32) (i)?; // interpret as number
+ let (i, variable_attribute_value) = cond(format.0 == 0 && attribute_length_or_value != 4, take(attribute_length_or_value))(i)?;
+ let attr = SaAttribute {
+ attribute_format: format.0,
+ attribute_type: get_attribute_type(format.1),
+ attribute_value : match format.1 {
+ 1 => get_encryption_algorithm(attribute_length_or_value),
+ 2 => get_hash_algorithm(attribute_length_or_value),
+ 3 => get_authentication_method(attribute_length_or_value),
+ 4 => get_group_description(attribute_length_or_value),
+ 11 => match attribute_length_or_value {
+ 1 => AttributeValue::LifeTypeSeconds,
+ 2 => AttributeValue::LifeTypeKilobytes,
+ _ => AttributeValue::Unknown
+ }
+ _ => AttributeValue::Unknown
+ },
+ numeric_value: match format.0 {
+ 1 => Some(attribute_length_or_value as u32),
+ 0 => {
+ numeric_variable_value
+ },
+ _ => None,
+ },
+ hex_value: match format.0 {
+ 0 => {
+ variable_attribute_value.map(|_variable_attribute_value| to_hex(_variable_attribute_value))
+ }
+ _ => None,
+ }
+ };
+ Ok((i, attr))
+ }
+ many0(complete(parse_attribute))(i)
}
pub fn parse_nonce(i: &[u8], length: u16) -> IResult<&[u8], NoncePayload> {
- map!(i, take!(length), |v| NoncePayload { nonce_data: v })
-}
-
-named! { pub parse_ikev1_payload_list<&[u8], Vec<IsakmpPayload>>,
- many0!(
- complete!(
- do_parse!(
- next_payload: be_u8 >>
- reserved: be_u8 >>
- payload_length: be_u16 >>
- payload_data: cond!(payload_length >= 4, take!(payload_length - 4)) >>
- (
- IsakmpPayload {
- payload_header: IsakmpPayloadHeader {
- next_payload,
- reserved,
- payload_length
- },
- data: if let Some(_data) = payload_data { _data } else { b"" }
- }
- )
- )
- )
- )
+ map(take(length), |v| NoncePayload { nonce_data: v })(i)
+}
+
+pub fn parse_ikev1_payload_list(i: &[u8]) -> IResult<&[u8], Vec<IsakmpPayload>> {
+ fn parse_payload(i: &[u8]) -> IResult<&[u8], IsakmpPayload> {
+ let (i, next_payload) = be_u8(i)?;
+ let (i, reserved) = be_u8(i)?;
+ let (i, payload_length) = be_u16(i)?;
+ let (i, payload_data) = cond(payload_length >= 4, |b| take(payload_length - 4)(b))(i)?;
+ Ok((i, IsakmpPayload {
+ payload_header: IsakmpPayloadHeader {
+ next_payload,
+ reserved,
+ payload_length
+ },
+ data: payload_data.unwrap_or_default(),
+ }))
+ }
+ many0(complete(parse_payload))(i)
}
#[derive(FromPrimitive, Debug)]
}
Ok(())
}
- Err(nom::Err::Incomplete(_)) => {
+ Err(Err::Incomplete(_)) => {
SCLogDebug!("Incomplete data parsing payload list");
Err(())
}
}
}
}
- Err(nom::Err::Incomplete(_)) => {
+ Err(Err::Incomplete(_)) => {
SCLogDebug!("Incomplete data");
Err(())
}
cur_payload_type = isakmp_payload.payload_header.next_payload;
}
}
- Err(nom::Err::Incomplete(_)) => {
+ Err(Err::Incomplete(_)) => {
SCLogDebug!("Incomplete data parsing payload list");
return Err(());
}
}
Ok(())
}
- Err(nom::Err::Incomplete(_)) => {
+ Err(Err::Incomplete(_)) => {
SCLogDebug!("Incomplete data");
Err(())
}