1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
use std::array::TryFromSliceError; use std::convert::{TryFrom, TryInto}; use std::net::IpAddr; use anyhow::{anyhow, Result}; use rand::random; use crate::icmp::{icmp4, icmp6}; #[derive(Debug)] pub struct Probe { pub addr: IpAddr, pub id: u16, pub seq: u16, pub token: Token, } #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] pub struct Token([u8; 16]); impl Probe { pub fn new(addr: IpAddr, id: u16, seq: u16) -> Self { let token = Token(random()); Self { addr, id, seq, token } } pub fn encode<'a>(&self, buf: &'a mut [u8]) -> Result<&'a mut [u8]> { let (request, mut n) = match self.addr { IpAddr::V4(_) => (icmp4::ECHO_REQUEST, icmp4::HEADER_SIZE), IpAddr::V6(_) => (icmp6::ECHO_REQUEST, icmp6::HEADER_SIZE), }; n += self.token.0.len(); if buf.len() < n { return Err(anyhow!("short buffer")); } buf[0..2].copy_from_slice(&[request, 0]); buf[2..4].copy_from_slice(&0u16.to_be_bytes()); buf[4..6].copy_from_slice(&self.id.to_be_bytes()); buf[6..8].copy_from_slice(&self.seq.to_be_bytes()); buf[8..n].copy_from_slice(&self.token.0); Ok(&mut buf[0..n]) } } impl TryFrom<&[u8]> for Token { type Error = TryFromSliceError; fn try_from(buf: &[u8]) -> Result<Self, Self::Error> { Ok(Self(buf.try_into()?)) } }