use super::super::*;
mod ip_header {
use super::*;
use crate::ip_number::*;
use std::io::Cursor;
const EXTESION_KNOWN_IP_NUMBERS : [u8;5] = [
AUTH,
IPV6_DEST_OPTIONS,
IPV6_HOP_BY_HOP,
IPV6_FRAG,
IPV6_ROUTE,
];
fn combine_v4(v4: &Ipv4Header, ext: &Ipv4Extensions) -> IpHeader {
IpHeader::Version4(
{
let mut v4 = v4.clone();
v4.protocol = if ext.auth.is_some() {
AUTH
} else {
UDP
};
v4.header_checksum = v4.calc_header_checksum().unwrap();
v4
},
ext.clone(),
)
}
fn combine_v6(v6: &Ipv6Header, ext: &Ipv6Extensions) -> IpHeader {
let (ext, next_header) = {
let mut ext = ext.clone();
let next_header = ext.set_next_headers(UDP);
(ext, next_header)
};
IpHeader::Version6(
{
let mut v6 = v6.clone();
v6.next_header = next_header;
v6
},
ext,
)
}
proptest!{
#[test]
#[allow(deprecated)]
fn read_from_slice(
v4 in ipv4_any(),
v4_exts in ipv4_extensions_any(),
) {
let header = combine_v4(&v4, &v4_exts);
let mut buffer = Vec::with_capacity(header.header_len());
header.write(&mut buffer).unwrap();
let actual = IpHeader::read_from_slice(&buffer).unwrap();
assert_eq!(actual.0, header);
assert_eq!(actual.1, header.next_header().unwrap());
assert_eq!(actual.2, &buffer[buffer.len()..]);
}
}
proptest!{
#[test]
fn from_slice(
v4 in ipv4_any(),
v4_exts in ipv4_extensions_any(),
v6 in ipv6_any(),
v6_exts in ipv6_extensions_any(),
) {
{
let header = combine_v4(&v4, &v4_exts);
let mut buffer = Vec::with_capacity(header.header_len() + 1);
header.write(&mut buffer).unwrap();
buffer.push(1);
{
let actual = IpHeader::from_slice(&buffer).unwrap();
assert_eq!(actual.0, header);
assert_eq!(actual.1, header.next_header().unwrap());
assert_eq!(actual.2, &buffer[buffer.len() - 1..]);
}
IpHeader::from_slice(&buffer[..1]).unwrap_err();
if v4_exts.header_len() > 0 {
IpHeader::from_slice(&buffer[..v4.header_len() + 1]).unwrap_err();
}
}
{
let header = combine_v6(&v6, &v6_exts);
let mut buffer = Vec::with_capacity(header.header_len() + 1);
header.write(&mut buffer).unwrap();
buffer.push(1);
{
let actual = IpHeader::from_slice(&buffer).unwrap();
assert_eq!(actual.0, header);
assert_eq!(actual.1, header.next_header().unwrap());
assert_eq!(actual.2, &buffer[buffer.len() - 1..]);
}
IpHeader::from_slice(&buffer[..1]).unwrap_err();
if v6_exts.header_len() > 0 {
IpHeader::from_slice(&buffer[..Ipv6Header::SERIALIZED_SIZE + 1]).unwrap_err();
}
}
}
}
proptest!{
#[test]
fn read(
v4 in ipv4_any(),
v4_exts in ipv4_extensions_any(),
v6 in ipv6_any(),
v6_exts in ipv6_extensions_any(),
) {
{
let header = combine_v4(&v4, &v4_exts);
let mut buffer = Vec::with_capacity(header.header_len());
header.write(&mut buffer).unwrap();
{
let mut cursor = Cursor::new(&buffer);
let actual = IpHeader::read(&mut cursor).unwrap();
assert_eq!(actual.0, header);
assert_eq!(actual.1, header.next_header().unwrap());
}
{
let mut cursor = Cursor::new(&buffer[..1]);
IpHeader::read(&mut cursor).unwrap_err();
}
if v4_exts.header_len() > 0 {
let mut cursor = Cursor::new(&buffer[..v4.header_len() + 1]);
IpHeader::read(&mut cursor).unwrap_err();
}
}
{
let header = combine_v6(&v6, &v6_exts);
let mut buffer = Vec::with_capacity(header.header_len());
header.write(&mut buffer).unwrap();
{
let mut cursor = Cursor::new(&buffer);
let actual = IpHeader::read(&mut cursor).unwrap();
assert_eq!(actual.0, header);
assert_eq!(actual.1, header.next_header().unwrap());
}
{
let mut cursor = Cursor::new(&buffer[..1]);
IpHeader::read(&mut cursor).unwrap_err();
}
if v6_exts.header_len() > 0 {
let mut cursor = Cursor::new(&buffer[..Ipv6Header::SERIALIZED_SIZE + 1]);
IpHeader::read(&mut cursor).unwrap_err();
}
}
}
}
proptest!{
#[test]
fn write(
v4 in ipv4_any(),
v4_exts in ipv4_extensions_any(),
v6 in ipv6_any(),
v6_exts in ipv6_extensions_any(),
) {
{
let header = combine_v4(&v4, &v4_exts);
let mut buffer = Vec::with_capacity(header.header_len());
header.write(&mut buffer).unwrap();
let actual = IpHeader::from_slice(&buffer).unwrap().0;
assert_eq!(header, actual);
let mut writer = TestWriter::with_max_size(1);
assert_eq!(
writer.error_kind(),
header.write(&mut writer).unwrap_err().io_error().unwrap().kind()
);
if v4_exts.header_len() > 0 {
let mut writer = TestWriter::with_max_size(v4.header_len() + 1);
assert_eq!(
writer.error_kind(),
header.write(&mut writer).unwrap_err().io_error().unwrap().kind()
);
}
}
{
let header = combine_v6(&v6, &v6_exts);
let mut buffer = Vec::with_capacity(header.header_len());
header.write(&mut buffer).unwrap();
let actual = IpHeader::from_slice(&buffer).unwrap().0;
assert_eq!(header, actual);
{
let mut writer = TestWriter::with_max_size(1);
assert_eq!(
writer.error_kind(),
header.write(&mut writer).unwrap_err().io_error().unwrap().kind()
);
}
if v6_exts.header_len() > 0 {
let mut writer = TestWriter::with_max_size(Ipv6Header::SERIALIZED_SIZE + 1);
assert_eq!(
writer.error_kind(),
header.write(&mut writer).unwrap_err().io_error().unwrap().kind()
);
}
}
}
}
proptest!{
#[test]
fn header_len(
v4 in ipv4_any(),
v4_exts in ipv4_extensions_any(),
v6 in ipv6_any(),
v6_exts in ipv6_extensions_any(),
) {
assert_eq!(
v4.header_len() + v4_exts.header_len(),
IpHeader::Version4(v4, v4_exts).header_len()
);
assert_eq!(
Ipv6Header::SERIALIZED_SIZE + v6_exts.header_len(),
IpHeader::Version6(v6, v6_exts).header_len()
);
}
}
proptest!{
#[test]
fn next_header(
v4 in ipv4_any(),
v4_exts in ipv4_extensions_any(),
v6 in ipv6_any(),
v6_exts in ipv6_extensions_any(),
post_header in any::<u8>()
.prop_filter("Must be a non ipv6 header relevant ip number".to_owned(),
|v| !EXTESION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x)
)
) {
{
let mut header = v4.clone();
let mut exts = v4_exts.clone();
header.protocol = exts.set_next_headers(post_header);
assert_eq!(
Ok(post_header),
IpHeader::Version4(header, exts).next_header()
);
}
{
let mut header = v6.clone();
let mut exts = v6_exts.clone();
header.next_header = exts.set_next_headers(post_header);
assert_eq!(
Ok(post_header),
IpHeader::Version6(header, exts).next_header()
);
}
}
}
proptest!{
#[test]
fn debug(
v4 in ipv4_any(),
v4_exts in ipv4_extensions_any(),
v6 in ipv6_any(),
v6_exts in ipv6_extensions_any(),
) {
assert_eq!(
format!(
"Version4({:?}, {:?})",
v4,
v4_exts
),
format!("{:?}", IpHeader::Version4(v4, v4_exts))
);
assert_eq!(
format!(
"Version6({:?}, {:?})",
v6,
v6_exts
),
format!("{:?}", IpHeader::Version6(v6, v6_exts))
);
}
}
proptest!{
#[test]
fn clone_eq(
v4 in ipv4_any(),
v4_exts in ipv4_extensions_any(),
v6 in ipv6_any(),
v6_exts in ipv6_extensions_any(),
) {
{
let v4 = IpHeader::Version4(v4, v4_exts);
assert_eq!(v4, v4.clone());
}
{
let v6 = IpHeader::Version6(v6, v6_exts);
assert_eq!(v6, v6.clone());
}
}
}
#[test]
fn read_ip_header_version_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)));
}
assert_matches!(
IpHeader::from_slice(&buffer),
Err(ReadError::IpUnsupportedVersion(0xf))
);
assert_matches!(
IpHeader::from_slice(&buffer[buffer.len()..]),
Err(ReadError::UnexpectedEndOfSlice(1))
);
}
}
mod ip_number {
use super::*;
#[test]
fn is_ipv6_ext_header_value() {
use crate::IpNumber;
use crate::ip_number::*;
let ext_ids = [
IPV6_HOP_BY_HOP,
IPV6_ROUTE,
IPV6_FRAG,
ENCAP_SEC,
AUTH,
IPV6_DEST_OPTIONS,
MOBILITY,
HIP,
SHIM6 as u8,
EXP0 as u8,
EXP1 as u8
];
for i in 0..std::u8::MAX {
assert_eq!(
ext_ids.contains(&i),
IpNumber::is_ipv6_ext_header_value(i)
);
}
}
#[test]
fn ip_number_eq_check() {
use crate::ip_number::*;
use crate::IpNumber::*;
let pairs = &[
(IPV6_HOP_BY_HOP, IPv6HeaderHopByHop),
(ICMP, Icmp),
(IGMP, Igmp),
(GGP, Ggp),
(IPV4, IPv4),
(STREAM, Stream),
(TCP, Tcp),
(UDP, Udp),
(IPV6, Ipv6),
(IPV6_ROUTE, IPv6RouteHeader),
(IPV6_FRAG, IPv6FragmentationHeader),
(ENCAP_SEC, EncapsulatingSecurityPayload),
(AUTH, AuthenticationHeader),
(IPV6_DEST_OPTIONS, IPv6DestinationOptions),
(MOBILITY, MobilityHeader),
(HIP, Hip),
(SHIM6, Shim6),
(EXP0, ExperimentalAndTesting0),
(EXP1, ExperimentalAndTesting1),
];
for (raw, enum_value) in pairs {
assert_eq!(*raw, *enum_value as u8);
}
}
#[test]
fn debug() {
assert_eq!(
"IPv6HeaderHopByHop",
&format!("{:?}", IpNumber::IPv6HeaderHopByHop)
);
}
#[test]
fn clone_eq() {
let value = IpNumber::IPv6HeaderHopByHop;
assert_eq!(value, value.clone());
}
}