use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt};
use std::io::Cursor;
type ByteOrder = BigEndian;
pub struct ICMP<'a> {
inner: &'a mut [u8],
}
impl<'a> ICMP<'a> {
pub fn typ(&self) -> u8 {
self.read_u8(0)
}
pub fn write_typ(&mut self, typ: u8) {
Cursor::new(&mut self.inner[..]).write_u8(typ).unwrap();
}
pub fn echo(&'a mut self) -> Echo<'_> {
Echo { raw: self }
}
pub fn echo_reply(&self) -> EchoReply<'_> {
EchoReply { raw: self }
}
}
pub struct Echo<'a> {
raw: &'a mut ICMP<'a>,
}
impl<'a> Echo<'a> {
pub fn typ(&self) -> u8 {
self.raw.typ()
}
pub fn identifier(&self) -> u16 {
self.raw.read_u16(4)
}
pub fn seq_num(&self) -> u16 {
self.raw.read_u16(6)
}
pub fn data(&self) -> &[u8] {
&self.raw.inner[8..]
}
pub fn checksum(&self) -> u16 {
self.raw.read_u16(2)
}
pub fn write_checksum(&mut self, val: u16) {
Cursor::new(&mut self.raw.inner[2..]).write_u16::<ByteOrder>(val).unwrap();
}
pub fn cal_checksum(&self) -> u16 {
let mut sum = 0u32;
let mut idx = 0;
for word in self.raw.inner.chunks(2) {
let part = match idx == 1 {
true => 0,
false => {
let mut part = u16::from(word[0]) << 8;
if word.len() > 1 {
part += u16::from(word[1]);
}
part
}
};
idx += 1;
sum = sum.wrapping_add(u32::from(part));
}
while (sum >> 16) > 0 {
sum = (sum & 0xffff) + (sum >> 16);
}
let sum = !sum as u16;
sum
}
}
pub struct EchoReply<'a> {
raw: &'a ICMP<'a>,
}
impl<'a> EchoReply<'a> {
pub fn identifier(&self) -> u16 {
self.raw.read_u16(4)
}
pub fn seq_num(&self) -> u16 {
self.raw.read_u16(6)
}
}
impl<'a> ICMP<'a> {
fn read_u16(&self, off: usize) -> u16 {
self.cursor(off).read_u16::<ByteOrder>().unwrap() as _
}
fn read_u8(&self, off: usize) -> u8 {
self.cursor(off).read_u8().unwrap()
}
fn cursor(&self, off: usize) -> Cursor<&[u8]> {
Cursor::new(&self.inner[off..])
}
}
pub fn from(buf: &mut [u8]) -> ICMP<'_> {
println!("buf({}): {:?}", buf.len(), buf);
ICMP { inner: buf }
}