Factor out pretty-printing of packets.
This commit is contained in:
parent
e7d6237279
commit
2a438b6e8d
|
@ -2,32 +2,14 @@ extern crate smoltcp;
|
|||
|
||||
use std::env;
|
||||
use smoltcp::phy::{Device, RawSocket};
|
||||
use smoltcp::wire::{EthernetFrame, EthernetProtocolType, ArpPacket};
|
||||
|
||||
fn print_frame(buffer: &[u8]) -> Result<(), ()> {
|
||||
let frame = try!(EthernetFrame::new(&buffer[..]));
|
||||
println!("{}", frame);
|
||||
|
||||
match frame.ethertype() {
|
||||
EthernetProtocolType::Arp => {
|
||||
let packet = try!(ArpPacket::new(frame.payload()));
|
||||
println!("| {}", packet);
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
use smoltcp::wire::{PrettyPrinter, EthernetFrame};
|
||||
|
||||
fn main() {
|
||||
let ifname = env::args().nth(1).unwrap();
|
||||
let mut socket = RawSocket::new(ifname.as_ref()).unwrap();
|
||||
loop {
|
||||
socket.recv(|buffer| {
|
||||
match print_frame(buffer) {
|
||||
Ok(()) => (),
|
||||
Err(()) => println!("buffer too small")
|
||||
}
|
||||
print!("{}", PrettyPrinter::<EthernetFrame<_>>::new("", &buffer))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -210,24 +210,6 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]>> fmt::Display for Packet<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match Repr::parse(self) {
|
||||
Ok(repr) => write!(f, "{}", repr),
|
||||
_ => {
|
||||
try!(write!(f, "ARP htype={:?} ptype={:?} hlen={:?} plen={:?} op={:?}",
|
||||
self.hardware_type(), self.protocol_type(),
|
||||
self.hardware_length(), self.protocol_length(),
|
||||
self.operation()));
|
||||
try!(write!(f, " sha={:?} spa={:?} tha={:?} tpa={:?}",
|
||||
self.source_hardware_addr(), self.source_protocol_addr(),
|
||||
self.target_hardware_addr(), self.target_protocol_addr()));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use super::{EthernetAddress, Ipv4Address};
|
||||
|
||||
/// A high-level representation of an Address Resolution Protocol packet.
|
||||
|
@ -291,6 +273,24 @@ impl Repr {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]>> fmt::Display for Packet<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match Repr::parse(self) {
|
||||
Ok(repr) => write!(f, "{}", repr),
|
||||
_ => {
|
||||
try!(write!(f, "ARP htype={:?} ptype={:?} hlen={:?} plen={:?} op={:?}",
|
||||
self.hardware_type(), self.protocol_type(),
|
||||
self.hardware_length(), self.protocol_length(),
|
||||
self.operation()));
|
||||
try!(write!(f, " sha={:?} spa={:?} tha={:?} tpa={:?}",
|
||||
self.source_hardware_addr(), self.source_protocol_addr(),
|
||||
self.target_hardware_addr(), self.target_protocol_addr()));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Repr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
|
@ -309,6 +309,18 @@ impl fmt::Display for Repr {
|
|||
}
|
||||
}
|
||||
|
||||
use super::pretty_print::{PrettyPrint, PrettyIndent};
|
||||
|
||||
impl<T: AsRef<[u8]>> PrettyPrint<T> for Packet<T> {
|
||||
fn pretty_print(buffer: T, f: &mut fmt::Formatter,
|
||||
indent: &mut PrettyIndent) -> fmt::Result {
|
||||
match Packet::new(buffer) {
|
||||
Err(()) => write!(f, "{}(truncated)\n", indent),
|
||||
Ok(frame) => write!(f, "{}{}\n", indent, frame)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
|
@ -147,6 +147,26 @@ impl<T: AsRef<[u8]>> fmt::Display for Frame<T> {
|
|||
}
|
||||
}
|
||||
|
||||
use super::pretty_print::{PrettyPrint, PrettyIndent};
|
||||
|
||||
impl<T: AsRef<[u8]>> PrettyPrint<T> for Frame<T> {
|
||||
fn pretty_print(buffer: T, f: &mut fmt::Formatter,
|
||||
indent: &mut PrettyIndent) -> fmt::Result {
|
||||
let frame = match Frame::new(buffer) {
|
||||
Err(()) => return write!(f, "{}(truncated)\n", indent),
|
||||
Ok(frame) => frame
|
||||
};
|
||||
try!(write!(f, "{}{}\n", indent, frame));
|
||||
indent.increase();
|
||||
|
||||
match frame.ethertype() {
|
||||
EtherType::Arp =>
|
||||
super::ArpPacket::pretty_print(frame.payload(), f, indent),
|
||||
_ => Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
|
@ -55,10 +55,14 @@ mod field {
|
|||
pub type FieldFrom = ::core::ops::RangeFrom<usize>;
|
||||
}
|
||||
|
||||
pub mod pretty_print;
|
||||
|
||||
mod ethernet;
|
||||
mod arp;
|
||||
mod ipv4;
|
||||
|
||||
pub use self::pretty_print::PrettyPrinter;
|
||||
|
||||
pub use self::ethernet::EtherType as EthernetProtocolType;
|
||||
pub use self::ethernet::Address as EthernetAddress;
|
||||
pub use self::ethernet::Frame as EthernetFrame;
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
//! Pretty-printing of packet representation.
|
||||
//!
|
||||
//! The `pretty_print` module provides bits and pieces for printing concise,
|
||||
//! easily human readable packet listings.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! A packet can be formatted using the `PrettyPrinter` wrapper:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! print!("{}", PrettyPrinter::<EthernetFrame<_>>::new("", &buffer))
|
||||
//! ```
|
||||
|
||||
use core::fmt;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
/// Indentation state.
|
||||
#[derive(Debug)]
|
||||
pub struct PrettyIndent {
|
||||
prefix: &'static str,
|
||||
level: usize
|
||||
}
|
||||
|
||||
impl PrettyIndent {
|
||||
/// Create an indentation state. The entire listing will be indented by the width
|
||||
/// of `prefix`, and `prefix` will appear at the start of the first line.
|
||||
pub fn new(prefix: &'static str) -> PrettyIndent {
|
||||
PrettyIndent { prefix: prefix, level: 0 }
|
||||
}
|
||||
|
||||
/// Increase indentation level.
|
||||
pub fn increase(&mut self) {
|
||||
self.level += 1
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for PrettyIndent {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.level == 0 {
|
||||
write!(f, "{}", self.prefix)
|
||||
} else {
|
||||
write!(f, "{0:1$}{0:2$}| ", "", self.prefix.len(), (self.level - 1) * 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface for printing listings.
|
||||
pub trait PrettyPrint<T: AsRef<[u8]>> {
|
||||
/// Write a concise, formatted representation of a packet contained in the provided
|
||||
/// buffer, and any nested packets it may contain.
|
||||
///
|
||||
/// `pretty_print` accepts a buffer and not a packet wrapper because the packet might
|
||||
/// be truncated, and so it might not be possible to create the packet wrapper.
|
||||
fn pretty_print(buffer: T, fmt: &mut fmt::Formatter, indent: &mut PrettyIndent) -> fmt::Result;
|
||||
}
|
||||
|
||||
/// Wrapper for using a `PrettyPrint` where a `Display` is expected.
|
||||
pub struct PrettyPrinter<'a, T: PrettyPrint<&'a AsRef<[u8]>>> {
|
||||
prefix: &'static str,
|
||||
buffer: &'a AsRef<[u8]>,
|
||||
phantom: PhantomData<T>
|
||||
}
|
||||
|
||||
impl<'a, T: PrettyPrint<&'a AsRef<[u8]>>> PrettyPrinter<'a, T> {
|
||||
/// Format the listing with the recorded parameters when Display::fmt is called.
|
||||
pub fn new(prefix: &'static str, buffer: &'a AsRef<[u8]>) -> PrettyPrinter<'a, T> {
|
||||
PrettyPrinter {
|
||||
prefix: prefix,
|
||||
buffer: buffer,
|
||||
phantom: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: PrettyPrint<&'a AsRef<[u8]>>> fmt::Display for PrettyPrinter<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
T::pretty_print(self.buffer, f, &mut PrettyIndent::new(self.prefix))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue