Implement UDP representation parsing and emission.

v0.7.x
whitequark 2016-12-14 01:59:47 +00:00
parent 5a721a7b11
commit 2b01a3dace
10 changed files with 275 additions and 111 deletions

View File

@ -3,14 +3,14 @@ extern crate smoltcp;
use std::env;
use smoltcp::phy::{Tracer, TapInterface};
use smoltcp::wire::{EthernetFrame, EthernetAddress};
use smoltcp::iface::{ProtocolAddress, SliceArpCache, EthernetInterface};
use smoltcp::wire::{EthernetFrame, EthernetAddress, InternetAddress};
use smoltcp::iface::{SliceArpCache, EthernetInterface};
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 protocol_addrs = [InternetAddress::ipv4([192, 168, 69, 1])];
let device = TapInterface::new(ifname.as_ref()).unwrap();
let device = Tracer::<_, EthernetFrame<&[u8]>>::new(device);

View File

@ -1,15 +1,14 @@
use wire::EthernetAddress;
use super::ProtocolAddress;
use wire::{EthernetAddress, InternetAddress};
/// An Address Resolution Protocol cache.
///
/// This cache maps protocol addresses to hardware addresses.
pub trait Cache {
/// Update the cache to map given protocol address to given hardware address.
fn fill(&mut self, protocol_addr: ProtocolAddress, hardware_addr: EthernetAddress);
fn fill(&mut self, protocol_addr: InternetAddress, hardware_addr: EthernetAddress);
/// Look up the hardware address corresponding for the given protocol address.
fn lookup(&mut self, protocol_addr: ProtocolAddress) -> Option<EthernetAddress>;
fn lookup(&mut self, protocol_addr: InternetAddress) -> Option<EthernetAddress>;
}
/// An Address Resolution Protocol cache backed by a slice.
@ -26,7 +25,7 @@ pub trait Cache {
/// let mut arp_cache = SliceArpCache::new(&mut arp_cache_storage);
/// ```
pub struct SliceCache<'a> {
storage: &'a mut [(ProtocolAddress, EthernetAddress, usize)],
storage: &'a mut [(InternetAddress, EthernetAddress, usize)],
counter: usize
}
@ -35,7 +34,7 @@ impl<'a> SliceCache<'a> {
///
/// # Panics
/// This function panics if `storage.len() == 0`.
pub fn new(storage: &'a mut [(ProtocolAddress, EthernetAddress, usize)]) -> SliceCache<'a> {
pub fn new(storage: &'a mut [(InternetAddress, EthernetAddress, usize)]) -> SliceCache<'a> {
if storage.len() == 0 {
panic!("ARP slice cache created with empty storage")
}
@ -50,9 +49,9 @@ impl<'a> SliceCache<'a> {
}
/// Find an entry for the given protocol address, if any.
fn find(&self, protocol_addr: ProtocolAddress) -> Option<usize> {
// The order of comparison is important: any valid ProtocolAddress should
// sort before ProtocolAddress::Invalid.
fn find(&self, protocol_addr: InternetAddress) -> Option<usize> {
// The order of comparison is important: any valid InternetAddress should
// sort before InternetAddress::Invalid.
self.storage.binary_search_by_key(&protocol_addr, |&(key, _, _)| key).ok()
}
@ -68,14 +67,14 @@ impl<'a> SliceCache<'a> {
}
impl<'a> Cache for SliceCache<'a> {
fn fill(&mut self, protocol_addr: ProtocolAddress, hardware_addr: EthernetAddress) {
fn fill(&mut self, protocol_addr: InternetAddress, hardware_addr: EthernetAddress) {
if let None = self.find(protocol_addr) {
self.storage[self.lru()] = (protocol_addr, hardware_addr, self.counter);
self.sort()
}
}
fn lookup(&mut self, protocol_addr: ProtocolAddress) -> Option<EthernetAddress> {
fn lookup(&mut self, protocol_addr: InternetAddress) -> Option<EthernetAddress> {
if let Some(index) = self.find(protocol_addr) {
let (_protocol_addr, hardware_addr, ref mut counter) = self.storage[index];
self.counter += 1;
@ -96,10 +95,10 @@ mod test {
const HADDR_C: EthernetAddress = EthernetAddress([0, 0, 0, 0, 0, 3]);
const HADDR_D: EthernetAddress = EthernetAddress([0, 0, 0, 0, 0, 4]);
const PADDR_A: ProtocolAddress = ProtocolAddress::ipv4([0, 0, 0, 0]);
const PADDR_B: ProtocolAddress = ProtocolAddress::ipv4([0, 0, 0, 1]);
const PADDR_C: ProtocolAddress = ProtocolAddress::ipv4([0, 0, 0, 2]);
const PADDR_D: ProtocolAddress = ProtocolAddress::ipv4([0, 0, 0, 3]);
const PADDR_A: InternetAddress = InternetAddress::ipv4([0, 0, 0, 0]);
const PADDR_B: InternetAddress = InternetAddress::ipv4([0, 0, 0, 1]);
const PADDR_C: InternetAddress = InternetAddress::ipv4([0, 0, 0, 2]);
const PADDR_D: InternetAddress = InternetAddress::ipv4([0, 0, 0, 3]);
#[test]
fn test_slice_cache() {

View File

@ -2,10 +2,10 @@ use Error;
use phy::Device;
use wire::{EthernetAddress, EthernetProtocolType, EthernetFrame};
use wire::{ArpPacket, ArpRepr, ArpOperation};
use wire::InternetProtocolType;
use wire::{InternetAddress, InternetProtocolType};
use wire::{Ipv4Packet, Ipv4Repr};
use wire::{Icmpv4Packet, Icmpv4Repr};
use super::{ProtocolAddress, ArpCache};
use super::{ArpCache};
/// An Ethernet network interface.
#[derive(Debug)]
@ -13,7 +13,7 @@ pub struct Interface<'a, DeviceT: Device, ArpCacheT: ArpCache> {
device: DeviceT,
arp_cache: ArpCacheT,
hardware_addr: EthernetAddress,
protocol_addrs: &'a [ProtocolAddress]
protocol_addrs: &'a [InternetAddress]
}
impl<'a, DeviceT: Device, ArpCacheT: ArpCache> Interface<'a, DeviceT, ArpCacheT> {
@ -48,7 +48,7 @@ impl<'a, DeviceT: Device, ArpCacheT: ArpCache> Interface<'a, DeviceT, ArpCacheT>
}
/// Get the protocol addresses of the interface.
pub fn protocol_addrs(&self) -> &'a [ProtocolAddress] {
pub fn protocol_addrs(&self) -> &'a [InternetAddress] {
self.protocol_addrs
}
@ -56,7 +56,7 @@ impl<'a, DeviceT: Device, ArpCacheT: ArpCache> Interface<'a, DeviceT, ArpCacheT>
///
/// # Panics
/// This function panics if any of the addresses is not unicast.
pub fn set_protocol_addrs(&mut self, addrs: &'a [ProtocolAddress]) {
pub fn set_protocol_addrs(&mut self, addrs: &'a [InternetAddress]) {
for addr in addrs {
if !addr.is_unicast() {
panic!("protocol address {} is not unicast", addr)
@ -67,7 +67,7 @@ impl<'a, DeviceT: Device, ArpCacheT: ArpCache> Interface<'a, DeviceT, ArpCacheT>
}
/// Checks whether the interface has the given protocol address assigned.
pub fn has_protocol_addr<T: Into<ProtocolAddress>>(&self, addr: T) -> bool {
pub fn has_protocol_addr<T: Into<InternetAddress>>(&self, addr: T) -> bool {
let addr = addr.into();
self.protocol_addrs.iter().any(|&probe| probe == addr)
}

View File

@ -2,58 +2,9 @@
//!
//! 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;
mod ethernet;
pub use self::arp_cache::Cache as ArpCache;
pub use self::arp_cache::SliceCache as SliceArpCache;
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 {
/// 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()
}
}
}
impl Default for ProtocolAddress {
fn default() -> 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

@ -291,7 +291,8 @@ impl<T: AsRef<[u8]>> fmt::Display for Packet<T> {
match Repr::parse(self) {
Ok(repr) => write!(f, "{}", repr),
_ => {
try!(write!(f, "ARP htype={:?} ptype={:?} hlen={:?} plen={:?} op={:?}",
try!(write!(f, "ARP (unrecognized)"));
try!(write!(f, " htype={:?} ptype={:?} hlen={:?} plen={:?} op={:?}",
self.hardware_type(), self.protocol_type(),
self.hardware_len(), self.protocol_len(),
self.operation()));

View File

@ -215,7 +215,7 @@ impl<T: AsRef<[u8]>> Packet<T> {
/// Validate the header checksum.
pub fn verify_checksum(&self) -> bool {
let data = self.buffer.as_ref();
checksum(data) == !0
checksum::data(data) == !0
}
}
@ -275,7 +275,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
self.set_checksum(0);
let checksum = {
let data = self.buffer.as_ref();
!checksum(data)
!checksum::data(data)
};
self.set_checksum(checksum)
}
@ -310,8 +310,7 @@ pub enum Repr<'a> {
impl<'a> Repr<'a> {
/// Parse an Internet Control Message Protocol version 4 packet and return
/// a high-level representation, or return `Err(())` if the packet is not recognized
/// or is malformed.
/// a high-level representation.
pub fn parse<T: AsRef<[u8]> + ?Sized>(packet: &Packet<&'a T>) -> Result<Repr<'a>, Error> {
match (packet.msg_type(), packet.msg_code()) {
(Type::EchoRequest, 0) => {
@ -343,7 +342,8 @@ impl<'a> Repr<'a> {
}
}
/// Emit a high-level representation into an Internet Protocol version 4 packet.
/// Emit a high-level representation into an Internet Control Message Protocol version 4
/// packet.
pub fn emit<T: AsRef<[u8]> + AsMut<[u8]> + ?Sized>(&self, packet: &mut Packet<&mut T>) {
packet.set_msg_code(0);
match self {
@ -372,8 +372,10 @@ impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&'a T> {
match Repr::parse(self) {
Ok(repr) => write!(f, "{}", repr),
_ => {
write!(f, "ICMPv4 type={} code={}",
self.msg_type(), self.msg_code())
try!(write!(f, "ICMPv4 (unrecognized)"));
try!(write!(f, " type={} code={} cksum={:#04x}",
self.msg_type(), self.msg_code(), self.checksum()));
Ok(())
}
}
}
@ -397,8 +399,8 @@ impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
fn pretty_print(buffer: &AsRef<[u8]>, f: &mut fmt::Formatter,
indent: &mut PrettyIndent) -> fmt::Result {
match Packet::new(buffer) {
Err(err) => write!(f, "{}({})\n", indent, err),
Ok(frame) => write!(f, "{}{}\n", indent, frame)
Err(err) => write!(f, "{}({})\n", indent, err),
Ok(packet) => write!(f, "{}{}\n", indent, packet)
}
}
}

View File

@ -1,8 +1,9 @@
use core::fmt;
use byteorder::{ByteOrder, NetworkEndian};
use super::Ipv4Address;
enum_with_unknown! {
/// Internet protocol type.
/// Internetworking protocol type.
pub enum ProtocolType(u8) {
Icmp = 0x01,
Tcp = 0x06,
@ -21,12 +22,93 @@ impl fmt::Display for ProtocolType {
}
}
/// Compute an RFC 1071 compliant checksum (without the final complement).
pub fn checksum(data: &[u8]) -> u16 {
let mut accum: u32 = 0;
for i in (0..data.len()).step_by(2) {
let word = NetworkEndian::read_u16(&data[i..i + 2]) as u32;
accum += word;
}
(((accum >> 16) as u16) + (accum as u16))
/// An internetworking address.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum Address {
/// An invalid address.
/// May be used as a placeholder for storage where the address is not assigned yet.
Invalid,
/// An IPv4 address.
Ipv4(Ipv4Address)
}
impl Address {
/// Create an address wrapping an IPv4 address with the given octets.
pub const fn ipv4(octets: [u8; 4]) -> Address {
Address::Ipv4(Ipv4Address(octets))
}
/// Query whether the address is a valid unicast address.
pub fn is_unicast(&self) -> bool {
match self {
&Address::Invalid => false,
&Address::Ipv4(addr) => addr.is_unicast()
}
}
}
impl Default for Address {
fn default() -> Address {
Address::Invalid
}
}
impl From<Ipv4Address> for Address {
fn from(addr: Ipv4Address) -> Self {
Address::Ipv4(addr)
}
}
impl fmt::Display for Address {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Address::Invalid => write!(f, "(invalid)"),
&Address::Ipv4(addr) => write!(f, "{}", addr)
}
}
}
pub mod checksum {
use byteorder::{ByteOrder, NetworkEndian};
use super::*;
/// Compute an RFC 1071 compliant checksum (without the final complement).
pub fn data(data: &[u8]) -> u16 {
let mut accum: u32 = 0;
for i in (0..data.len()).step_by(2) {
let word = NetworkEndian::read_u16(&data[i..i + 2]) as u32;
accum += word;
}
(((accum >> 16) as u16) + (accum as u16))
}
/// Combine several RFC 1071 compliant checksums.
pub fn combine(checksums: &[u16]) -> u16 {
let mut accum: u32 = 0;
for &word in checksums {
accum += word as u32;
}
(((accum >> 16) as u16) + (accum as u16))
}
/// Compute an IP pseudo header checksum.
pub fn pseudo_header(src_addr: &Address, dst_addr: &Address,
protocol: ProtocolType, length: u32) -> u16 {
match (src_addr, dst_addr) {
(&Address::Ipv4(src_addr), &Address::Ipv4(dst_addr)) => {
let mut proto_len = [0u8; 4];
proto_len[1] = protocol.into();
NetworkEndian::write_u16(&mut proto_len[2..4], length as u16);
combine(&[
data(src_addr.as_bytes()),
data(dst_addr.as_bytes()),
data(&proto_len[..])
])
},
_ => panic!("Unexpected pseudo header ")
}
}
}

View File

@ -210,7 +210,7 @@ impl<T: AsRef<[u8]>> Packet<T> {
/// Validate the header checksum.
pub fn verify_checksum(&self) -> bool {
let data = self.buffer.as_ref();
checksum(&data[..self.header_len() as usize]) == !0
checksum::data(&data[..self.header_len() as usize]) == !0
}
}
@ -332,7 +332,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
self.set_checksum(0);
let checksum = {
let data = self.buffer.as_ref();
!checksum(&data[..self.header_len() as usize])
!checksum::data(&data[..self.header_len() as usize])
};
self.set_checksum(checksum)
}
@ -357,8 +357,7 @@ pub struct Repr {
}
impl Repr {
/// Parse an Internet Protocol version 4 packet and return a high-level representation,
/// or return `Err(())` if the packet is not recognized or is malformed.
/// Parse an Internet Protocol version 4 packet and return a high-level representation.
pub fn parse<T: AsRef<[u8]> + ?Sized>(packet: &Packet<&T>) -> Result<Repr, Error> {
// Version 4 is expected.
if packet.version() != 4 { return Err(Error::Malformed) }
@ -408,7 +407,8 @@ impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&'a T> {
match Repr::parse(self) {
Ok(repr) => write!(f, "{}", repr),
_ => {
try!(write!(f, "IPv4 src={} dst={} proto={} ttl={}",
try!(write!(f, "IPv4 (unrecognized)"));
try!(write!(f, " src={} dst={} proto={} ttl={}",
self.src_addr(), self.dst_addr(), self.protocol(), self.ttl()));
if self.version() != 4 {
try!(write!(f, " ver={}", self.version()))
@ -463,6 +463,8 @@ impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
match packet.protocol() {
ProtocolType::Icmp =>
super::Icmpv4Packet::<&[u8]>::pretty_print(&packet.payload(), f, indent),
ProtocolType::Udp =>
super::UdpPacket::<&[u8]>::pretty_print(&packet.payload(), f, indent),
_ => Ok(())
}
}

View File

@ -16,9 +16,9 @@
//! `-Cpanic=abort`. The accessor and parsing functions never panic. The setter and emission
//! functions only panic if the underlying buffer is too small.
//!
//! The data structures in the `wire` module do not perform validation of received data;
//! that is the job of an upper layer. This includes the `Repr` family, which only validate
//! as much as is necessary to build the representation.
//! The `Frame` and `Packet` families of data structures in the `wire` module do not perform
//! validation of received data except as needed to access the contents without panicking;
//! the `Repr` family does.
macro_rules! enum_with_unknown {
(
@ -94,12 +94,12 @@ pub use self::ethernet::Address as EthernetAddress;
pub use self::ethernet::Frame as EthernetFrame;
pub use self::arp::HardwareType as ArpHardwareType;
pub use self::arp::ProtocolType as ArpProtocolType;
pub use self::arp::Operation as ArpOperation;
pub use self::arp::Packet as ArpPacket;
pub use self::arp::Repr as ArpRepr;
pub use self::ip::ProtocolType as InternetProtocolType;
pub use self::ip::Address as InternetAddress;
pub use self::ipv4::Address as Ipv4Address;
pub use self::ipv4::Packet as Ipv4Packet;
@ -114,3 +114,4 @@ pub use self::icmpv4::Packet as Icmpv4Packet;
pub use self::icmpv4::Repr as Icmpv4Repr;
pub use self::udp::Packet as UdpPacket;
pub use self::udp::Repr as UdpRepr;

View File

@ -1,7 +1,8 @@
use core::{cmp, fmt};
use core::fmt;
use byteorder::{ByteOrder, NetworkEndian};
use Error;
use super::{InternetProtocolType, InternetAddress};
use super::ip::checksum;
/// A read/write wrapper around an User Datagram Protocol packet buffer.
@ -71,9 +72,17 @@ impl<T: AsRef<[u8]>> Packet<T> {
}
/// Validate the packet checksum.
pub fn verify_checksum(&self) -> bool {
///
/// # Panics
/// This function panics unless `src_addr` and `dst_addr` belong to the same family,
/// and that family is IPv4 or IPv6.
pub fn verify_checksum(&self, src_addr: &InternetAddress, dst_addr: &InternetAddress) -> bool {
let data = self.buffer.as_ref();
checksum(&data[..self.len() as usize]) == !0
checksum::combine(&[
checksum::pseudo_header(src_addr, dst_addr, InternetProtocolType::Udp,
self.len() as u32),
checksum::data(&data[..self.len() as usize])
]) == !0
}
}
@ -116,11 +125,19 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
}
/// Compute and fill in the header checksum.
pub fn fill_checksum(&mut self) {
///
/// # Panics
/// This function panics unless `src_addr` and `dst_addr` belong to the same family,
/// and that family is IPv4 or IPv6.
pub fn fill_checksum(&mut self, src_addr: &InternetAddress, dst_addr: &InternetAddress) {
self.set_checksum(0);
let checksum = {
let data = self.buffer.as_ref();
!checksum(&data[..self.len() as usize])
!checksum::combine(&[
checksum::pseudo_header(src_addr, dst_addr, InternetProtocolType::Udp,
self.len() as u32),
checksum::data(&data[..self.len() as usize])
])
};
self.set_checksum(checksum)
}
@ -135,13 +152,99 @@ impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> Packet<&'a mut T> {
}
}
/// A high-level representation of an User Datagram Protocol packet.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Repr<'a> {
pub src_port: u16,
pub dst_port: u16,
pub payload: &'a [u8]
}
impl<'a> Repr<'a> {
/// Parse an User Datagram Protocol packet and return a high-level representation.
pub fn parse<T: ?Sized>(packet: &Packet<&'a T>,
src_addr: &InternetAddress,
dst_addr: &InternetAddress) -> Result<Repr<'a>, Error>
where T: AsRef<[u8]> {
// Destination port cannot be omitted (but source port can be).
if packet.dst_port() == 0 { return Err(Error::Malformed) }
// Valid checksum is expected...
if !packet.verify_checksum(src_addr, dst_addr) {
match (src_addr, dst_addr) {
(&InternetAddress::Ipv4(_), &InternetAddress::Ipv4(_))
if packet.checksum() != 0 => {
// ... except on UDP-over-IPv4, where it can be omitted.
return Err(Error::Checksum)
},
_ => {
return Err(Error::Checksum)
}
}
}
Ok(Repr {
src_port: packet.src_port(),
dst_port: packet.dst_port(),
payload: packet.payload()
})
}
/// Return the length of a packet that will be emitted from this high-level representation.
pub fn len(&self) -> usize {
field::PAYLOAD.start + self.payload.len()
}
/// Emit a high-level representation into an User Datagram Protocol packet.
pub fn emit<T: ?Sized>(&self, packet: &mut Packet<&mut T>,
src_addr: &InternetAddress,
dst_addr: &InternetAddress)
where T: AsRef<[u8]> + AsMut<[u8]> {
packet.set_src_port(self.src_port);
packet.set_dst_port(self.dst_port);
packet.set_len((field::PAYLOAD.start + self.payload.len()) as u16);
packet.payload_mut().copy_from_slice(self.payload);
packet.fill_checksum(src_addr, dst_addr)
}
}
impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&'a T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Cannot use Repr::parse because we don't have the IP addresses.
write!(f, "UDP src={} dst={} len={}",
self.src_port(), self.dst_port(), self.payload().len())
}
}
impl<'a> fmt::Display for Repr<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "UDP src={} dst={} len={}",
self.src_port, self.dst_port, self.payload.len())
}
}
use super::pretty_print::{PrettyPrint, PrettyIndent};
impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
fn pretty_print(buffer: &AsRef<[u8]>, f: &mut fmt::Formatter,
indent: &mut PrettyIndent) -> fmt::Result {
match Packet::new(buffer) {
Err(err) => write!(f, "{}({})\n", indent, err),
Ok(packet) => write!(f, "{}{}\n", indent, packet)
}
}
}
#[cfg(test)]
mod test {
use wire::Ipv4Address;
use super::*;
const SRC_ADDR: Ipv4Address = Ipv4Address([192, 168, 1, 1]);
const DST_ADDR: Ipv4Address = Ipv4Address([192, 168, 1, 2]);
static PACKET_BYTES: [u8; 12] =
[0xbf, 0x00, 0x00, 0x35,
0x00, 0x0c, 0x95, 0xbe,
0x00, 0x0c, 0x12, 0x4d,
0xaa, 0x00, 0x00, 0xff];
static PAYLOAD_BYTES: [u8; 4] =
@ -153,9 +256,9 @@ mod test {
assert_eq!(packet.src_port(), 48896);
assert_eq!(packet.dst_port(), 53);
assert_eq!(packet.len(), 12);
assert_eq!(packet.checksum(), 0x95be);
assert_eq!(packet.checksum(), 0x124d);
assert_eq!(packet.payload(), &PAYLOAD_BYTES[..]);
assert_eq!(packet.verify_checksum(), true);
assert_eq!(packet.verify_checksum(&SRC_ADDR.into(), &DST_ADDR.into()), true);
}
#[test]
@ -167,7 +270,30 @@ mod test {
packet.set_len(12);
packet.set_checksum(0xffff);
packet.payload_mut().copy_from_slice(&PAYLOAD_BYTES[..]);
packet.fill_checksum();
packet.fill_checksum(&SRC_ADDR.into(), &DST_ADDR.into());
assert_eq!(&packet.into_inner()[..], &PACKET_BYTES[..]);
}
fn packet_repr() -> Repr<'static> {
Repr {
src_port: 48896,
dst_port: 53,
payload: &PAYLOAD_BYTES
}
}
#[test]
fn test_parse() {
let packet = Packet::new(&PACKET_BYTES[..]).unwrap();
let repr = Repr::parse(&packet, &SRC_ADDR.into(), &DST_ADDR.into()).unwrap();
assert_eq!(repr, packet_repr());
}
#[test]
fn test_emit() {
let mut bytes = vec![0; 12];
let mut packet = Packet::new(&mut bytes).unwrap();
packet_repr().emit(&mut packet, &SRC_ADDR.into(), &DST_ADDR.into());
assert_eq!(&packet.into_inner()[..], &PACKET_BYTES[..]);
}
}