Implement ARP replies.

v0.7.x
whitequark 2016-12-12 07:19:53 +00:00
parent d862512582
commit 4421b2fe27
11 changed files with 433 additions and 134 deletions

View File

@ -49,10 +49,46 @@ smoltcp = "0.1"
Usage example
-------------
```rust
TBD
_smoltcp_, being a userspace networking stack, needs to be able to send and receive raw frames.
This normally requires superuser privileges, but on Linux it is possible to create
a _persistent tap interface_ that can be manipulated by a specific user:
```sh
sudo ip tuntap add name tap0 mode tap user $USER
sudo ip link set tap0 up
sudo ip addr add 192.168.69.100 dev tap0
```
### smoltcpdump
_smoltcpdump_ is a tiny clone of the _tcpdump_ utility.
Unlike the rest of the examples, it uses raw sockets, and so it can be used on regular interfaces,
e.g. `eth0` or `wlan0`, as well as the `tap0` interface we've created above.
Read its [source code](/examples/smoltcpdump.rs), then run it as:
```sh
cargo build --example smoltcpdump
sudo ./target/debug/smoltcpdump eth0
```
### smoltcpserver
_smoltcpserver_ emulates a network host that can serve requests.
The host is assigned the hardware address `02-00-00-00-00-01` and IPv4 address `192.168.69.1`.
Read its [source code](/examples/smoltcpserver.rs), then run it as:
```sh
cargo run --example smoltcpserver -- tap0
```
It responds to:
* pings (`ping 192.168.69.1`) (actually not yet).
License
-------

54
examples/smoltcpserver.rs Normal file
View File

@ -0,0 +1,54 @@
#![feature(associated_consts)]
extern crate smoltcp;
use std::env;
use smoltcp::phy::{Device, TapInterface};
use smoltcp::wire::{PrettyPrinter, EthernetFrame, EthernetAddress};
use smoltcp::iface::{ProtocolAddress, SliceArpCache, EthernetInterface};
struct TracingDevice<T: Device>(T);
impl<T: Device> Device for TracingDevice<T> {
fn mtu(&self) -> usize {
self.0.mtu()
}
fn recv<R, F: FnOnce(&[u8]) -> R>(&self, handler: F) -> R {
self.0.recv(|buffer| {
print!("{}", PrettyPrinter::<EthernetFrame<_>>::new("<- ", &buffer));
handler(buffer)
})
}
fn send<R, F: FnOnce(&mut [u8]) -> R>(&self, len: usize, handler: F) -> R {
self.0.send(len, |buffer| {
let result = handler(buffer);
print!("{}", PrettyPrinter::<EthernetFrame<_>>::new("-> ", &buffer));
result
})
}
}
fn main() {
let ifname = env::args().nth(1).unwrap();
let hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]);
let protocol_addrs = [ProtocolAddress::ipv4([192, 168, 69, 1])];
let device = TapInterface::new(ifname.as_ref()).unwrap();
let device = TracingDevice(device);
let mut arp_cache_data = [Default::default(); 8];
let arp_cache = SliceArpCache::new(&mut arp_cache_data);
let mut iface = EthernetInterface::new(device, arp_cache);
iface.set_hardware_addr(hardware_addr);
iface.set_protocol_addrs(&protocol_addrs);
loop {
match iface.poll() {
Ok(()) => (),
Err(e) => println!("{}", e)
}
}
}

View File

@ -1,25 +1,29 @@
use Error;
use phy::Device;
use wire::EthernetAddress;
use wire::{EthernetAddress, EthernetProtocolType, EthernetFrame};
use wire::{ArpPacket, ArpRepr, ArpOperation};
use super::{ProtocolAddress, ArpCache};
/// An Ethernet network interface.
#[derive(Debug)]
pub struct Interface<DeviceT: Device, ArpCacheT: ArpCache> {
device: DeviceT,
arp_cache: ArpCacheT,
hardware_addr: EthernetAddress,
pub struct Interface<'a, DeviceT: Device, ArpCacheT: ArpCache> {
device: DeviceT,
arp_cache: ArpCacheT,
hardware_addr: EthernetAddress,
protocol_addrs: &'a [ProtocolAddress]
}
impl<DeviceT: Device, ArpCacheT: ArpCache> Interface<DeviceT, ArpCacheT> {
impl<'a, DeviceT: Device, ArpCacheT: ArpCache> Interface<'a, DeviceT, ArpCacheT> {
/// Create a network interface using the provided network device.
///
/// The newly created interface uses hardware address `00-00-00-00-00-00` and
/// has no assigned protocol addresses.
pub fn new(device: DeviceT, arp_cache: ArpCacheT) -> Interface<DeviceT, ArpCacheT> {
pub fn new(device: DeviceT, arp_cache: ArpCacheT) -> Interface<'a, DeviceT, ArpCacheT> {
Interface {
device: device,
arp_cache: arp_cache,
hardware_addr: EthernetAddress([0x00; 6])
device: device,
arp_cache: arp_cache,
hardware_addr: EthernetAddress([0x00; 6]),
protocol_addrs: &[]
}
}
@ -31,9 +35,98 @@ impl<DeviceT: Device, ArpCacheT: ArpCache> Interface<DeviceT, ArpCacheT> {
/// Set the hardware address of the interface.
///
/// # Panics
/// This function panics if `addr` is not unicast.
/// This function panics if the address is not unicast.
pub fn set_hardware_addr(&mut self, addr: EthernetAddress) {
if addr.is_multicast() { panic!("hardware address should be unicast") }
if addr.is_multicast() {
panic!("hardware address {} is not unicast", addr)
}
self.hardware_addr = addr
}
/// Get the protocol addresses of the interface.
pub fn protocol_addrs(&self) -> &'a [ProtocolAddress] {
self.protocol_addrs
}
/// Set the protocol addresses of the interface.
///
/// # Panics
/// This function panics if any of the addresses is not unicast.
pub fn set_protocol_addrs(&mut self, addrs: &'a [ProtocolAddress]) {
for addr in addrs {
if !addr.is_unicast() {
panic!("protocol address {} is not unicast", addr)
}
}
self.protocol_addrs = addrs
}
/// Checks whether the interface has the given protocol address assigned.
pub fn has_protocol_addr<T: Into<ProtocolAddress>>(&self, addr: T) -> bool {
let addr = addr.into();
self.protocol_addrs.iter().any(|&probe| probe == addr)
}
/// Receive and process a packet, if available.
pub fn poll(&mut self) -> Result<(), Error> {
enum Response {
Nop,
Arp(ArpRepr)
}
let response = try!(self.device.recv(|buffer| {
let frame = try!(EthernetFrame::new(buffer));
match frame.ethertype() {
EthernetProtocolType::Arp => {
let packet = try!(ArpPacket::new(frame.payload()));
let repr = try!(ArpRepr::parse(&packet));
match repr {
ArpRepr::EthernetIpv4 {
operation: ArpOperation::Request,
source_hardware_addr, source_protocol_addr,
target_protocol_addr, ..
} => {
if self.has_protocol_addr(target_protocol_addr) {
Ok(Response::Arp(ArpRepr::EthernetIpv4 {
operation: ArpOperation::Reply,
source_hardware_addr: self.hardware_addr,
source_protocol_addr: target_protocol_addr,
target_hardware_addr: source_hardware_addr,
target_protocol_addr: source_protocol_addr
}))
} else {
Ok(Response::Nop)
}
},
_ => Err(Error::Unrecognized)
}
},
_ => Err(Error::Unrecognized)
}
}));
// TODO: accurately calculate the outgoing packet size?
let size = self.device.mtu();
match response {
Response::Nop => Ok(()),
Response::Arp(repr) => {
self.device.send(size, |buffer| {
let mut frame = try!(EthernetFrame::new(buffer));
frame.set_source(self.hardware_addr);
frame.set_destination(match repr {
ArpRepr::EthernetIpv4 { target_hardware_addr, .. } => target_hardware_addr,
_ => unreachable!()
});
let mut packet = try!(ArpPacket::new(frame.payload_mut()));
repr.emit(&mut packet);
Ok(())
})
}
}
}
}

View File

@ -2,6 +2,7 @@
//!
//! The `iface` module deals with the *network interfaces*. It filters incoming frames,
//! provides lookup and caching of hardware addresses, and handles management packets.
use core::fmt;
use wire;
mod arp_cache;
@ -14,13 +15,25 @@ pub use self::ethernet::Interface as EthernetInterface;
/// An internetworking protocol address.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum ProtocolAddress {
/// An invalid address.
/// May be used as a placeholder for storage where the address is not assigned yet.
Invalid,
/// An IPv4 address.
Ipv4(wire::Ipv4Address)
}
impl ProtocolAddress {
pub const fn ipv4(bytes: [u8; 4]) -> ProtocolAddress {
ProtocolAddress::Ipv4(wire::Ipv4Address(bytes))
/// Create a protocol address wrapping an IPv4 address with the given octets.
pub const fn ipv4(octets: [u8; 4]) -> ProtocolAddress {
ProtocolAddress::Ipv4(wire::Ipv4Address(octets))
}
/// Query whether the address is a valid unicast address.
pub fn is_unicast(&self) -> bool {
match self {
&ProtocolAddress::Invalid => false,
&ProtocolAddress::Ipv4(addr) => addr.is_unicast()
}
}
}
@ -29,3 +42,18 @@ impl Default for ProtocolAddress {
ProtocolAddress::Invalid
}
}
impl From<wire::Ipv4Address> for ProtocolAddress {
fn from(addr: wire::Ipv4Address) -> Self {
ProtocolAddress::Ipv4(addr)
}
}
impl fmt::Display for ProtocolAddress {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&ProtocolAddress::Invalid => write!(f, "(invalid)"),
&ProtocolAddress::Ipv4(addr) => write!(f, "{}", addr)
}
}
}

View File

@ -1,4 +1,4 @@
#![feature(range_contains, associated_consts, const_fn)]
#![feature(associated_consts, const_fn)]
#![no_std]
extern crate byteorder;
@ -9,6 +9,31 @@ extern crate std;
#[cfg(feature = "std")]
extern crate libc;
use core::fmt;
pub mod phy;
pub mod wire;
pub mod iface;
/// The error type for the networking stack.
#[derive(Debug)]
pub enum Error {
/// A packet could not be parsed or emitted because a field was out of bounds
/// for the underlying buffer.
Truncated,
/// A packet could not be recognized and was dropped.
Unrecognized,
#[doc(hidden)]
__Nonexhaustive
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Error::Truncated => write!(f, "truncated packet"),
&Error::Unrecognized => write!(f, "unrecognized packet"),
&Error::__Nonexhaustive => unreachable!()
}
}
}

View File

@ -27,15 +27,18 @@ pub trait Device {
/// Maximum transmission unit.
///
/// The network device is unable to send or receive frames larger than the MTU.
/// In practice, MTU will fall between 64 and 9216 octets.
const MTU: usize;
/// In practice, MTU will fall between 576 (for IPv4) or 1280 (for IPv6) and 9216 octets.
fn mtu(&self) -> usize;
/// Receives a frame.
///
/// It is expected that a `recv` implementation, once a packet is written to memory
/// through DMA, would gain ownership of the underlying buffer, provide it for parsing,
/// and then return it to the network device.
fn recv<F: FnOnce(&[u8])>(&mut self, handler: F);
///
/// # Panics
/// This function may panic if called recursively.
fn recv<R, F: FnOnce(&[u8]) -> R>(&self, handler: F) -> R;
/// Transmits a frame.
///
@ -44,6 +47,6 @@ pub trait Device {
/// memory by the network device.
///
/// # Panics
/// This function may panic if `len` is larger than `MTU`.
fn send<F: FnOnce(&mut [u8])>(&mut self, len: usize, handler: F);
/// This function may panic if `len` is larger than `MTU`, or if called recursively.
fn send<R, F: FnOnce(&mut [u8]) -> R>(&self, len: usize, handler: F) -> R;
}

View File

@ -1,11 +1,13 @@
use std::{vec, io};
use std::cell::RefCell;
use std::vec::Vec;
use std::io;
use super::{sys, Device};
/// A socket that captures or transmits the complete frame.
#[derive(Debug)]
pub struct RawSocket {
lower: sys::RawSocketDesc,
buffer: vec::Vec<u8>
lower: RefCell<sys::RawSocketDesc>,
buffer: RefCell<Vec<u8>>
}
impl RawSocket {
@ -17,25 +19,33 @@ impl RawSocket {
let mut lower = try!(sys::RawSocketDesc::new(name));
try!(lower.bind_interface());
let mut buffer = vec::Vec::new();
let mut buffer = Vec::new();
buffer.resize(try!(lower.interface_mtu()), 0);
Ok(RawSocket {
lower: lower,
buffer: buffer
lower: RefCell::new(lower),
buffer: RefCell::new(buffer)
})
}
}
impl Device for RawSocket {
const MTU: usize = 1536;
fn recv<F: FnOnce(&[u8])>(&mut self, handler: F) {
let len = self.lower.recv(&mut self.buffer[..]).unwrap();
handler(&self.buffer[..len])
fn mtu(&self) -> usize {
let mut lower = self.lower.borrow_mut();
lower.interface_mtu().unwrap()
}
fn send<F: FnOnce(&mut [u8])>(&mut self, len: usize, handler: F) {
handler(&mut self.buffer[..len]);
self.lower.send(&self.buffer[..len]).unwrap();
fn recv<R, F: FnOnce(&[u8]) -> R>(&self, handler: F) -> R {
let mut lower = self.lower.borrow_mut();
let mut buffer = self.buffer.borrow_mut();
let len = lower.recv(&mut buffer[..]).unwrap();
handler(&buffer[..len])
}
fn send<R, F: FnOnce(&mut [u8]) -> R>(&self, len: usize, handler: F) -> R {
let mut lower = self.lower.borrow_mut();
let mut buffer = self.buffer.borrow_mut();
let result = handler(&mut buffer[..len]);
lower.send(&buffer[..len]).unwrap();
result
}
}

View File

@ -1,11 +1,13 @@
use std::{vec, io};
use std::cell::RefCell;
use std::vec::Vec;
use std::io;
use super::{sys, Device};
/// A virtual Ethernet interface.
#[derive(Debug)]
pub struct TapInterface {
lower: sys::TapInterfaceDesc,
buffer: vec::Vec<u8>
lower: RefCell<sys::TapInterfaceDesc>,
buffer: RefCell<Vec<u8>>
}
impl TapInterface {
@ -18,25 +20,33 @@ impl TapInterface {
let mut lower = try!(sys::TapInterfaceDesc::new(name));
try!(lower.attach_interface());
let mut buffer = vec::Vec::new();
buffer.resize(Self::MTU, 0);
let mut buffer = Vec::new();
buffer.resize(1536, 0);
Ok(TapInterface {
lower: lower,
buffer: buffer
lower: RefCell::new(lower),
buffer: RefCell::new(buffer)
})
}
}
impl Device for TapInterface {
const MTU: usize = 1536;
fn recv<F: FnOnce(&[u8])>(&mut self, handler: F) {
let len = self.lower.recv(&mut self.buffer[..]).unwrap();
handler(&self.buffer[..len])
fn mtu(&self) -> usize {
let buffer = self.buffer.borrow();
buffer.len()
}
fn send<F: FnOnce(&mut [u8])>(&mut self, len: usize, handler: F) {
handler(&mut self.buffer[..len]);
self.lower.send(&self.buffer[..len]).unwrap();
fn recv<R, F: FnOnce(&[u8]) -> R>(&self, handler: F) -> R {
let mut lower = self.lower.borrow_mut();
let mut buffer = self.buffer.borrow_mut();
let len = lower.recv(&mut buffer[..]).unwrap();
handler(&buffer[..len])
}
fn send<R, F: FnOnce(&mut [u8]) -> R>(&self, len: usize, handler: F) -> R {
let mut lower = self.lower.borrow_mut();
let mut buffer = self.buffer.borrow_mut();
let result = handler(&mut buffer[..len]);
lower.send(&buffer[..len]).unwrap();
result
}
}

View File

@ -1,5 +1,6 @@
use core::fmt;
use byteorder::{ByteOrder, NetworkEndian};
use Error;
pub use super::EthernetProtocolType as ProtocolType;
@ -20,7 +21,9 @@ enum_with_unknown! {
/// A read/write wrapper around an Address Resolution Protocol packet.
#[derive(Debug)]
pub struct Packet<T: AsRef<[u8]>>(T);
pub struct Packet<T: AsRef<[u8]>> {
buffer: T
}
mod field {
#![allow(non_snake_case)]
@ -61,14 +64,14 @@ mod field {
impl<T: AsRef<[u8]>> Packet<T> {
/// Wrap a buffer with an ARP packet. Returns an error if the buffer
/// is too small to contain one.
pub fn new(storage: T) -> Result<Packet<T>, ()> {
let len = storage.as_ref().len();
pub fn new(buffer: T) -> Result<Packet<T>, Error> {
let len = buffer.as_ref().len();
if len < field::OPER.end {
Err(())
Err(Error::Truncated)
} else {
let packet = Packet(storage);
let packet = Packet { buffer: buffer };
if len < field::TPA(packet.hardware_len(), packet.protocol_len()).end {
Err(())
Err(Error::Truncated)
} else {
Ok(packet)
}
@ -77,96 +80,96 @@ impl<T: AsRef<[u8]>> Packet<T> {
/// Consumes the packet, returning the underlying buffer.
pub fn into_inner(self) -> T {
self.0
self.buffer
}
/// Return the hardware type field.
pub fn hardware_type(&self) -> HardwareType {
let bytes = self.0.as_ref();
let raw = NetworkEndian::read_u16(&bytes[field::HTYPE]);
let data = self.buffer.as_ref();
let raw = NetworkEndian::read_u16(&data[field::HTYPE]);
HardwareType::from(raw)
}
/// Return the protocol type field.
pub fn protocol_type(&self) -> ProtocolType {
let bytes = self.0.as_ref();
let raw = NetworkEndian::read_u16(&bytes[field::PTYPE]);
let data = self.buffer.as_ref();
let raw = NetworkEndian::read_u16(&data[field::PTYPE]);
ProtocolType::from(raw)
}
/// Return the hardware length field.
pub fn hardware_len(&self) -> u8 {
let bytes = self.0.as_ref();
bytes[field::HLEN]
let data = self.buffer.as_ref();
data[field::HLEN]
}
/// Return the protocol length field.
pub fn protocol_len(&self) -> u8 {
let bytes = self.0.as_ref();
bytes[field::PLEN]
let data = self.buffer.as_ref();
data[field::PLEN]
}
/// Return the operation field.
pub fn operation(&self) -> Operation {
let bytes = self.0.as_ref();
let raw = NetworkEndian::read_u16(&bytes[field::OPER]);
let data = self.buffer.as_ref();
let raw = NetworkEndian::read_u16(&data[field::OPER]);
Operation::from(raw)
}
/// Return the source hardware address field.
pub fn source_hardware_addr(&self) -> &[u8] {
let bytes = self.0.as_ref();
&bytes[field::SHA(self.hardware_len(), self.protocol_len())]
let data = self.buffer.as_ref();
&data[field::SHA(self.hardware_len(), self.protocol_len())]
}
/// Return the source protocol address field.
pub fn source_protocol_addr(&self) -> &[u8] {
let bytes = self.0.as_ref();
&bytes[field::SPA(self.hardware_len(), self.protocol_len())]
let data = self.buffer.as_ref();
&data[field::SPA(self.hardware_len(), self.protocol_len())]
}
/// Return the target hardware address field.
pub fn target_hardware_addr(&self) -> &[u8] {
let bytes = self.0.as_ref();
&bytes[field::THA(self.hardware_len(), self.protocol_len())]
let data = self.buffer.as_ref();
&data[field::THA(self.hardware_len(), self.protocol_len())]
}
/// Return the target protocol address field.
pub fn target_protocol_addr(&self) -> &[u8] {
let bytes = self.0.as_ref();
&bytes[field::TPA(self.hardware_len(), self.protocol_len())]
let data = self.buffer.as_ref();
&data[field::TPA(self.hardware_len(), self.protocol_len())]
}
}
impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
/// Set the hardware type field.
pub fn set_hardware_type(&mut self, value: HardwareType) {
let bytes = self.0.as_mut();
NetworkEndian::write_u16(&mut bytes[field::HTYPE], value.into())
let data = self.buffer.as_mut();
NetworkEndian::write_u16(&mut data[field::HTYPE], value.into())
}
/// Set the protocol type field.
pub fn set_protocol_type(&mut self, value: ProtocolType) {
let bytes = self.0.as_mut();
NetworkEndian::write_u16(&mut bytes[field::PTYPE], value.into())
let data = self.buffer.as_mut();
NetworkEndian::write_u16(&mut data[field::PTYPE], value.into())
}
/// Set the hardware length field.
pub fn set_hardware_len(&mut self, value: u8) {
let bytes = self.0.as_mut();
bytes[field::HLEN] = value
let data = self.buffer.as_mut();
data[field::HLEN] = value
}
/// Set the protocol length field.
pub fn set_protocol_len(&mut self, value: u8) {
let bytes = self.0.as_mut();
bytes[field::PLEN] = value
let data = self.buffer.as_mut();
data[field::PLEN] = value
}
/// Set the operation field.
pub fn set_operation(&mut self, value: Operation) {
let bytes = self.0.as_mut();
NetworkEndian::write_u16(&mut bytes[field::OPER], value.into())
let data = self.buffer.as_mut();
NetworkEndian::write_u16(&mut data[field::OPER], value.into())
}
/// Set the source hardware address field.
@ -175,8 +178,8 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
/// The function panics if `value` is not `self.hardware_len()` long.
pub fn set_source_hardware_addr(&mut self, value: &[u8]) {
let (hardware_len, protocol_len) = (self.hardware_len(), self.protocol_len());
let bytes = self.0.as_mut();
bytes[field::SHA(hardware_len, protocol_len)].copy_from_slice(value)
let data = self.buffer.as_mut();
data[field::SHA(hardware_len, protocol_len)].copy_from_slice(value)
}
/// Set the source protocol address field.
@ -185,8 +188,8 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
/// The function panics if `value` is not `self.protocol_len()` long.
pub fn set_source_protocol_addr(&mut self, value: &[u8]) {
let (hardware_len, protocol_len) = (self.hardware_len(), self.protocol_len());
let bytes = self.0.as_mut();
bytes[field::SPA(hardware_len, protocol_len)].copy_from_slice(value)
let data = self.buffer.as_mut();
data[field::SPA(hardware_len, protocol_len)].copy_from_slice(value)
}
/// Set the target hardware address field.
@ -195,8 +198,8 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
/// The function panics if `value` is not `self.hardware_len()` long.
pub fn set_target_hardware_addr(&mut self, value: &[u8]) {
let (hardware_len, protocol_len) = (self.hardware_len(), self.protocol_len());
let bytes = self.0.as_mut();
bytes[field::THA(hardware_len, protocol_len)].copy_from_slice(value)
let data = self.buffer.as_mut();
data[field::THA(hardware_len, protocol_len)].copy_from_slice(value)
}
/// Set the target protocol address field.
@ -205,8 +208,8 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
/// The function panics if `value` is not `self.protocol_len()` long.
pub fn set_target_protocol_addr(&mut self, value: &[u8]) {
let (hardware_len, protocol_len) = (self.hardware_len(), self.protocol_len());
let bytes = self.0.as_mut();
bytes[field::TPA(hardware_len, protocol_len)].copy_from_slice(value)
let data = self.buffer.as_mut();
data[field::TPA(hardware_len, protocol_len)].copy_from_slice(value)
}
}
@ -230,7 +233,7 @@ pub enum Repr {
impl Repr {
/// Parse an Address Resolution Packet and return a high-level representation,
/// or return `Err(())` if the packet is not recognized.
pub fn parse<T: AsRef<[u8]>>(packet: &Packet<T>) -> Result<Repr, ()> {
pub fn parse<T: AsRef<[u8]>>(packet: &Packet<T>) -> Result<Repr, Error> {
match (packet.hardware_type(), packet.protocol_type(),
packet.hardware_len(), packet.protocol_len()) {
(HardwareType::Ethernet, ProtocolType::Ipv4, 6, 4) => {
@ -246,7 +249,7 @@ impl Repr {
Ipv4Address::from_bytes(packet.target_protocol_addr())
})
},
_ => Err(())
_ => Err(Error::Unrecognized)
}
}
@ -315,7 +318,7 @@ 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),
Err(err) => write!(f, "{}({})\n", indent, err),
Ok(frame) => write!(f, "{}{}\n", indent, frame)
}
}

View File

@ -1,5 +1,6 @@
use core::fmt;
use byteorder::{ByteOrder, NetworkEndian};
use Error;
enum_with_unknown! {
/// Ethernet protocol type.
@ -57,20 +58,22 @@ impl Address {
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}",
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.
#[derive(Debug)]
pub struct Frame<T: AsRef<[u8]>>(T);
pub struct Frame<T: AsRef<[u8]>> {
buffer: T
}
mod field {
use ::wire::field::*;
pub const SOURCE: Field = 0..6;
pub const DESTINATION: Field = 6..12;
pub const DESTINATION: Field = 0..6;
pub const SOURCE: Field = 6..12;
pub const ETHERTYPE: Field = 12..14;
pub const PAYLOAD: FieldFrom = 14..;
}
@ -78,77 +81,77 @@ mod field {
impl<T: AsRef<[u8]>> Frame<T> {
/// Wrap a buffer with an Ethernet frame. Returns an error if the buffer
/// is too small or too large to contain one.
pub fn new(storage: T) -> Result<Frame<T>, ()> {
let len = storage.as_ref().len();
if !(14..1518).contains(len) {
Err(()) // TODO: error type?
pub fn new(buffer: T) -> Result<Frame<T>, Error> {
let len = buffer.as_ref().len();
if len < field::PAYLOAD.start {
Err(Error::Truncated)
} else {
Ok(Frame(storage))
Ok(Frame { buffer: buffer })
}
}
/// Consumes the frame, returning the underlying buffer.
pub fn into_inner(self) -> T {
self.0
}
/// Return the source address field.
#[inline(always)]
pub fn source(&self) -> Address {
let bytes = self.0.as_ref();
Address::from_bytes(&bytes[field::SOURCE])
self.buffer
}
/// Return the destination address field.
#[inline(always)]
pub fn destination(&self) -> Address {
let bytes = self.0.as_ref();
Address::from_bytes(&bytes[field::DESTINATION])
let data = self.buffer.as_ref();
Address::from_bytes(&data[field::DESTINATION])
}
/// Return the source address field.
#[inline(always)]
pub fn source(&self) -> Address {
let data = self.buffer.as_ref();
Address::from_bytes(&data[field::SOURCE])
}
/// Return the EtherType field, without checking for 802.1Q.
#[inline(always)]
pub fn ethertype(&self) -> EtherType {
let bytes = self.0.as_ref();
let raw = NetworkEndian::read_u16(&bytes[field::ETHERTYPE]);
let data = self.buffer.as_ref();
let raw = NetworkEndian::read_u16(&data[field::ETHERTYPE]);
EtherType::from(raw)
}
/// Return a pointer to the payload, without checking for 802.1Q.
#[inline(always)]
pub fn payload(&self) -> &[u8] {
let bytes = self.0.as_ref();
&bytes[field::PAYLOAD]
let data = self.buffer.as_ref();
&data[field::PAYLOAD]
}
}
impl<T: AsRef<[u8]> + AsMut<[u8]>> Frame<T> {
/// Set the source address field.
#[inline(always)]
pub fn set_source(&mut self, value: Address) {
let bytes = self.0.as_mut();
bytes[field::SOURCE].copy_from_slice(value.as_bytes())
}
/// Set the destination address field.
#[inline(always)]
pub fn set_destination(&mut self, value: Address) {
let bytes = self.0.as_mut();
bytes[field::DESTINATION].copy_from_slice(value.as_bytes())
let data = self.buffer.as_mut();
data[field::DESTINATION].copy_from_slice(value.as_bytes())
}
/// Set the source address field.
#[inline(always)]
pub fn set_source(&mut self, value: Address) {
let data = self.buffer.as_mut();
data[field::SOURCE].copy_from_slice(value.as_bytes())
}
/// Set the EtherType field.
#[inline(always)]
pub fn set_ethertype(&mut self, value: EtherType) {
let bytes = self.0.as_mut();
NetworkEndian::write_u16(&mut bytes[field::ETHERTYPE], value.into())
let data = self.buffer.as_mut();
NetworkEndian::write_u16(&mut data[field::ETHERTYPE], value.into())
}
/// Return a mutable pointer to the payload.
#[inline(always)]
pub fn payload_mut(&mut self) -> &mut [u8] {
let bytes = self.0.as_mut();
&mut bytes[field::PAYLOAD]
let data = self.buffer.as_mut();
&mut data[field::PAYLOAD]
}
}
@ -165,7 +168,7 @@ 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),
Err(err) => return write!(f, "{}({})\n", indent, err),
Ok(frame) => frame
};
try!(write!(f, "{}{}\n", indent, frame));

View File

@ -5,6 +5,8 @@ use core::fmt;
pub struct Address(pub [u8; 4]);
impl Address {
pub const BROADCAST: Address = Address([255; 4]);
/// Construct an IPv4 address from a sequence of octets, in big-endian.
///
/// # Panics
@ -19,6 +21,38 @@ impl Address {
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() ||
self.is_unspecified())
}
/// Query whether the address is the broadcast address.
pub fn is_broadcast(&self) -> bool {
self.0[0..4] == [255; 4]
}
/// Query whether the address is a multicast address.
pub fn is_multicast(&self) -> bool {
self.0[0] & 0xf0 == 224
}
/// Query whether the address falls into the "unspecified" range.
pub fn is_unspecified(&self) -> bool {
self.0[0] == 0
}
/// Query whether the address falls into the "link-local" range.
pub fn is_link_local(&self) -> bool {
self.0[0..2] == [169, 254]
}
/// Query whether the address falls into the "loopback" range.
pub fn is_loopback(&self) -> bool {
self.0[0] == 127
}
}
impl fmt::Display for Address {