use super::*;
#[test]
fn test_tun_state_display() {
assert_eq!(format!("{}", TunState::Disabled), "disabled");
assert_eq!(format!("{}", TunState::Active), "active");
}
#[test]
fn tun_outbound_packet_reserves_tail_room_for_dataplane_prepend() {
let packet = vec![0x42; 1280];
let outbound = tun_outbound_packet(&packet);
assert_eq!(outbound, packet);
assert!(
outbound.capacity() >= packet.len() + TUN_OUTBOUND_PACKET_TAIL_RESERVE,
"TUN outbound packets need spare tail room so IPv6 shim plus AEAD prepend can avoid a second hot-path allocation"
);
}
#[test]
fn tun_outbound_owned_packet_reserves_tail_room_without_copying_when_possible() {
let mut packet = Vec::with_capacity(1280 + TUN_OUTBOUND_PACKET_TAIL_RESERVE);
packet.extend_from_slice(&[0x42; 1280]);
let ptr = packet.as_ptr();
let outbound = tun_outbound_packet_owned(packet);
assert_eq!(outbound, vec![0x42; 1280]);
assert_eq!(outbound.as_ptr(), ptr);
assert!(
outbound.capacity() >= outbound.len() + TUN_OUTBOUND_PACKET_TAIL_RESERVE,
"owned TUN outbound packets should keep spare tail room for dataplane prepend"
);
}
fn fips_addr_with_node_byte(b: u8) -> FipsAddress {
let mut bytes = [0u8; 16];
bytes[0] = crate::identity::FIPS_ADDRESS_PREFIX;
bytes[1] = b;
FipsAddress::from_bytes(bytes).unwrap()
}
fn empty_lookup() -> PathMtuLookup {
Arc::new(RwLock::new(HashMap::new()))
}
#[test]
fn per_flow_empty_lookup_returns_conservative_ceiling() {
let lookup = empty_lookup();
let addr = fips_addr_with_node_byte(0x42);
assert_eq!(per_flow_max_mss(&lookup, addr.as_bytes(), 1360), 1143);
}
#[test]
fn per_flow_empty_lookup_returns_global_when_global_smaller() {
let lookup = empty_lookup();
let addr = fips_addr_with_node_byte(0x42);
assert_eq!(per_flow_max_mss(&lookup, addr.as_bytes(), 1100), 1100);
}
#[test]
fn per_flow_clamps_to_path_mtu_when_smaller() {
let lookup = empty_lookup();
let addr = fips_addr_with_node_byte(0x42);
lookup.write().unwrap().insert(addr, 1280);
assert_eq!(per_flow_max_mss(&lookup, addr.as_bytes(), 1360), 1143);
}
#[test]
fn per_flow_keeps_global_when_path_mtu_larger() {
let lookup = empty_lookup();
let addr = fips_addr_with_node_byte(0x42);
lookup.write().unwrap().insert(addr, 1452);
assert_eq!(per_flow_max_mss(&lookup, addr.as_bytes(), 1143), 1143);
}
#[test]
fn per_flow_learned_value_overrides_conservative_ceiling() {
let lookup = empty_lookup();
let addr = fips_addr_with_node_byte(0x42);
lookup.write().unwrap().insert(addr, 1452);
assert_eq!(per_flow_max_mss(&lookup, addr.as_bytes(), 1360), 1315);
}
#[test]
fn per_flow_returns_conservative_ceiling_for_non_fips_addr() {
let lookup = empty_lookup();
let mut bytes = [0u8; 16];
bytes[0] = 0xfe;
bytes[1] = 0x80;
assert_eq!(per_flow_max_mss(&lookup, &bytes, 1360), 1143);
}
#[test]
fn per_flow_returns_conservative_ceiling_on_short_addr_slice() {
let lookup = empty_lookup();
let bytes = [0u8; 8];
assert_eq!(per_flow_max_mss(&lookup, &bytes, 1360), 1143);
}
#[test]
fn per_flow_independent_per_destination() {
let lookup = empty_lookup();
let a = fips_addr_with_node_byte(0x10);
let b = fips_addr_with_node_byte(0x20);
lookup.write().unwrap().insert(a, 1280);
lookup.write().unwrap().insert(b, 1452);
assert_eq!(per_flow_max_mss(&lookup, a.as_bytes(), 1360), 1143);
assert_eq!(per_flow_max_mss(&lookup, b.as_bytes(), 1360), 1315);
}
#[cfg(target_os = "macos")]
mod macos_utun_header {
use super::super::{UTUN_AF_INET6, parse_utun_af_prefix, utun_af_inet6_header};
#[test]
fn af_inet6_constant_matches_darwin() {
assert_eq!(UTUN_AF_INET6, 30);
}
#[test]
fn encode_produces_big_endian_af_inet6() {
let header = utun_af_inet6_header();
assert_eq!(header, [0x00, 0x00, 0x00, 0x1e]);
}
#[test]
fn encode_round_trips_through_parse() {
let header = utun_af_inet6_header();
let parsed = parse_utun_af_prefix(&header).expect("4 bytes is enough");
assert_eq!(parsed, UTUN_AF_INET6);
}
#[test]
fn parse_rejects_short_buffer() {
assert_eq!(parse_utun_af_prefix(&[]), None);
assert_eq!(parse_utun_af_prefix(&[0x00]), None);
assert_eq!(parse_utun_af_prefix(&[0x00, 0x00]), None);
assert_eq!(parse_utun_af_prefix(&[0x00, 0x00, 0x00]), None);
}
#[test]
fn parse_accepts_minimum_header_with_trailing_payload() {
let mut frame = utun_af_inet6_header().to_vec();
frame.extend_from_slice(&[0x60; 40]); let parsed = parse_utun_af_prefix(&frame).expect("4 bytes is enough");
assert_eq!(parsed, UTUN_AF_INET6);
}
#[test]
fn parse_garbage_bytes_returns_garbage_value_not_panic() {
let buf = [0xde, 0xad, 0xbe, 0xef];
let parsed = parse_utun_af_prefix(&buf).expect("4 bytes is enough");
assert_eq!(parsed, 0xdeadbeef);
assert_ne!(parsed, UTUN_AF_INET6);
}
}