use etherparse::*;
use byteorder::{ByteOrder, BigEndian};
use super::super::*;
proptest! {
#[test]
fn read_write(ref input in udp_any()) {
use std::io::Cursor;
let mut buffer: Vec<u8> = Vec::with_capacity(UdpHeader::SERIALIZED_SIZE + 1);
input.write(&mut buffer).unwrap();
{
let result = UdpHeader::read(&mut Cursor::new(&buffer)).unwrap();
assert_eq!(input, &result);
}
{
buffer.push(1);
let result = UdpHeader::read_from_slice(&buffer).unwrap();
assert_eq!(input, &result.0);
assert_eq!(&buffer[buffer.len()-1 .. ], result.1);
}
}
}
#[test]
fn with_ipv4_checksum() {
let payload = [9,10,11,12, 13,14,15,16];
let ip_header = Ipv4Header::new(
(UdpHeader::SERIALIZED_SIZE + payload.len()) as u16,
5,
IpTrafficClass::Udp,
[1,2,3,4],
[5,6,7,8]
);
let result = UdpHeader::with_ipv4_checksum(1234, 5678, &ip_header, &payload).unwrap();
assert_eq!(UdpHeader {
source_port: 1234,
destination_port: 5678,
length: (UdpHeader::SERIALIZED_SIZE + payload.len()) as u16,
checksum: 42118
}, result);
}
#[test]
fn with_ipv4_checksum_flip() {
let mut payload = [0,0,0,0];
let sum: u16 = IpTrafficClass::Udp as u16 +
(2*(UdpHeader::SERIALIZED_SIZE as u16 +
payload.len() as u16));
BigEndian::write_u16(&mut payload, 0xffff - sum);
let ip_header = Ipv4Header::new(
(UdpHeader::SERIALIZED_SIZE + payload.len()) as u16,
5,
IpTrafficClass::Udp,
[0,0,0,0],
[0,0,0,0],
);
let result = UdpHeader::with_ipv4_checksum(0, 0, &ip_header, &payload).unwrap();
assert_eq!(UdpHeader {
source_port: 0,
destination_port: 0,
length: (UdpHeader::SERIALIZED_SIZE + payload.len()) as u16,
checksum: 0xffff
}, result);
}
#[test]
fn with_ipv4_payload_size_check() {
use std;
let mut payload = Vec::with_capacity(std::u16::MAX as usize);
payload.resize(std::u16::MAX as usize - UdpHeader::SERIALIZED_SIZE, 0);
let ip_header = Ipv4Header::new(
0,
5,
IpTrafficClass::Udp,
[1,2,3,4],
[5,6,7,8]
);
assert_matches!(UdpHeader::with_ipv4_checksum(1234, 5678, &ip_header, &payload),
Ok(_));
assert_matches!(UdpHeader::without_ipv4_checksum(1234, 5678, payload.len()),
Ok(_));
{
let header = UdpHeader::without_ipv4_checksum(1234, 5678, payload.len()).unwrap();
assert_matches!(header.calc_checksum_ipv4(&ip_header, &payload),
Ok(_));
assert_matches!(header.calc_checksum_ipv4_raw(ip_header.source, ip_header.destination, ip_header.protocol, &payload),
Ok(_));
}
const TOO_LARGE: usize = std::u16::MAX as usize - UdpHeader::SERIALIZED_SIZE + 1;
payload.resize(TOO_LARGE, 0);
assert_matches!(UdpHeader::with_ipv4_checksum(1234, 5678, &ip_header, &payload),
Err(ValueError::UdpPayloadLengthTooLarge(TOO_LARGE)));
assert_matches!(UdpHeader::without_ipv4_checksum(1234, 5678, payload.len()),
Err(ValueError::UdpPayloadLengthTooLarge(TOO_LARGE)));
{
let header = UdpHeader::without_ipv4_checksum(1234, 5678, 1234).unwrap();
assert_matches!(header.calc_checksum_ipv4(&ip_header, &payload),
Err(ValueError::UdpPayloadLengthTooLarge(TOO_LARGE)));
assert_matches!(header.calc_checksum_ipv4_raw(ip_header.source, ip_header.destination, ip_header.protocol, &payload),
Err(ValueError::UdpPayloadLengthTooLarge(TOO_LARGE)));
}
}
#[test]
fn udp_calc_checksum_ipv4() {
let ipheader = Ipv4Header::new(4*3 + 8, 5, IpTrafficClass::Udp, [1,2,3,4], [5,6,7,8]);
let payload = [9,10,11,12, 13,14,15,16];
let udp = UdpHeader {
source_port: 1234,
destination_port: 5678,
length: (UdpHeader::SERIALIZED_SIZE + payload.len()) as u16,
checksum: 0
};
assert_eq!(42118, udp.calc_checksum_ipv4(&ipheader, &payload).unwrap());
}
#[test]
fn udp_calc_checksum_ipv4_raw() {
let udp = UdpHeader {
source_port: 1234,
destination_port: 5678,
length: 8,
checksum: 0
};
let payload = [9,10,11,12, 13,14,15,16];
assert_eq!(42134, udp.calc_checksum_ipv4_raw([1,2,3,4], [5,6,7,8], IpTrafficClass::Udp as u8, &payload).unwrap());
}
#[test]
fn udp_with_ipv6_checksum() {
{
let udp_payload = [39,40,41,42];
let ip_header = Ipv6Header {
traffic_class: 1,
flow_label: 0x81806,
payload_length: (UdpHeader::SERIALIZED_SIZE + udp_payload.len()) as u16,
next_header: IpTrafficClass::Udp as u8,
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 result = UdpHeader::with_ipv6_checksum(37, 38, &ip_header, &udp_payload).unwrap();
assert_eq!(37, result.source_port);
assert_eq!(38, result.destination_port);
assert_eq!((UdpHeader::SERIALIZED_SIZE + udp_payload.len()) as u16, result.length);
const EXPECTED_CHECKSUM: u16 = 0x8e08;
assert_eq!(EXPECTED_CHECKSUM, result.checksum);
let udp_header = UdpHeader{
source_port: 37,
destination_port: 38,
length: (UdpHeader::SERIALIZED_SIZE + udp_payload.len()) as u16,
checksum: 0
};
assert_matches!(udp_header.calc_checksum_ipv6(&ip_header,
&udp_payload),
Ok(EXPECTED_CHECKSUM));
assert_matches!(udp_header.calc_checksum_ipv6_raw(&ip_header.source,
&ip_header.destination,
&udp_payload),
Ok(EXPECTED_CHECKSUM));
}
{
let udp_payload = [39,40,41,42,43];
let ip_header = Ipv6Header {
traffic_class: 1,
flow_label: 0x81806,
payload_length: (UdpHeader::SERIALIZED_SIZE + udp_payload.len()) as u16,
next_header: IpTrafficClass::Udp as u8,
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 result = UdpHeader::with_ipv6_checksum(37, 38, &ip_header, &udp_payload).unwrap();
assert_eq!(37, result.source_port);
assert_eq!(38, result.destination_port);
assert_eq!((UdpHeader::SERIALIZED_SIZE + udp_payload.len()) as u16, result.length);
const EXPECTED_CHECKSUM: u16 = 0x6306;
assert_eq!(EXPECTED_CHECKSUM, result.checksum);
let udp_header = UdpHeader{
source_port: 37,
destination_port: 38,
length: (UdpHeader::SERIALIZED_SIZE + udp_payload.len()) as u16,
checksum: 0
};
assert_matches!(udp_header.calc_checksum_ipv6(&ip_header,
&udp_payload),
Ok(EXPECTED_CHECKSUM));
assert_matches!(udp_header.calc_checksum_ipv6_raw(&ip_header.source,
&ip_header.destination,
&udp_payload),
Ok(EXPECTED_CHECKSUM));
}
{
let udp_payload_len = 0xffff
- (Ipv4Header::SERIALIZED_SIZE as usize)
- (UdpHeader::SERIALIZED_SIZE as usize);
let mut udp_payload = Vec::with_capacity(udp_payload_len);
udp_payload.resize(udp_payload_len, 0xff);
let ip_header = Ipv6Header {
traffic_class: 1,
flow_label: 0x81806,
payload_length: (UdpHeader::SERIALIZED_SIZE + udp_payload.len()) as u16,
next_header: IpTrafficClass::Udp as u8,
hop_limit: 40,
source: [0xff;16],
destination: [0xff;16]
};
let result = UdpHeader::with_ipv6_checksum(0xffff,
0xffff,
&ip_header,
&udp_payload).unwrap();
assert_eq!(0xffff, result.source_port);
assert_eq!(0xffff, result.destination_port);
assert_eq!((UdpHeader::SERIALIZED_SIZE + udp_payload.len()) as u16, result.length);
const EXPECTED_CHECKSUM: u16 = 0x0116;
assert_eq!(EXPECTED_CHECKSUM, result.checksum);
let udp_header = UdpHeader{
source_port: 0xffff,
destination_port: 0xffff,
length: (UdpHeader::SERIALIZED_SIZE + udp_payload.len()) as u16,
checksum: 0
};
assert_matches!(udp_header.calc_checksum_ipv6(&ip_header,
&udp_payload),
Ok(EXPECTED_CHECKSUM));
assert_matches!(udp_header.calc_checksum_ipv6_raw(&ip_header.source,
&ip_header.destination,
&udp_payload),
Ok(EXPECTED_CHECKSUM));
}
}
#[test]
fn udp_ipv6_errors() {
use std;
let ip_header = Ipv6Header {
traffic_class: 1,
flow_label: 0x81806,
payload_length: 1234,
next_header: IpTrafficClass::Udp as u8,
hop_limit: 40,
source: [0xff;16],
destination: [0xff;16]
};
const MAX: usize = (std::u16::MAX as usize) - UdpHeader::SERIALIZED_SIZE;
{
let mut payload = Vec::with_capacity(MAX);
payload.resize(MAX, 0);
let udp_header = UdpHeader{
source_port: 37,
destination_port: 38,
length: (UdpHeader::SERIALIZED_SIZE + payload.len()) as u16,
checksum: 0
};
assert_matches!(UdpHeader::with_ipv6_checksum(0, 0, &ip_header, &payload),
Ok(_));
assert_matches!(udp_header.calc_checksum_ipv6(&ip_header, &payload),
Ok(_));
assert_matches!(udp_header.calc_checksum_ipv6_raw(&ip_header.source, &ip_header.destination, &payload),
Ok(_));
}
{
const OVER_MAX: usize = MAX + 1;
let mut payload = Vec::with_capacity(OVER_MAX);
payload.resize(OVER_MAX, 0);
let udp_header = UdpHeader{
source_port: 37,
destination_port: 38,
length: (UdpHeader::SERIALIZED_SIZE + payload.len()) as u16,
checksum: 0
};
assert_matches!(UdpHeader::with_ipv6_checksum(0, 0, &ip_header, &payload),
Err(ValueError::UdpPayloadLengthTooLarge(OVER_MAX)));
assert_matches!(udp_header.calc_checksum_ipv6(&ip_header, &payload),
Err(ValueError::UdpPayloadLengthTooLarge(OVER_MAX)));
assert_matches!(udp_header.calc_checksum_ipv6_raw(&ip_header.source, &ip_header.destination, &payload),
Err(ValueError::UdpPayloadLengthTooLarge(OVER_MAX)));
}
}
#[test]
fn from_slice() {
let input = UdpHeader {
source_port: 1234,
destination_port: 5678,
length: 1356,
checksum: 2467
};
let mut buffer: Vec<u8> = Vec::with_capacity(8);
input.write(&mut buffer).unwrap();
use crate::ReadError::*;
assert_matches!(
UdpHeaderSlice::from_slice(&buffer[..7]),
Err(UnexpectedEndOfSlice(UdpHeader::SERIALIZED_SIZE))
);
let slice = UdpHeaderSlice::from_slice(&buffer).unwrap();
assert_eq!(slice.source_port(), input.source_port);
assert_eq!(slice.destination_port(), input.destination_port);
assert_eq!(slice.length(), input.length);
assert_eq!(slice.checksum(), input.checksum);
assert_eq!(slice.to_header(), input);
}