libtun 0.1.0

a cross-platform(macosx, linux) tunnel library
Documentation
use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt};
use std::io::Cursor;
type ByteOrder = BigEndian;

/// https://tools.ietf.org/html/rfc792
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 }
}