extern crate byteorder;
use self::byteorder::{ByteOrder, BigEndian, ReadBytesExt, WriteBytesExt};
use std::io;
#[derive(Debug, PartialEq)]
pub enum EtherType {
Ipv4 = 0x0800,
Ipv6 = 0x86dd,
Arp = 0x0806,
WakeOnLan = 0x0842,
VlanTaggedFrame = 0x8100,
VlanDoubleTaggedFrame = 0x9100
}
impl EtherType {
pub fn from_u16(value: u16) -> Option<EtherType> {
use EtherType::*;
match value {
0x0800 => Some(Ipv4),
0x86dd => Some(Ipv6),
0x0806 => Some(Arp),
0x0842 => Some(WakeOnLan),
0x8100 => Some(VlanTaggedFrame),
0x9100 => Some(VlanDoubleTaggedFrame),
_ => None
}
}
}
#[derive(Debug, PartialEq)]
pub struct Ethernet2Header {
pub destination: [u8;6],
pub source: [u8;6],
pub ether_type: u16
}
#[derive(Debug, PartialEq)]
pub enum IpHeader {
Version4(Ipv4Header),
Version6(Ipv6Header)
}
#[derive(Debug, PartialEq)]
pub struct Ipv4Header {
pub header_length: u8,
pub differentiated_services_code_point: u8,
pub explicit_congestion_notification: u8,
pub total_length: u16,
pub identification: u16,
pub dont_fragment: bool,
pub more_fragments: bool,
pub fragments_offset: u16,
pub time_to_live: u8,
pub protocol: u8,
pub header_checksum: u16,
pub source: [u8;4],
pub destination: [u8;4]
}
#[derive(Debug, PartialEq)]
pub struct Ipv6Header {
pub traffic_class: u8,
pub flow_label: u32,
pub payload_length: u16,
pub next_header: u8,
pub hop_limit: u8,
pub source: [u8;16],
pub destination: [u8;16]
}
#[derive(Debug)]
pub enum ReadError {
IoError(io::Error),
IpUnsupportedVersion(u8),
Ipv4UnexpectedVersion(u8),
Ipv6UnexpectedVersion(u8),
Ipv6TooManyHeaderExtensions
}
impl From<io::Error> for ReadError {
fn from(err: io::Error) -> ReadError {
ReadError::IoError(err)
}
}
#[derive(Debug)]
pub enum WriteError {
IoError(io::Error),
ValueU8TooLarge{value: u8, max: u8, field: ErrorField},
ValueU16TooLarge{value: u16, max: u16, field: ErrorField},
ValueU32TooLarge{value: u32, max: u32, field: ErrorField}
}
impl From<io::Error> for WriteError {
fn from(err: io::Error) -> WriteError {
WriteError::IoError(err)
}
}
#[derive(Debug)]
pub enum ErrorField {
Ipv4HeaderLength,
Ipv4Dscp,
Ipv4Ecn,
Ipv4FragmentsOffset,
Ipv6FlowLabel
}
pub trait WriteEtherExt: io::Write {
fn write_ethernet2_header(&mut self, value: &Ethernet2Header) -> Result<(), io::Error> {
self.write_all(&value.destination)?;
self.write_all(&value.source)?;
self.write_u16::<BigEndian>(value.ether_type)?;
Ok(())
}
fn write_ipv4_header(&mut self, value: &Ipv4Header) -> Result<(), WriteError> {
use WriteError::*;
use ErrorField::*;
fn max_check_u8(value: u8, max: u8, field: ErrorField) -> Result<(), WriteError> {
if value <= max {
Ok(())
} else {
Err(ValueU8TooLarge{ value: value, max: max, field: field })
}
};
fn max_check_u16(value: u16, max: u16, field: ErrorField) -> Result<(), WriteError> {
if value <= max {
Ok(())
} else {
Err(ValueU16TooLarge{ value: value, max: max, field: field })
}
};
max_check_u8(value.header_length, 0xf, Ipv4HeaderLength)?;
self.write_u8((4 << 4) | value.header_length)?;
max_check_u8(value.differentiated_services_code_point, 0x3f, Ipv4Dscp)?;
max_check_u8(value.explicit_congestion_notification, 0x3, Ipv4Ecn)?;
self.write_u8((value.differentiated_services_code_point << 2) | value.explicit_congestion_notification)?;
self.write_u16::<BigEndian>(value.total_length)?;
self.write_u16::<BigEndian>(value.identification)?;
max_check_u16(value.fragments_offset, 0x1fff, Ipv4FragmentsOffset)?;
{
let mut buf: [u8;2] = [0;2];
BigEndian::write_u16(&mut buf, value.fragments_offset);
let flags = {
let mut result = 0;
if value.dont_fragment {
result = result | 64;
}
if value.more_fragments {
result = result | 32;
}
result
};
self.write_u8(
flags |
(buf[0] & 0x1f),
)?;
self.write_u8(
buf[1]
)?;
}
self.write_u8(value.time_to_live)?;
self.write_u8(value.protocol)?;
self.write_u16::<BigEndian>(value.header_checksum)?;
self.write_all(&value.source)?;
self.write_all(&value.destination)?;
Ok(())
}
fn write_ipv6_header(&mut self, value: &Ipv6Header) -> Result<(), WriteError> {
use WriteError::*;
use ErrorField::*;
fn max_check_u32(value: u32, max: u32, field: ErrorField) -> Result<(), WriteError> {
if value <= max {
Ok(())
} else {
Err(ValueU32TooLarge{ value: value, max: max, field: field })
}
};
self.write_u8((6 << 4) | (value.traffic_class >> 4))?;
max_check_u32(value.flow_label, 0xfffff, Ipv6FlowLabel)?;
{
let mut buffer: [u8; 4] = [0;4];
byteorder::BigEndian::write_u32(&mut buffer, value.flow_label);
buffer[1] = buffer[1] | (value.traffic_class << 4);
self.write_all(&buffer[1..])?;
}
self.write_u16::<BigEndian>(value.payload_length)?;
self.write_u8(value.next_header)?;
self.write_u8(value.hop_limit)?;
self.write_all(&value.source)?;
self.write_all(&value.destination)?;
Ok(())
}
}
impl<W: io::Write + ?Sized> WriteEtherExt for W {}
pub trait ReadEtherExt: io::Read + io::Seek {
fn read_ethernet2_header(&mut self) -> Result<Ethernet2Header, io::Error> {
Ok(Ethernet2Header {
destination: self.read_mac_address()?,
source: self.read_mac_address()?,
ether_type: self.read_u16::<BigEndian>()?
})
}
fn read_ip_header(&mut self) -> Result<IpHeader, ReadError> {
let value = self.read_u8()?;
match value >> 4 {
4 => Ok(IpHeader::Version4(self.read_ipv4_header_without_version(value & 0xf)?)),
6 => Ok(IpHeader::Version6(self.read_ipv6_header_without_version(value & 0xf)?)),
version => Err(ReadError::IpUnsupportedVersion(version))
}
}
fn read_ipv4_header(&mut self) -> Result<Ipv4Header, ReadError> {
let value = self.read_u8()?;
let version = value >> 4;
if 4 != version {
return Err(ReadError::Ipv4UnexpectedVersion(version));
}
self.read_ipv4_header_without_version(value & 0xf)
}
fn read_ipv4_header_without_version(&mut self, version_rest: u8) -> Result<Ipv4Header, ReadError> {
let ihl = version_rest;
let (dscp, ecn) = {
let value = self.read_u8()?;
(value >> 2, value & 0x3)
};
let total_length = self.read_u16::<BigEndian>()?;
let identification = self.read_u16::<BigEndian>()?;
let (dont_fragment, more_fragments, fragments_offset) = {
let mut values: [u8; 2] = [0;2];
self.read_exact(&mut values)?;
(0 != (values[0] & 0x40),
0 != (values[0] & 0x20),
{
let buf = [values[0] & 0x1f, values[1]];
let mut cursor = io::Cursor::new(&buf);
cursor.read_u16::<BigEndian>()?
})
};
Ok(Ipv4Header{
differentiated_services_code_point: dscp,
explicit_congestion_notification: ecn,
total_length: total_length,
identification: identification,
dont_fragment: dont_fragment,
more_fragments: more_fragments,
fragments_offset: fragments_offset,
time_to_live: self.read_u8()?,
protocol: self.read_u8()?,
header_checksum: self.read_u16::<BigEndian>()?,
source: {
let mut values: [u8;4] = [0;4];
self.read_exact(&mut values)?;
values
},
destination: {
let mut values: [u8;4] = [0;4];
self.read_exact(&mut values)?;
values
},
header_length: ihl
})
}
fn read_ipv6_header(&mut self) -> Result<Ipv6Header, ReadError> {
let value = self.read_u8()?;
let version = value >> 4;
if 6 != version {
return Err(ReadError::Ipv6UnexpectedVersion(version));
}
self.read_ipv6_header_without_version(value & 0xf)
}
fn read_ipv6_header_without_version(&mut self, version_rest: u8) -> Result<Ipv6Header, ReadError> {
let (traffic_class, flow_label) = {
let mut buffer: [u8; 4] = [0;4];
self.read_exact(&mut buffer[1..])?;
let traffic_class = (version_rest << 4) | (buffer[1] >> 4);
buffer[1] = buffer[1] & 0xf;
(traffic_class, byteorder::BigEndian::read_u32(&buffer))
};
Ok(Ipv6Header{
traffic_class: traffic_class,
flow_label: flow_label,
payload_length: self.read_u16::<BigEndian>()?,
next_header: self.read_u8()?,
hop_limit: self.read_u8()?,
source: {
let mut buffer: [u8; 16] = [0;16];
self.read_exact(&mut buffer)?;
buffer
},
destination: {
let mut buffer: [u8; 16] = [0;16];
self.read_exact(&mut buffer)?;
buffer
}
})
}
fn skip_ipv6_header_extension(&mut self) -> Result<u8, ReadError> {
let next_header = self.read_u8()?;
let rest_length = ((self.read_u8()? as i64)*8) + 8 - 2;
self.seek(io::SeekFrom::Current(rest_length))?;
Ok(next_header)
}
fn skip_all_ipv6_header_extensions(&mut self, traffic_class: u8) -> Result<u8, ReadError> {
use IpTrafficClass::*;
const HOP_BY_HOP: u8 = IPv6HeaderHopByHop as u8;
const ROUTE: u8 = IPv6RouteHeader as u8;
const FRAG: u8 = IPv6FragmentationHeader as u8;
const OPTIONS: u8 = IPv6DestinationOptions as u8;
const AUTH: u8 = IPv6AuthenticationHeader as u8;
const ENCAP_SEC: u8 = IPv6EncapSecurityPayload as u8;
let mut next_traffic_class = traffic_class;
for _i in 0..7 {
match next_traffic_class {
HOP_BY_HOP | ROUTE | FRAG | OPTIONS | AUTH | ENCAP_SEC => {
next_traffic_class = self.skip_ipv6_header_extension()?;
},
_ => return Ok(next_traffic_class)
}
}
match next_traffic_class {
HOP_BY_HOP | ROUTE | FRAG | OPTIONS | AUTH | ENCAP_SEC => Err(ReadError::Ipv6TooManyHeaderExtensions),
value => Ok(value)
}
}
fn read_mac_address(&mut self) -> Result<[u8;6], io::Error> {
let mut result: [u8;6] = [0;6];
self.read_exact(&mut result)?;
Ok(result)
}
}
impl<W: io::Read + io::Seek + ?Sized> ReadEtherExt for W {}
pub enum IpTrafficClass {
IPv6HeaderHopByHop = 0,
Icmp = 1,
Igmp = 2,
Ggp = 3,
IPv4 = 4,
Stream = 5,
Tcp = 6,
Cbt = 7,
Egp = 8,
Igp = 9,
BbnRccMon = 10,
NvpII = 11,
Pup = 12,
Argus = 13,
Emcon = 14,
Xnet = 15,
Chaos = 16,
Udp = 17,
Mux = 18,
DcnMeas = 19,
Hmp = 20,
Prm = 21,
XnsIdp = 22,
Trunk1 = 23,
Trunk2 = 24,
Leaf1 = 25,
Leaf2 = 26,
Rdp = 27,
Irtp = 28,
IsoTp4 = 29,
NetBlt = 30,
MfeNsp = 31,
MeritInp = 32,
Dccp = 33,
ThirdPartyConnectProtocol = 34,
Idpr = 35,
Xtp = 36,
Ddp = 37,
IdprCmtp = 38,
TpPlusPlus = 39,
Il = 40,
Ipv6 = 41,
Sdrp = 42,
IPv6RouteHeader = 43,
IPv6FragmentationHeader = 44,
Idrp = 45,
Rsvp = 46,
Gre = 47,
Dsr = 48,
Bna = 49,
IPv6EncapSecurityPayload = 50,
IPv6AuthenticationHeader = 51,
Inlsp = 52,
Swipe = 53,
Narp = 54,
Mobile = 55,
Tlsp = 56,
Skip = 57,
IPv6Icmp = 58,
IPv6NoNextHeader = 59,
IPv6DestinationOptions = 60,
AnyHostInternalProtocol = 61,
Cftp = 62,
AnyLocalNetwork = 63,
SatExpak = 64,
Krytolan = 65,
Rvd = 66,
Ippc = 67,
AnyDistributedFileSystem = 68,
SatMon = 69,
Visa = 70,
Ipcv = 71,
Cpnx = 72,
Cphb = 73,
Wsn = 74,
Pvp = 75,
BrSatMon = 76,
SunNd = 77,
WbMon = 78,
WbExpak = 79,
IsoIp = 80,
Vmtp = 81,
SecureVmtp = 82,
Vines = 83,
TtpOrIptm = 84,
NsfnetIgp = 85,
Dgp = 86,
Tcf = 87,
Eigrp = 88,
Ospfigp = 89,
SpriteRpc = 90,
Larp = 91,
Mtp = 92,
Ax25 = 93,
Ipip = 94,
Micp = 95,
SccSp = 96,
EtherIp = 97,
Encap = 98,
Gmtp = 100,
Ifmp = 101,
Pnni = 102,
Pim = 103,
Aris = 104,
Scps = 105,
Qnx = 106,
ActiveNetworks = 107,
IpComp = 108,
SitraNetworksProtocol = 109,
CompaqPeer = 110,
IpxInIp = 111,
Vrrp = 112,
Pgm = 113,
AnyZeroHopProtocol = 114,
Layer2TunnelingProtocol = 115,
Ddx = 116,
Iatp = 117,
Stp = 118,
Srp = 119,
Uti = 120,
SimpleMessageProtocol = 121,
Sm = 122,
Ptp = 123,
IsisOverIpv4 = 124,
Fire = 125,
Crtp = 126,
Crudp = 127,
Sscopmce = 128,
Iplt = 129,
Sps = 130,
Pipe = 131,
Sctp = 132,
Fc = 133,
RsvpE2eIgnore = 134,
MobilityHeader = 135,
UdpLite = 136,
MplsInIp = 137,
Manet = 138,
Hip = 139,
Shim6 = 140,
Wesp = 141,
Rohc = 142
}
#[cfg(test)]
mod tests {
#[test]
fn ether_test_convert() {
use super::*;
use EtherType::*;
assert_eq!(0x0800, Ipv4 as u16);
assert_eq!(0x86dd, Ipv6 as u16);
assert_eq!(0x0806, Arp as u16);
assert_eq!(0x0842, WakeOnLan as u16);
assert_eq!(0x8100, VlanTaggedFrame as u16);
assert_eq!(0x9100, VlanDoubleTaggedFrame as u16);
assert_eq!(EtherType::from_u16(0x0800), Some(Ipv4));
assert_eq!(EtherType::from_u16(0x86dd), Some(Ipv6));
assert_eq!(EtherType::from_u16(0x0806), Some(Arp));
assert_eq!(EtherType::from_u16(0x0842), Some(WakeOnLan));
assert_eq!(EtherType::from_u16(0x8100), Some(VlanTaggedFrame));
assert_eq!(EtherType::from_u16(0x9100), Some(VlanDoubleTaggedFrame));
}
#[test]
fn readwrite_ethernet2_header() {
use super::*;
use std::io::Cursor;
let input = Ethernet2Header{
destination: [1,2,3,4,5,6],
source: [10,11,12,13,14,15],
ether_type: 0x0800
};
let mut buffer: Vec<u8> = Vec::with_capacity(14);
buffer.write_ethernet2_header(&input).unwrap();
let result = {
let mut cursor = Cursor::new(&buffer);
cursor.read_ethernet2_header().unwrap()
};
assert_eq!(input, result);
}
#[test]
fn read_ip_header_ipv4() {
use super::*;
use std::io::Cursor;
let input = Ipv4Header {
header_length: 10,
differentiated_services_code_point: 42,
explicit_congestion_notification: 3,
total_length: 1234,
identification: 4321,
dont_fragment: true,
more_fragments: false,
fragments_offset: 4367,
time_to_live: 8,
protocol: 1,
header_checksum: 2345,
source: [192, 168, 1, 1],
destination: [212, 10, 11, 123]
};
let mut buffer: Vec<u8> = Vec::with_capacity(20);
buffer.write_ipv4_header(&input).unwrap();
match {
let mut cursor = Cursor::new(&buffer);
cursor.read_ip_header().unwrap()
} {
IpHeader::Version4(result) => assert_eq!(input, result),
value => assert!(false, format!("Expected IpHeaderV4 but received {:?}", value))
}
}
#[test]
fn read_ip_header_ipv6() {
use super::*;
use std::io::Cursor;
let input = Ipv6Header {
traffic_class: 1,
flow_label: 0x81806,
payload_length: 0x8021,
next_header: 30,
hop_limit: 40,
source: [1, 2, 3, 4, 5, 6, 7, 8,
9,10,11,12,13,14,15,16],
destination: [21,22,23,24,25,26,27,28,
29,30,31,32,33,34,35,36]
};
let mut buffer: Vec<u8> = Vec::with_capacity(20);
buffer.write_ipv6_header(&input).unwrap();
match {
let mut cursor = Cursor::new(&buffer);
cursor.read_ip_header().unwrap()
} {
IpHeader::Version6(result) => assert_eq!(input, result),
value => assert!(false, format!("Expected IpHeaderV6 but received {:?}", value))
}
}
#[test]
fn readwrite_ipv4_header() {
use super::*;
use std::io::Cursor;
let input = Ipv4Header {
header_length: 10,
differentiated_services_code_point: 42,
explicit_congestion_notification: 3,
total_length: 1234,
identification: 4321,
dont_fragment: true,
more_fragments: false,
fragments_offset: 4367,
time_to_live: 8,
protocol: 1,
header_checksum: 2345,
source: [192, 168, 1, 1],
destination: [212, 10, 11, 123]
};
let mut buffer: Vec<u8> = Vec::with_capacity(20);
buffer.write_ipv4_header(&input).unwrap();
let result = {
let mut cursor = Cursor::new(&buffer);
cursor.read_ipv4_header().unwrap()
};
assert_eq!(input, result);
}
#[test]
fn write_ipv4_header_errors() {
use super::*;
use super::WriteError::*;
use super::ErrorField::*;
fn base() -> Ipv4Header {
Ipv4Header{
header_length: 10,
differentiated_services_code_point: 42,
explicit_congestion_notification: 3,
total_length: 1234,
identification: 4321,
dont_fragment: true,
more_fragments: false,
fragments_offset: 4367,
time_to_live: 8,
protocol: 1,
header_checksum: 2345,
source: [192, 168, 1, 1],
destination: [212, 10, 11, 123]
}
};
fn test_write(input: &Ipv4Header) -> Result<(), WriteError> {
let mut buffer: Vec<u8> = Vec::with_capacity(20);
buffer.write_ipv4_header(input)
};
match test_write(&{
let mut value = base();
value.header_length = 0x1f;
value
}) {
Err(ValueU8TooLarge{value: 0x1f, max: 0xf, field: Ipv4HeaderLength}) => {}, value => assert!(false, format!("Expected a range error but received {:?}", value))
}
match test_write(&{
let mut value = base();
value.differentiated_services_code_point = 0x40;
value
}) {
Err(ValueU8TooLarge{value: 0x40, max: 0x3f, field: Ipv4Dscp}) => {}, value => assert!(false, format!("Expected a range error but received {:?}", value))
}
match test_write(&{
let mut value = base();
value.explicit_congestion_notification = 0x4;
value
}) {
Err(ValueU8TooLarge{value: 0x4, max: 0x3, field: Ipv4Ecn}) => {}, value => assert!(false, format!("Expected a range error but received {:?}", value))
}
match test_write(&{
let mut value = base();
value.fragments_offset = 0x2000;
value
}) {
Err(ValueU16TooLarge{value: 0x2000, max: 0x1FFF, field: Ipv4FragmentsOffset}) => {}, value => assert!(false, format!("Expected a range error but received {:?}", value))
}
}
#[test]
fn read_ipv4_error_header() {
use super::*;
let buffer: [u8;20] = [0;20];
let mut cursor = io::Cursor::new(&buffer);
let result = cursor.read_ipv4_header();
match result {
Err(ReadError::Ipv4UnexpectedVersion(0)) => {},
_ => assert!(false, format!("Expected ipv 4 version error but received {:?}", result))
}
}
#[test]
fn readwrite_ipv6_header() {
use super::*;
use std::io::Cursor;
let input = Ipv6Header {
traffic_class: 1,
flow_label: 0x81806,
payload_length: 0x8021,
next_header: 30,
hop_limit: 40,
source: [1, 2, 3, 4, 5, 6, 7, 8,
9,10,11,12,13,14,15,16],
destination: [21,22,23,24,25,26,27,28,
29,30,31,32,33,34,35,36]
};
let mut buffer: Vec<u8> = Vec::with_capacity(20);
buffer.write_ipv6_header(&input).unwrap();
let result = {
let mut cursor = Cursor::new(&buffer);
cursor.read_ipv6_header().unwrap()
};
assert_eq!(input, result);
}
#[test]
fn write_ipv6_header_errors() {
use super::*;
use super::WriteError::*;
use super::ErrorField::*;
fn base() -> Ipv6Header {
Ipv6Header {
traffic_class: 1,
flow_label: 0x201806,
payload_length: 0x8021,
next_header: 30,
hop_limit: 40,
source: [1, 2, 3, 4, 5, 6, 7, 8,
9,10,11,12,13,14,15,16],
destination: [21,22,23,24,25,26,27,28,
29,30,31,32,33,34,35,36]
}
};
fn test_write(input: &Ipv6Header) -> Result<(), WriteError> {
let mut buffer: Vec<u8> = Vec::with_capacity(20);
buffer.write_ipv6_header(input)
};
match test_write(&{
let mut value = base();
value.flow_label = 0x100000;
value
}) {
Err(ValueU32TooLarge{value: 0x100000, max: 0xFFFFF, field: Ipv6FlowLabel}) => {}, value => assert!(false, format!("Expected a range error but received {:?}", value))
}
}
#[test]
fn read_ipv6_error_header() {
use super::*;
let buffer: [u8;20] = [0;20];
let mut cursor = io::Cursor::new(&buffer);
let result = cursor.read_ipv6_header();
match result {
Err(ReadError::Ipv6UnexpectedVersion(0)) => {},
_ => assert!(false, format!("Expected ipv 6 version error but received {:?}", result))
}
}
#[test]
fn skip_ipv6_header_extension() {
use super::*;
use std::io::Cursor;
{
let buffer: [u8; 8] = [0;8];
let mut cursor = Cursor::new(&buffer);
match cursor.skip_ipv6_header_extension() {
Ok(0) => {},
value => assert!(false, format!("Expected Ok(0) but received {:?}", value))
}
assert_eq!(8, cursor.position());
}
{
let buffer: [u8; 8*3] = [
4,2,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0,
];
let mut cursor = Cursor::new(&buffer);
match cursor.skip_ipv6_header_extension() {
Ok(4) => {},
value => assert!(false, format!("Expected Ok(4) but received {:?}", value))
}
assert_eq!(8*3, cursor.position());
}
}
#[test]
fn skip_all_ipv6_header_extensions() {
use super::*;
use io::Cursor;
use IpTrafficClass::*;
const EXTENSION_IDS: [u8;7] = [
IPv6HeaderHopByHop as u8,
IPv6DestinationOptions as u8,
IPv6RouteHeader as u8,
IPv6FragmentationHeader as u8,
IPv6AuthenticationHeader as u8,
IPv6EncapSecurityPayload as u8,
IPv6DestinationOptions as u8
];
const UDP: u8 = Udp as u8;
{
let buffer: [u8; 8*3] = [
UDP,2,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0,
];
for i_as16 in 0..((u8::max_value() as u16) + 1) {
let i = i_as16 as u8; let mut cursor = Cursor::new(&buffer);
let result = cursor.skip_all_ipv6_header_extensions(i);
match EXTENSION_IDS.iter().find(|&&x| x == i) {
Some(_) => {
match result {
Ok(UDP) => {},
_ => assert!(false, format!("exepected udp as next traffic_class but received {:?}", result))
}
assert_eq!(buffer.len(), cursor.position() as usize);
},
None => {
match result {
Ok(next) => assert_eq!(i, next),
_ => assert!(false, format!("exepected {} as next traffic_class but received {:?}", i, result))
}
assert_eq!(0, cursor.position());
}
}
}
}
{
let buffer = vec![
EXTENSION_IDS[1],0,0,0, 0,0,0,0,
EXTENSION_IDS[2],1,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0,
EXTENSION_IDS[3],0,0,0, 0,0,0,0,
EXTENSION_IDS[4],1,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0,
EXTENSION_IDS[5],0,0,0, 0,0,0,0,
EXTENSION_IDS[6],0,0,0, 0,0,0,0,
UDP,2,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0,
];
let mut cursor = Cursor::new(&buffer);
let result = cursor.skip_all_ipv6_header_extensions(EXTENSION_IDS[0]);
match result {
Ok(UDP) => {},
result => assert!(false, format!("exepected udp as next traffic_class but received {:?}", result))
}
assert_eq!(buffer.len(), cursor.position() as usize);
}
{
let buffer = vec![
EXTENSION_IDS[1],0,0,0, 0,0,0,0,
EXTENSION_IDS[2],0,0,0, 0,0,0,0,
EXTENSION_IDS[3],0,0,0, 0,0,0,0,
EXTENSION_IDS[4],0,0,0, 0,0,0,0,
EXTENSION_IDS[5],0,0,0, 0,0,0,0,
EXTENSION_IDS[6],0,0,0, 0,0,0,0,
EXTENSION_IDS[1],0,0,0, 0,0,0,0,
];
let mut cursor = Cursor::new(&buffer);
let result = cursor.skip_all_ipv6_header_extensions(EXTENSION_IDS[0]);
match result {
Err(ReadError::Ipv6TooManyHeaderExtensions) => {},
result => assert!(false, format!("exepected error Ipv6TooManyHeaderExtensions but received {:?}", result))
}
}
}
}