123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385 |
- use core::fmt;
- use byteorder::{ByteOrder, NetworkEndian};
- use crate::{Error, Result};
- enum_with_unknown! {
- /// Ethernet protocol type.
- pub enum EtherType(u16) {
- Ipv4 = 0x0800,
- Arp = 0x0806,
- Ipv6 = 0x86DD
- }
- }
- impl fmt::Display for EtherType {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- EtherType::Ipv4 => write!(f, "IPv4"),
- EtherType::Ipv6 => write!(f, "IPv6"),
- EtherType::Arp => write!(f, "ARP"),
- EtherType::Unknown(id) => write!(f, "0x{:04x}", id)
- }
- }
- }
- /// A six-octet Ethernet II address.
- #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
- pub struct Address(pub [u8; 6]);
- impl Address {
- /// The broadcast address.
- pub const BROADCAST: Address = Address([0xff; 6]);
- /// Construct an Ethernet address from a sequence of octets, in big-endian.
- ///
- /// # Panics
- /// The function panics if `data` is not six octets long.
- pub fn from_bytes(data: &[u8]) -> Address {
- let mut bytes = [0; 6];
- bytes.copy_from_slice(data);
- Address(bytes)
- }
- /// Return an Ethernet address as a sequence of octets, in big-endian.
- pub fn as_bytes(&self) -> &[u8] {
- &self.0
- }
- /// Query whether the address is an unicast address.
- pub fn is_unicast(&self) -> bool {
- !(self.is_broadcast() ||
- self.is_multicast())
- }
- /// Query whether this address is the broadcast address.
- pub fn is_broadcast(&self) -> bool {
- *self == Self::BROADCAST
- }
- /// Query whether the "multicast" bit in the OUI is set.
- pub fn is_multicast(&self) -> bool {
- self.0[0] & 0x01 != 0
- }
- /// Query whether the "locally administered" bit in the OUI is set.
- pub fn is_local(&self) -> bool {
- self.0[0] & 0x02 != 0
- }
- }
- impl fmt::Display for Address {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let bytes = self.0;
- write!(f, "{:02x}-{:02x}-{:02x}-{:02x}-{:02x}-{:02x}",
- bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5])
- }
- }
- /// A read/write wrapper around an Ethernet II frame buffer.
- #[derive(Debug, Clone)]
- pub struct Frame<T: AsRef<[u8]>> {
- buffer: T
- }
- mod field {
- use crate::wire::field::*;
- pub const DESTINATION: Field = 0..6;
- pub const SOURCE: Field = 6..12;
- pub const ETHERTYPE: Field = 12..14;
- pub const PAYLOAD: Rest = 14..;
- }
- /// The Ethernet header length
- pub const HEADER_LEN: usize = field::PAYLOAD.start;
- impl<T: AsRef<[u8]>> Frame<T> {
- /// Imbue a raw octet buffer with Ethernet frame structure.
- pub fn new_unchecked(buffer: T) -> Frame<T> {
- Frame { buffer }
- }
- /// Shorthand for a combination of [new_unchecked] and [check_len].
- ///
- /// [new_unchecked]: #method.new_unchecked
- /// [check_len]: #method.check_len
- pub fn new_checked(buffer: T) -> Result<Frame<T>> {
- let packet = Self::new_unchecked(buffer);
- packet.check_len()?;
- Ok(packet)
- }
- /// Ensure that no accessor method will panic if called.
- /// Returns `Err(Error::Truncated)` if the buffer is too short.
- pub fn check_len(&self) -> Result<()> {
- let len = self.buffer.as_ref().len();
- if len < HEADER_LEN {
- Err(Error::Truncated)
- } else {
- Ok(())
- }
- }
- /// Consumes the frame, returning the underlying buffer.
- pub fn into_inner(self) -> T {
- self.buffer
- }
- /// Return the length of a frame header.
- pub fn header_len() -> usize {
- HEADER_LEN
- }
- /// Return the length of a buffer required to hold a packet with the payload
- /// of a given length.
- pub fn buffer_len(payload_len: usize) -> usize {
- HEADER_LEN + payload_len
- }
- /// Return the destination address field.
- #[inline]
- pub fn dst_addr(&self) -> Address {
- let data = self.buffer.as_ref();
- Address::from_bytes(&data[field::DESTINATION])
- }
- /// Return the source address field.
- #[inline]
- pub fn src_addr(&self) -> Address {
- let data = self.buffer.as_ref();
- Address::from_bytes(&data[field::SOURCE])
- }
- /// Return the EtherType field, without checking for 802.1Q.
- #[inline]
- pub fn ethertype(&self) -> EtherType {
- let data = self.buffer.as_ref();
- let raw = NetworkEndian::read_u16(&data[field::ETHERTYPE]);
- EtherType::from(raw)
- }
- }
- impl<'a, T: AsRef<[u8]> + ?Sized> Frame<&'a T> {
- /// Return a pointer to the payload, without checking for 802.1Q.
- #[inline]
- pub fn payload(&self) -> &'a [u8] {
- let data = self.buffer.as_ref();
- &data[field::PAYLOAD]
- }
- }
- impl<T: AsRef<[u8]> + AsMut<[u8]>> Frame<T> {
- /// Set the destination address field.
- #[inline]
- pub fn set_dst_addr(&mut self, value: Address) {
- let data = self.buffer.as_mut();
- data[field::DESTINATION].copy_from_slice(value.as_bytes())
- }
- /// Set the source address field.
- #[inline]
- pub fn set_src_addr(&mut self, value: Address) {
- let data = self.buffer.as_mut();
- data[field::SOURCE].copy_from_slice(value.as_bytes())
- }
- /// Set the EtherType field.
- #[inline]
- pub fn set_ethertype(&mut self, value: EtherType) {
- let data = self.buffer.as_mut();
- NetworkEndian::write_u16(&mut data[field::ETHERTYPE], value.into())
- }
- /// Return a mutable pointer to the payload.
- #[inline]
- pub fn payload_mut(&mut self) -> &mut [u8] {
- let data = self.buffer.as_mut();
- &mut data[field::PAYLOAD]
- }
- }
- impl<T: AsRef<[u8]>> AsRef<[u8]> for Frame<T> {
- fn as_ref(&self) -> &[u8] {
- self.buffer.as_ref()
- }
- }
- impl<T: AsRef<[u8]>> fmt::Display for Frame<T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "EthernetII src={} dst={} type={}",
- self.src_addr(), self.dst_addr(), self.ethertype())
- }
- }
- use crate::wire::pretty_print::{PrettyPrint, PrettyIndent};
- impl<T: AsRef<[u8]>> PrettyPrint for Frame<T> {
- fn pretty_print(buffer: &dyn AsRef<[u8]>, f: &mut fmt::Formatter,
- indent: &mut PrettyIndent) -> fmt::Result {
- let frame = match Frame::new_checked(buffer) {
- Err(err) => return write!(f, "{}({})", indent, err),
- Ok(frame) => frame
- };
- write!(f, "{}{}", indent, frame)?;
- match frame.ethertype() {
- #[cfg(feature = "proto-ipv4")]
- EtherType::Arp => {
- indent.increase(f)?;
- super::ArpPacket::<&[u8]>::pretty_print(&frame.payload(), f, indent)
- }
- #[cfg(feature = "proto-ipv4")]
- EtherType::Ipv4 => {
- indent.increase(f)?;
- super::Ipv4Packet::<&[u8]>::pretty_print(&frame.payload(), f, indent)
- }
- #[cfg(feature = "proto-ipv6")]
- EtherType::Ipv6 => {
- indent.increase(f)?;
- super::Ipv6Packet::<&[u8]>::pretty_print(&frame.payload(), f, indent)
- }
- _ => Ok(())
- }
- }
- }
- /// A high-level representation of an Internet Protocol version 4 packet header.
- #[derive(Debug, PartialEq, Eq, Clone, Copy)]
- pub struct Repr {
- pub src_addr: Address,
- pub dst_addr: Address,
- pub ethertype: EtherType,
- }
- impl Repr {
- /// Parse an Ethernet II frame and return a high-level representation.
- pub fn parse<T: AsRef<[u8]> + ?Sized>(frame: &Frame<&T>) -> Result<Repr> {
- frame.check_len()?;
- Ok(Repr {
- src_addr: frame.src_addr(),
- dst_addr: frame.dst_addr(),
- ethertype: frame.ethertype(),
- })
- }
- /// Return the length of a header that will be emitted from this high-level representation.
- pub fn buffer_len(&self) -> usize {
- HEADER_LEN
- }
- /// Emit a high-level representation into an Ethernet II frame.
- pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, frame: &mut Frame<T>) {
- frame.set_src_addr(self.src_addr);
- frame.set_dst_addr(self.dst_addr);
- frame.set_ethertype(self.ethertype);
- }
- }
- #[cfg(test)]
- mod test {
- // Tests that are valid with any combination of
- // "proto-*" features.
- use super::*;
- #[test]
- fn test_broadcast() {
- assert!(Address::BROADCAST.is_broadcast());
- assert!(!Address::BROADCAST.is_unicast());
- assert!(Address::BROADCAST.is_multicast());
- assert!(Address::BROADCAST.is_local());
- }
- }
- #[cfg(test)]
- #[cfg(feature = "proto-ipv4")]
- mod test_ipv4 {
- // Tests that are valid only with "proto-ipv4"
- use super::*;
- static FRAME_BYTES: [u8; 64] =
- [0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
- 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
- 0x08, 0x00,
- 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xff];
- static PAYLOAD_BYTES: [u8; 50] =
- [0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xff];
- #[test]
- fn test_deconstruct() {
- let frame = Frame::new_unchecked(&FRAME_BYTES[..]);
- assert_eq!(frame.dst_addr(), Address([0x01, 0x02, 0x03, 0x04, 0x05, 0x06]));
- assert_eq!(frame.src_addr(), Address([0x11, 0x12, 0x13, 0x14, 0x15, 0x16]));
- assert_eq!(frame.ethertype(), EtherType::Ipv4);
- assert_eq!(frame.payload(), &PAYLOAD_BYTES[..]);
- }
- #[test]
- fn test_construct() {
- let mut bytes = vec![0xa5; 64];
- let mut frame = Frame::new_unchecked(&mut bytes);
- frame.set_dst_addr(Address([0x01, 0x02, 0x03, 0x04, 0x05, 0x06]));
- frame.set_src_addr(Address([0x11, 0x12, 0x13, 0x14, 0x15, 0x16]));
- frame.set_ethertype(EtherType::Ipv4);
- frame.payload_mut().copy_from_slice(&PAYLOAD_BYTES[..]);
- assert_eq!(&frame.into_inner()[..], &FRAME_BYTES[..]);
- }
- }
- #[cfg(test)]
- #[cfg(feature = "proto-ipv6")]
- mod test_ipv6 {
- // Tests that are valid only with "proto-ipv6"
- use super::*;
- static FRAME_BYTES: [u8; 54] =
- [0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
- 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
- 0x86, 0xdd,
- 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01];
- static PAYLOAD_BYTES: [u8; 40] =
- [0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01];
- #[test]
- fn test_deconstruct() {
- let frame = Frame::new_unchecked(&FRAME_BYTES[..]);
- assert_eq!(frame.dst_addr(), Address([0x01, 0x02, 0x03, 0x04, 0x05, 0x06]));
- assert_eq!(frame.src_addr(), Address([0x11, 0x12, 0x13, 0x14, 0x15, 0x16]));
- assert_eq!(frame.ethertype(), EtherType::Ipv6);
- assert_eq!(frame.payload(), &PAYLOAD_BYTES[..]);
- }
- #[test]
- fn test_construct() {
- let mut bytes = vec![0xa5; 54];
- let mut frame = Frame::new_unchecked(&mut bytes);
- frame.set_dst_addr(Address([0x01, 0x02, 0x03, 0x04, 0x05, 0x06]));
- frame.set_src_addr(Address([0x11, 0x12, 0x13, 0x14, 0x15, 0x16]));
- frame.set_ethertype(EtherType::Ipv6);
- assert_eq!(PAYLOAD_BYTES.len(), frame.payload_mut().len());
- frame.payload_mut().copy_from_slice(&PAYLOAD_BYTES[..]);
- assert_eq!(&frame.into_inner()[..], &FRAME_BYTES[..]);
- }
- }
|