use super::super::*;
use std;
use std::io;
use std::io::Write;
use proptest::prelude::*;
proptest! {
#[test]
fn ipv4_new(source_ip in prop::array::uniform4(any::<u8>()),
dest_ip in prop::array::uniform4(any::<u8>()),
ttl in any::<u8>(),
payload_and_options_length in 0u16..(std::u16::MAX - 20))
{
let result = Ipv4Header::new(payload_and_options_length as usize,
ttl,
IpTrafficClass::Udp,
source_ip,
dest_ip);
assert_eq!(Ipv4Header {
header_length: 0,
differentiated_services_code_point: 0,
explicit_congestion_notification: 0,
total_length: payload_and_options_length + 20,
identification: 0,
dont_fragment: true,
more_fragments: false,
fragments_offset: 0,
time_to_live: ttl,
protocol: IpTrafficClass::Udp as u8,
header_checksum: 0,
source: source_ip,
destination: dest_ip
}, result.unwrap());
}
}
#[test]
fn ipv4_new_error() {
assert_matches!(Ipv4Header::new(
(std::u16::MAX as usize) - 20,
4,
IpTrafficClass::Udp,
[1,2,3,4],
[5,6,7,8]
),
Ok(_));
const TOO_LARGE_PAYLOAD: usize = (std::u16::MAX as usize) - 19;
assert_matches!(Ipv4Header::new(
(std::u16::MAX as usize) - 19,
4,
IpTrafficClass::Udp,
[1,2,3,4],
[5,6,7,8]
),
Err(ValueError::Ipv4PayloadAndOptionsLengthTooLarge(TOO_LARGE_PAYLOAD)));
}
#[test]
fn ipv4_calc_header_checksum() {
{
let header = Ipv4Header {
header_length: 5,
differentiated_services_code_point: 0,
explicit_congestion_notification: 0,
total_length: 40 + 20,
identification: 0,
dont_fragment: true,
more_fragments: false,
fragments_offset: 0,
time_to_live: 4,
protocol: IpTrafficClass::Udp as u8,
header_checksum: 0,
source: [192, 168, 1, 1],
destination: [212, 10, 11, 123]
};
assert_eq!(0xd582, header.calc_header_checksum(&[]).unwrap());
let header = Ipv4Header {
header_length: 5,
differentiated_services_code_point: 0,
explicit_congestion_notification: 0,
total_length: 40 + 20,
identification: 0,
dont_fragment: false,
more_fragments: true,
fragments_offset: 0,
time_to_live: 4,
protocol: IpTrafficClass::Udp as u8,
header_checksum: 0,
source: [192, 168, 1, 1],
destination: [212, 10, 11, 123]
};
assert_eq!(0xf582, header.calc_header_checksum(&[]).unwrap());
}
{
let header = Ipv4Header {
header_length: 7,
differentiated_services_code_point: 0,
explicit_congestion_notification: 0,
total_length: 40 + 20,
identification: 0,
dont_fragment: true,
more_fragments: false,
fragments_offset: 0,
time_to_live: 4,
protocol: IpTrafficClass::Udp as u8,
header_checksum: 0,
source: [192, 168, 1, 1],
destination: [212, 10, 11, 123]
};
assert_eq!(0xc36e, header.calc_header_checksum(&[1,2,3,4,5,6,7,8]).unwrap());
}
}
#[test]
fn ipv4_calc_header_checksum_errors() {
use ValueError::*;
use ErrorField::*;
{
{
let mut header = Ipv4Header::new(15, 4, IpTrafficClass::Udp, [1,2,3,4], [5,6,7,8]).unwrap();
header.header_length = 0x10;
assert_matches!(header.calc_header_checksum(&[]),
Err(U8TooLarge{value: 0x10, max: 0xf, field: Ipv4HeaderLength}));
}
{
let mut header = Ipv4Header::new(15, 4, IpTrafficClass::Udp, [1,2,3,4], [5,6,7,8]).unwrap();
header.differentiated_services_code_point = 0x40;
assert_matches!(header.calc_header_checksum(&[]),
Err(U8TooLarge{value: 0x40, max: 0x3f, field: Ipv4Dscp}));
}
{
let mut header = Ipv4Header::new(15, 4, IpTrafficClass::Udp, [1,2,3,4], [5,6,7,8]).unwrap();
header.explicit_congestion_notification = 0x4;
assert_matches!(header.calc_header_checksum(&[]),
Err(U8TooLarge{value: 0x4, max: 0x3, field: Ipv4Ecn}));
}
{
let mut header = Ipv4Header::new(15, 4, IpTrafficClass::Udp, [1,2,3,4], [5,6,7,8]).unwrap();
header.fragments_offset = 0x2000;
assert_matches!(header.calc_header_checksum(&[]),
Err(U16TooLarge{value: 0x2000, max: 0x1fff, field: Ipv4FragmentsOffset}));
}
{
let header = Ipv4Header::new(15, 4, IpTrafficClass::Udp, [1,2,3,4], [5,6,7,8]).unwrap();
let options = vec![0;9]; assert_matches!(header.calc_header_checksum(&options),
Err(Ipv4OptionsLengthBad(9)));
}
{
let header = Ipv4Header::new(15, 4, IpTrafficClass::Udp, [1,2,3,4], [5,6,7,8]).unwrap();
let options = vec![0;11*4]; assert_matches!(header.calc_header_checksum(&options),
Err(Ipv4OptionsLengthBad(44)));
}
}
}
#[test]
fn readwrite_ip_header() {
use std::io::Cursor;
let inputs = [
IpHeader::Version4(Ipv4Header {
header_length: 5,
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: 43617,
source: [192, 168, 1, 1],
destination: [212, 10, 11, 123]
}),
IpHeader::Version4(Ipv4Header {
header_length: 5,
differentiated_services_code_point: 42,
explicit_congestion_notification: 3,
total_length: 1234,
identification: 4321,
dont_fragment: false,
more_fragments: true,
fragments_offset: 4367,
time_to_live: 8,
protocol: 1,
header_checksum: 51809,
source: [192, 168, 1, 1],
destination: [212, 10, 11, 123]
}),
IpHeader::Version6(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]
})
];
for input in &inputs {
let mut buffer: Vec<u8> = Vec::with_capacity(20);
input.write(&mut buffer).unwrap();
println!("{:?}", input);
match *input {
IpHeader::Version4(_) => assert_eq!(20, buffer.len()),
IpHeader::Version6(_) => assert_eq!(40, buffer.len())
}
let mut cursor = Cursor::new(&buffer);
let result = IpHeader::read(&mut cursor).unwrap();
match *input {
IpHeader::Version4(_) => assert_eq!(20, cursor.position()),
IpHeader::Version6(_) => assert_eq!(40, cursor.position())
}
assert_eq!(result, *input);
}
}
#[test]
fn read_ip_header_ipv6() {
use std::io::Cursor;
const INPUT: Ipv6Header = 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);
INPUT.write(&mut buffer).unwrap();
assert_eq!(40, buffer.len());
let mut cursor = Cursor::new(&buffer);
let result = IpHeader::read(&mut cursor).unwrap();
assert_eq!(40, cursor.position());
assert_matches!(result, IpHeader::Version6(INPUT));
}
#[test]
fn read_ip_header_error() {
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);
input.write(&mut buffer).unwrap();
assert_eq!(40, buffer.len());
buffer[0] = 0xff;
let mut cursor = Cursor::new(&buffer);
assert_matches!(IpHeader::read(&mut cursor), Err(ReadError::IpUnsupportedVersion(0xf)));
}
proptest! {
#[test]
fn readwrite_ipv4_header_raw(ref input in ipv4_any())
{
use std::io::Cursor;
let expected_size = Ipv4Header::SERIALIZED_SIZE + input.1.len();
let mut buffer: Vec<u8> = Vec::with_capacity(expected_size);
input.0.write_raw(&mut buffer, &[]).unwrap();
buffer.write(&input.1).unwrap();
assert_eq!(expected_size, buffer.len());
let mut cursor = Cursor::new(&buffer);
let result = Ipv4Header::read(&mut cursor).unwrap();
assert_eq!(20, cursor.position());
assert_eq!(input.0, result);
use std::net::Ipv4Addr;
let slice = Ipv4HeaderSlice::from_slice(&buffer[..]).unwrap();
assert_eq!(slice.version(), 4);
assert_eq!(slice.ihl(), input.0.header_length);
assert_eq!(slice.dcp(), input.0.differentiated_services_code_point);
assert_eq!(slice.ecn(), input.0.explicit_congestion_notification);
assert_eq!(slice.total_length(), input.0.total_length);
assert_eq!(slice.identification(), input.0.identification);
assert_eq!(slice.dont_fragment(), input.0.dont_fragment);
assert_eq!(slice.more_fragments(), input.0.more_fragments);
assert_eq!(slice.fragments_offset(), input.0.fragments_offset);
assert_eq!(slice.ttl(), input.0.time_to_live);
assert_eq!(slice.protocol(), input.0.protocol);
assert_eq!(slice.header_checksum(), input.0.header_checksum);
assert_eq!(slice.source(), input.0.source);
assert_eq!(slice.source_addr(), Ipv4Addr::from(input.0.source));
assert_eq!(slice.destination(), input.0.destination);
assert_eq!(slice.destination_addr(), Ipv4Addr::from(input.0.destination));
assert_eq!(slice.to_header(), input.0);
assert_eq!(slice.options(), &input.1[..]);
}
}
#[test]
fn ipv4_slice_bad_ihl() {
let input = Ipv4Header {
header_length:4,
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);
input.write_raw(&mut buffer, &[]).unwrap();
use ReadError::*;
assert_matches!(Ipv4HeaderSlice::from_slice(&buffer[..]), Err(Ipv4HeaderLengthBad(4)));
}
#[test]
fn ipv4_slice_bad_version() {
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);
input.write(&mut buffer).unwrap();
use ReadError::*;
assert_matches!(Ipv4HeaderSlice::from_slice(&buffer[..]), Err(Ipv4UnexpectedVersion(6)));
}
#[test]
fn write_ipv4_raw_header_errors() {
use WriteError::ValueError;
use ValueError::*;
use 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::new();
let result = input.write_raw(&mut buffer, &[]);
assert_eq!(0, buffer.len());
result
};
{
let result = test_write(&{
let mut value = base();
value.header_length = 0x10;
value
});
assert_matches!(result, Err(ValueError(U8TooLarge{value: 0x10, max: 0xf, field: Ipv4HeaderLength})));
}
{
let result = test_write(&{
let mut value = base();
value.differentiated_services_code_point = 0x40;
value
});
assert_matches!(result, Err(ValueError(U8TooLarge{value: 0x40, max: 0x3f, field: Ipv4Dscp})));
}
{
let result = test_write(&{
let mut value = base();
value.explicit_congestion_notification = 0x4;
value
});
assert_matches!(result, Err(ValueError(U8TooLarge{value: 0x4, max: 0x3, field: Ipv4Ecn})));
}
{
let result = test_write(&{
let mut value = base();
value.fragments_offset = 0x2000;
value
});
assert_matches!(result, Err(ValueError(U16TooLarge{value: 0x2000, max: 0x1FFF, field: Ipv4FragmentsOffset})));
}
{
let mut buffer: Vec<u8> = Vec::new();
let result = base().write_raw(&mut buffer, &vec![0;44]);
assert_eq!(0, buffer.len());
assert_matches!(result, Err(ValueError(Ipv4OptionsLengthBad(44))));
}
}
#[test]
fn write_ipv4_header() {
use std::io::Cursor;
let mut input = Ipv4Header {
header_length: 0,
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: 0,
source: [192, 168, 1, 1],
destination: [212, 10, 11, 123]
};
let mut buffer: Vec<u8> = Vec::with_capacity(20);
input.write(&mut buffer, &[]).unwrap();
assert_eq!(20, buffer.len());
let mut cursor = Cursor::new(&buffer);
let result = Ipv4Header::read(&mut cursor).unwrap();
assert_eq!(20, cursor.position());
input.header_length = 5;
input.header_checksum = input.calc_header_checksum(&[]).unwrap();
assert_eq!(input, result);
}
#[test]
fn read_ipv4_error_header() {
{
let result = Ipv4Header::read(&mut io::Cursor::new(&[0;20]));
assert_matches!(result, Err(ReadError::Ipv4UnexpectedVersion(0)));
}
{
let result = Ipv4Header::read(&mut io::Cursor::new(&[0x40]));
assert_matches!(result, Err(ReadError::IoError(_)));
}
{
let result = Ipv4Header::read(&mut io::Cursor::new(&[0x40;19]));
assert_matches!(result, Err(ReadError::IoError(_)));
}
}
#[test]
fn skip_options() {
let header_with_length = |header_length: u8| {
Ipv4Header {
header_length: header_length,
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: 0,
source: [192, 168, 1, 1],
destination: [212, 10, 11, 123]
}
};
use std::io::Cursor;
use ReadError::*;
{
let mut cursor = Cursor::new(Vec::new());
assert_matches!(header_with_length(0).skip_options(&mut cursor),
Err(Ipv4HeaderLengthBad(0)));
}
{
let mut cursor = Cursor::new(Vec::new());
assert_matches!(header_with_length(4).skip_options(&mut cursor),
Err(Ipv4HeaderLengthBad(4)));
}
{
let mut cursor = Cursor::new(Vec::new());
assert_matches!(header_with_length(5).skip_options(&mut cursor),
Ok(()));
}
{
let mut cursor = Cursor::new(Vec::new());
assert_matches!(header_with_length(6).skip_options(&mut cursor),
Err(IoError(_)));
}
{
let mut cursor = Cursor::new(&[0;11]);
assert_matches!(header_with_length(8).skip_options(&mut cursor),
Err(IoError(_)));
}
{
let mut cursor = Cursor::new(&[0;12]);
assert_matches!(header_with_length(8).skip_options(&mut cursor),
Ok(()));
}
}
#[test]
fn write_ipv4_error_header() {
let input = Ipv4Header {
header_length: 0,
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: 0,
source: [192, 168, 1, 1],
destination: [212, 10, 11, 123]
};
{
let mut buffer: Vec<u8> = Vec::with_capacity(20);
let result = input.write(&mut buffer, &[1,2,3,4,5,6,7]);
assert_eq!(0, buffer.len());
use ValueError::Ipv4OptionsLengthBad;
assert_matches!(result, Err(WriteError::ValueError(Ipv4OptionsLengthBad(7))));
}
{
let mut buffer: Vec<u8> = Vec::with_capacity(20);
let result = input.write(&mut buffer, &[0;44]);
assert_eq!(0, buffer.len());
use ValueError::Ipv4OptionsLengthBad;
assert_matches!(result, Err(WriteError::ValueError(Ipv4OptionsLengthBad(44))));
}
}
#[test]
fn readwrite_ipv6_header() {
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);
input.write(&mut buffer).unwrap();
let result = Ipv6Header::read(&mut Cursor::new(&buffer)).unwrap();
assert_eq!(input, result);
}
#[test]
fn write_ipv6_header_errors() {
use WriteError::ValueError;
use ValueError::*;
use 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);
input.write(&mut buffer)
};
assert_matches!(
test_write(&{
let mut value = base();
value.flow_label = 0x100000;
value
}),
Err(ValueError(U32TooLarge{value: 0x100000, max: 0xFFFFF, field: Ipv6FlowLabel})));
}
#[test]
fn read_ipv6_error_header() {
{
let buffer: [u8;20] = [0;20];
let result = Ipv6Header::read(&mut io::Cursor::new(&buffer));
assert_matches!(result, Err(ReadError::Ipv6UnexpectedVersion(0)))
}
{
let buffer: [u8;1] = [0x60];
let result = Ipv6Header::read(&mut io::Cursor::new(&buffer));
assert_matches!(result, Err(ReadError::IoError(_)));
}
}
#[test]
fn skip_ipv6_header_extension() {
const HOP_BY_HOP: u8 = IpTrafficClass::IPv6HeaderHopByHop as u8;
const ROUTE: u8 = IpTrafficClass::IPv6RouteHeader as u8;
const FRAG: u8 = IpTrafficClass::IPv6FragmentationHeader as u8;
use std::io::Cursor;
{
let buffer: [u8; 8] = [0;8];
let mut cursor = Cursor::new(&buffer);
assert_matches!(Ipv6Header::skip_header_extension(&mut cursor, HOP_BY_HOP), Ok(0));
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);
assert_matches!(Ipv6Header::skip_header_extension(&mut cursor, ROUTE), Ok(4));
assert_eq!(8*3, 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);
assert_matches!(Ipv6Header::skip_header_extension(&mut cursor, FRAG), Ok(4));
assert_eq!(8, cursor.position());
}
}
#[test]
fn skip_all_ipv6_header_extensions() {
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 = Ipv6Header::skip_all_header_extensions(&mut cursor, i);
match EXTENSION_IDS.iter().find(|&&x| x == i) {
Some(_) => {
assert_matches!(result, Ok(UDP));
if i == IPv6FragmentationHeader as u8 {
assert_eq!(8, cursor.position() as usize);
} else {
assert_eq!(buffer.len(), cursor.position() as usize);
}
},
None => {
assert_matches!(result, Ok(next) => assert_eq!(i, next));
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],2,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0,
EXTENSION_IDS[4],5,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 = Ipv6Header::skip_all_header_extensions(&mut cursor, EXTENSION_IDS[0]);
assert_matches!(result, Ok(UDP));
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],4,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 = Ipv6Header::skip_all_header_extensions(&mut cursor, EXTENSION_IDS[0]);
assert_matches!(result, Err(ReadError::Ipv6TooManyHeaderExtensions));
}
{
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],2,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0,
EXTENSION_IDS[4],5,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
];
println!("buffer.len(). {}", buffer.len());
let mut cursor = Cursor::new(&buffer);
let result = Ipv6Header::skip_all_header_extensions(&mut cursor, EXTENSION_IDS[0]);
assert_matches!(result, Err(ReadError::IoError(_)));
}
}
#[test]
fn ipv4_set_payload_and_options_length() {
let mut header = Ipv4Header::new(0, 0, IpTrafficClass::Udp, [0;4], [0;4]).unwrap();
assert_matches!(header.set_payload_and_options_length(0), Ok(()));
assert_eq!(header.total_length, 20);
const MAX: usize = (std::u16::MAX as usize) - Ipv4Header::SERIALIZED_SIZE;
assert_matches!(header.set_payload_and_options_length(MAX), Ok(()));
assert_eq!(header.total_length, std::u16::MAX);
const OVER_MAX: usize = MAX + 1;
assert_matches!(header.set_payload_and_options_length(OVER_MAX),
Err(ValueError::Ipv4PayloadAndOptionsLengthTooLarge(OVER_MAX)));
}
#[test]
fn ipv6_set_payload_lengt() {
let mut header = Ipv6Header {
traffic_class: 0,
flow_label: 0,
payload_length: 0,
next_header: 0,
hop_limit: 0,
source: [0;16],
destination: [0;16]
};
assert_matches!(header.set_payload_length(0), Ok(()));
assert_eq!(header.payload_length, 0);
const MAX: usize = std::u16::MAX as usize;
assert_matches!(header.set_payload_length(MAX), Ok(()));
assert_eq!(header.payload_length, MAX as u16);
const OVER_MAX: usize = MAX + 1;
assert_matches!(header.set_payload_length(OVER_MAX),
Err(ValueError::Ipv6PayloadLengthTooLarge(OVER_MAX)));
}
proptest! {
#[test]
fn ipv6_from_slice(ref input in ipv6_any()) {
let mut buffer: Vec<u8> = Vec::with_capacity(20);
input.write(&mut buffer).unwrap();
assert_matches!(Ipv6HeaderSlice::from_slice(&buffer[..buffer.len()-1]), Err(ReadError::IoError(_)));
use std::net::Ipv6Addr;
let slice = Ipv6HeaderSlice::from_slice(&buffer).unwrap();
assert_eq!(slice.version(), 6);
assert_eq!(slice.traffic_class(), input.traffic_class);
assert_eq!(slice.flow_label(), input.flow_label);
assert_eq!(slice.payload_length(), input.payload_length);
assert_eq!(slice.next_header(), input.next_header);
assert_eq!(slice.hop_limit(), input.hop_limit);
assert_eq!(slice.source(), input.source);
assert_eq!(slice.source_addr(), Ipv6Addr::from(input.source));
assert_eq!(slice.destination(), input.destination);
assert_eq!(slice.destination_addr(), Ipv6Addr::from(input.destination));
assert_eq!(&slice.to_header(), input);
}
}
#[test]
fn ipv6_from_slice_bad_version() {
let input = Ipv4Header {
header_length:4,
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);
input.write_raw(&mut buffer, &[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]).unwrap();
use ReadError::*;
assert_matches!(Ipv6HeaderSlice::from_slice(&buffer[..]), Err(Ipv6UnexpectedVersion(4)));
}
#[test]
fn ipv6_extension_from_slice() {
use IpTrafficClass::*;
const FRAG: u8 = IPv6FragmentationHeader 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,
];
{
let slice = Ipv6ExtensionHeaderSlice::from_slice(FRAG, &buffer).unwrap();
assert_eq!(slice.next_header(), UDP);
assert_eq!(slice.slice(), &buffer[..8])
}
{
const EXTENSION_IDS_WITH_LENGTH: [u8;5] = [
IPv6HeaderHopByHop as u8,
IPv6DestinationOptions as u8,
IPv6RouteHeader as u8,
IPv6AuthenticationHeader as u8,
IPv6EncapSecurityPayload as u8
];
for id in EXTENSION_IDS_WITH_LENGTH.iter() {
let slice = Ipv6ExtensionHeaderSlice::from_slice(*id, &buffer).unwrap();
assert_eq!(slice.next_header(), UDP);
assert_eq!(slice.slice(), &buffer[..])
}
}
}
#[test]
fn ipv6_extension_from_slice_bad_length() {
use IpTrafficClass::*;
const FRAG: u8 = IPv6FragmentationHeader as u8;
const UDP: u8 = Udp as u8;
const EXTENSION_IDS_WITH_LENGTH: [u8;5] = [
IPv6HeaderHopByHop as u8,
IPv6DestinationOptions as u8,
IPv6RouteHeader as u8,
IPv6AuthenticationHeader as u8,
IPv6EncapSecurityPayload as u8
];
{
let buffer: [u8; 7] = [
UDP,2,0,0, 0,0,0
];
assert_matches!(Ipv6ExtensionHeaderSlice::from_slice(FRAG, &buffer), Err(_));
}
{
let buffer: [u8; 8*3-1] = [
UDP,2,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,
];
{
let slice = Ipv6ExtensionHeaderSlice::from_slice(FRAG, &buffer).unwrap();
assert_eq!(slice.next_header(), UDP);
assert_eq!(slice.slice(), &buffer[..8])
}
for id in EXTENSION_IDS_WITH_LENGTH.iter() {
let slice = Ipv6ExtensionHeaderSlice::from_slice(*id, &buffer);
assert_matches!(slice, Err(_));
}
}
}