//! What the readers and writers of the wire format share: the shape of a //! parser's result and its errors, the fields that several messages and //! attributes have in common, and the lengths that are written before what //! they count. use bytes::{BufMut, BytesMut}; use nom::Err::Failure; use nom::IResult; use nom::number::complete::{be_u8, be_u16, be_u32}; use bgp_primitives::constants::{Afi, AfiSafi, Safi}; use bgp_primitives::parser::{BgpParserError, EncodeError, ParserContext}; use crate::message::AS_TRANS; /// A parser's result: what is left of the input, and what was read. pub(crate) type Parsed<'a, T> = IResult<&'a [u8], T, BgpParserError<&'a [u8]>>; /// The error for input that does not follow the format; `detail` says how. pub(crate) fn malformed<'a>(detail: impl Into) -> nom::Err> { Failure(BgpParserError::Malformed(detail.into())) } /// Parses `buf` to its end as a list of `item`s. Unlike nom's `many0`, /// which stops quietly at an item it cannot read, an error in an item is an /// error of the list. pub(crate) fn list<'a, T>( mut buf: &'a [u8], item: impl Fn(&'a [u8]) -> Parsed<'a, T>, ) -> Parsed<'a, Vec> { let mut items = Vec::new(); while !buf.is_empty() { let (rest, parsed) = item(buf)?; items.push(parsed); buf = rest; } Ok((buf, items)) } /// A parsed value, provided the parser used all of the input. `what` names /// the input in the error. pub(crate) fn whole( what: impl std::fmt::Display, (rest, parsed): (&[u8], T), ) -> Result>> { if rest.is_empty() { Ok(parsed) } else { Err(malformed(format!( "{} octets left over in {what}", rest.len() ))) } } /// `value` as a list of one or more records of `N` octets each: how the /// community attributes and CLUSTER_LIST are laid out. An empty list is /// malformed (RFC 7606 §7.8 for COMMUNITIES, and the others alike). `what` /// names the attribute in the error. pub(crate) fn records<'a, const N: usize>( value: &'a [u8], what: &str, ) -> Result<&'a [[u8; N]], nom::Err>> { let (records, rest) = value.as_chunks::(); if records.is_empty() || !rest.is_empty() { return Err(malformed(format!( "{what} is {} octets long, not a non-empty multiple of {N}", value.len() ))); } Ok(records) } /// Parses an AS number as wide as the session's: four octets or two /// (RFC 6793). pub(crate) fn parse_asn(four_octet: bool, buf: &[u8]) -> Parsed<'_, u32> { if four_octet { be_u32(buf) } else { be_u16(buf).map(|(buf, asn)| (buf, u32::from(asn))) } } /// Writes an AS number as wide as the session's. On a two-octet session /// one that does not fit is written as AS_TRANS (RFC 6793 §4.2.2). pub(crate) fn put_asn(four_octet: bool, asn: u32, out: &mut BytesMut) { if four_octet { out.put_u32(asn); } else { out.put_u16(u16::try_from(asn).unwrap_or(AS_TRANS)); } } /// Whether the prefixes in the body of an UPDATE carry path identifiers /// on a session with `ctx`. The body holds IPv4 unicast routes and nothing /// else (RFC 4271 §4.3), so that is the family whose ADD-PATH agreement /// decides it; every other family's prefixes are in MP_REACH_NLRI and /// MP_UNREACH_NLRI, which name their family. pub(crate) fn body_has_path_id(ctx: &ParserContext) -> bool { ctx.has_add_path(AfiSafi::IPV4_UNICAST) } /// Parses an address family as the multiprotocol attributes and most /// capabilities name it: a two-octet AFI and a one-octet SAFI. pub(crate) fn parse_afi_safi(buf: &[u8]) -> Parsed<'_, AfiSafi> { let (buf, afi) = be_u16(buf)?; let (buf, safi) = be_u8(buf)?; Ok((buf, AfiSafi::new(Afi(afi), Safi(safi)))) } /// Writes an address family as [`parse_afi_safi`] reads it. pub(crate) fn put_afi_safi(family: AfiSafi, out: &mut BytesMut) { out.put_u16(family.afi.0); out.put_u8(family.safi.0); } /// Writes `length` into the field of `width` octets reserved at `at`, if /// it is no more than `max`. `what` names the field in the error. pub(crate) fn put_length( out: &mut BytesMut, at: usize, width: usize, length: usize, max: usize, what: &'static str, ) -> Result<(), EncodeError> { if length > max { return Err(EncodeError::TooLong { what, len: length, max, }); } let bytes = length.to_be_bytes(); out[at..at + width].copy_from_slice(&bytes[bytes.len() - width..]); Ok(()) } /// Fills in the field of `width` octets reserved at `at` with how much /// has been written after it, if that is no more than `max`: for a length /// that is known only once what it counts has been written. `what` names /// the field in the error. pub(crate) fn fill_length( out: &mut BytesMut, at: usize, width: usize, max: usize, what: &'static str, ) -> Result<(), EncodeError> { let length = out.len() - at - width; put_length(out, at, width, length, max, what) } #[cfg(test)] mod tests { use super::*; #[test] fn a_length_is_filled_in_after_what_it_counts() { let mut out = BytesMut::new(); out.put_u8(0xaa); let at = out.len(); out.put_u16(0); out.put_slice(&[1, 2, 3]); fill_length(&mut out, at, 2, u16::MAX.into(), "field").unwrap(); assert_eq!(&out[..], [0xaa, 0, 3, 1, 2, 3]); let mut out = BytesMut::new(); out.put_u8(0); out.put_slice(&[0; 300]); assert_eq!( fill_length(&mut out, 0, 1, u8::MAX.into(), "field"), Err(EncodeError::TooLong { what: "field", len: 300, max: 255, }) ); } #[test] fn records_are_a_whole_number_of_them_and_at_least_one() { assert_eq!( records::<4>(&[1, 2, 3, 4, 5, 6, 7, 8], "X").unwrap().len(), 2 ); for value in [&[][..], &[1, 2, 3][..], &[1, 2, 3, 4, 5][..]] { let error = records::<4>(value, "X").unwrap_err(); assert_eq!( crate::message::describe(&error), format!( "X is {} octets long, not a non-empty multiple of 4", value.len() ) ); } } }