// SPDX-License-Identifier: MIT use anyhow::Context; use netlink_packet_utils::{ traits::{Parseable, ParseableParametrized}, DecodeError, }; use crate::{constants::*, inet, unix, SockDiagMessage}; const BUF_MIN_LEN: usize = 2; pub struct SockDiagBuffer { buffer: T, } impl> SockDiagBuffer { pub fn new(buffer: T) -> SockDiagBuffer { SockDiagBuffer { buffer } } pub fn length(&self) -> usize { self.buffer.as_ref().len() } pub fn new_checked(buffer: T) -> Result { let packet = Self::new(buffer); packet.check_len()?; Ok(packet) } pub(crate) fn check_len(&self) -> Result<(), DecodeError> { let len = self.buffer.as_ref().len(); if len < BUF_MIN_LEN { return Err(format!( "invalid buffer: length is {len} but packets are at least {BUF_MIN_LEN} bytes" ) .into()); } Ok(()) } pub(crate) fn family(&self) -> u8 { self.buffer.as_ref()[0] } } impl<'a, T: AsRef<[u8]> + ?Sized> SockDiagBuffer<&'a T> { pub fn inner(&self) -> &'a [u8] { self.buffer.as_ref() } } impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> SockDiagBuffer<&'a mut T> { pub fn inner_mut(&mut self) -> &mut [u8] { self.buffer.as_mut() } } impl<'a, T: AsRef<[u8]>> ParseableParametrized, u16> for SockDiagMessage { fn parse_with_param( buf: &SockDiagBuffer<&'a T>, message_type: u16, ) -> Result { use self::SockDiagMessage::*; buf.check_len()?; let message = match (message_type, buf.family()) { (SOCK_DIAG_BY_FAMILY, AF_INET) => { let err = "invalid AF_INET response"; let buf = inet::InetResponseBuffer::new_checked(buf.inner()) .context(err)?; InetResponse(Box::new( inet::InetResponse::parse(&buf).context(err)?, )) } (SOCK_DIAG_BY_FAMILY, AF_INET6) => { let err = "invalid AF_INET6 response"; let buf = inet::InetResponseBuffer::new_checked(buf.inner()) .context(err)?; InetResponse(Box::new( inet::InetResponse::parse(&buf).context(err)?, )) } (SOCK_DIAG_BY_FAMILY, AF_UNIX) => { let err = "invalid AF_UNIX response"; let buf = unix::UnixResponseBuffer::new_checked(buf.inner()) .context(err)?; UnixResponse(Box::new( unix::UnixResponse::parse(&buf).context(err)?, )) } (SOCK_DIAG_BY_FAMILY, af) => { return Err(format!("unknown address family {af}").into()) } _ => { return Err( format!("unknown message type {message_type}").into() ) } }; Ok(message) } }