use super::Header;
use crate::{
decode::decoder::Decoder,
decode::error::DecodeError::ECHLengthMismatch,
rr::ServiceParameter,
{DecodeError, DomainName},
};
use bytes::Bytes;
use std::{
net::{Ipv4Addr, Ipv6Addr},
str::FromStr,
};
#[test]
fn header_get_class_error() {
let header = Header {
domain_name: DomainName::default(),
class: u16::MAX,
ttl: 1000,
};
assert_eq!(header.get_class(), Err(DecodeError::Class(u16::MAX)));
}
#[test]
fn test_service_binding_alias_form() {
let mut bytes: Vec<u8> = vec![];
bytes.extend_from_slice(b"\x00\x00"); bytes.extend_from_slice(b"\x03foo\x07example\x03com\x00"); let mut decoder = Decoder::main(Bytes::from(bytes));
let header = Header {
domain_name: "test.example.com".parse().unwrap(),
class: 1,
ttl: 7200,
};
let result = decoder.rr_service_binding(header, false).unwrap();
assert_eq!(result.priority, 0);
assert_eq!(result.target_name, "foo.example.com".parse().unwrap());
assert_eq!(result.ttl, 7200);
assert_eq!(result.name, "test.example.com".parse().unwrap());
assert!(result.parameters.is_empty());
assert!(result.to_string().ends_with("0 foo.example.com."));
}
#[test]
fn test_service_binding_use_the_ownername() {
let mut bytes: Vec<u8> = vec![];
bytes.extend_from_slice(b"\x00\x01"); bytes.extend_from_slice(b"\x00"); let mut decoder = Decoder::main(Bytes::from(bytes));
let header = Header {
domain_name: "test.example.com".parse().unwrap(),
class: 1,
ttl: 7200,
};
let result = decoder.rr_service_binding(header, false).unwrap();
assert_eq!(result.priority, 1);
assert_eq!(result.target_name, DomainName::default());
assert_eq!(result.ttl, 7200);
assert_eq!(result.name, "test.example.com".parse().unwrap());
assert!(result.parameters.is_empty());
assert!(result.to_string().ends_with("1 ."));
}
#[test]
fn test_service_binding_map_port() {
let mut bytes: Vec<u8> = vec![];
bytes.extend_from_slice(b"\x00\x10"); bytes.extend_from_slice(b"\x03foo\x07example\x03com\x00"); bytes.extend_from_slice(b"\x00\x03"); bytes.extend_from_slice(b"\x00\x02"); bytes.extend_from_slice(b"\x00\x35"); let mut decoder = Decoder::main(Bytes::from(bytes));
let header = Header {
domain_name: "test.example.com".parse().unwrap(),
class: 1,
ttl: 7200,
};
let result = decoder.rr_service_binding(header, false).unwrap();
assert_eq!(result.priority, 16);
assert_eq!(result.target_name, "foo.example.com".parse().unwrap());
assert_eq!(result.ttl, 7200);
assert_eq!(result.name, "test.example.com".parse().unwrap());
assert_eq!(result.parameters.len(), 1);
assert!(matches!(result.parameters.iter().next().unwrap(),
ServiceParameter::PORT {port} if *port == 53));
assert!(result.to_string().ends_with("16 foo.example.com. port=53"));
}
#[test]
fn test_service_binding_unregistered_key() {
let mut bytes: Vec<u8> = vec![];
bytes.extend_from_slice(b"\x00\x01"); bytes.extend_from_slice(b"\x03foo\x07example\x03com\x00"); bytes.extend_from_slice(b"\x02\x9b"); bytes.extend_from_slice(b"\x00\x05"); bytes.extend_from_slice(b"hello"); let mut decoder = Decoder::main(Bytes::from(bytes));
let header = Header {
domain_name: "test.example.com".parse().unwrap(),
class: 1,
ttl: 7200,
};
let result = decoder.rr_service_binding(header, false).unwrap();
assert_eq!(result.priority, 1);
assert_eq!(result.target_name, "foo.example.com".parse().unwrap());
assert_eq!(result.ttl, 7200);
assert_eq!(result.name, "test.example.com".parse().unwrap());
assert_eq!(result.parameters.len(), 1);
assert!(matches!(result.parameters.iter().next().unwrap(),
ServiceParameter::PRIVATE { number, wire_data, } if *number == 667
&& String::from_utf8(wire_data.clone()).unwrap() == *"hello"))
}
#[test]
fn test_service_binding_unregistered_key_escaped_value() {
let mut bytes: Vec<u8> = vec![];
bytes.extend_from_slice(b"\x00\x01"); bytes.extend_from_slice(b"\x03foo\x07example\x03com\x00"); bytes.extend_from_slice(b"\x02\x9b"); bytes.extend_from_slice(b"\x00\x09"); bytes.extend_from_slice(b"hello\xd2qoo"); let mut decoder = Decoder::main(Bytes::from(bytes));
let header = Header {
domain_name: "test.example.com".parse().unwrap(),
class: 1,
ttl: 7200,
};
let result = decoder.rr_service_binding(header, false).unwrap();
assert_eq!(result.priority, 1);
assert_eq!(result.target_name, "foo.example.com".parse().unwrap());
assert_eq!(result.ttl, 7200);
assert_eq!(result.name, "test.example.com".parse().unwrap());
assert_eq!(result.parameters.len(), 1);
assert!(matches!(result.parameters.iter().next().unwrap(),
ServiceParameter::PRIVATE { number, wire_data, } if *number == 667
&& wire_data.as_slice() == b"hello\xd2qoo"));
}
#[test]
fn test_service_binding_ipv6_hints() {
let mut bytes: Vec<u8> = vec![];
bytes.extend_from_slice(b"\x00\x01"); bytes.extend_from_slice(b"\x03foo\x07example\x03com\x00"); bytes.extend_from_slice(b"\x00\x06"); bytes.extend_from_slice(b"\x00\x20"); bytes.extend_from_slice(b"\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"); bytes.extend_from_slice(b"\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x53\x00\x01"); let mut decoder = Decoder::main(Bytes::from(bytes));
let header = Header {
domain_name: "test.example.com".parse().unwrap(),
class: 1,
ttl: 7200,
};
let result = decoder.rr_service_binding(header, false).unwrap();
assert_eq!(result.priority, 1);
assert_eq!(result.target_name, "foo.example.com".parse().unwrap());
assert_eq!(result.ttl, 7200);
assert_eq!(result.name, "test.example.com".parse().unwrap());
assert_eq!(result.parameters.len(), 1);
assert!(matches!(result.parameters.iter().next().unwrap(),
ServiceParameter::IPV6_HINT { hints } if hints.len() == 2
&& hints[0] == Ipv6Addr::from_str("2001:db8::1").unwrap()
&& hints[1] == Ipv6Addr::from_str("2001:db8::53:1").unwrap()));
}
#[test]
fn test_service_binding_ipv6_in_ipv4_mapped_ipv6_format() {
let mut bytes: Vec<u8> = vec![];
bytes.extend_from_slice(b"\x00\x01"); bytes.extend_from_slice(b"\x07example\x03com\x00"); bytes.extend_from_slice(b"\x00\x06"); bytes.extend_from_slice(b"\x00\x10"); bytes.extend_from_slice(b"\x20\x01\x0d\xb8\xff\xff\xff\xff\xff\xff\xff\xff\xc6\x33\x64\x64"); let mut decoder = Decoder::main(Bytes::from(bytes));
let header = Header {
domain_name: "test.example.com".parse().unwrap(),
class: 1,
ttl: 7200,
};
let result = decoder.rr_service_binding(header, false).unwrap();
assert_eq!(result.priority, 1);
assert_eq!(result.target_name, "example.com".parse().unwrap());
assert_eq!(result.ttl, 7200);
assert_eq!(result.name, "test.example.com".parse().unwrap());
assert_eq!(result.parameters.len(), 1);
assert!(matches!(result.parameters.iter().next().unwrap(),
ServiceParameter::IPV6_HINT { hints } if hints.len() == 1 && hints[0] == Ipv6Addr::from_str("2001:db8:ffff:ffff:ffff:ffff:198.51.100.100").unwrap()))
}
#[test]
fn test_service_binding_multiple_parameters() {
let mut bytes: Vec<u8> = vec![];
bytes.extend_from_slice(b"\x00\x10"); bytes.extend_from_slice(b"\x03foo\x07example\x03org\x00");
bytes.extend_from_slice(b"\x00\x01"); bytes.extend_from_slice(b"\x00\x09"); bytes.extend_from_slice(b"\x02"); bytes.extend_from_slice(b"h2"); bytes.extend_from_slice(b"\x05"); bytes.extend_from_slice(b"h3-19"); bytes.extend_from_slice(b"\x00\x00"); bytes.extend_from_slice(b"\x00\x02"); bytes.extend_from_slice(b"\x00\x01"); bytes.extend_from_slice(b"\x00\x04"); bytes.extend_from_slice(b"\x00\x04"); bytes.extend_from_slice(b"\xc0\x00\x02\x01"); let mut decoder = Decoder::main(Bytes::from(bytes));
let header = Header {
domain_name: "test.example.com".parse().unwrap(),
class: 1,
ttl: 7200,
};
let result = decoder.rr_service_binding(header, false).unwrap();
assert_eq!(result.priority, 16);
assert_eq!(result.target_name, "foo.example.org".parse().unwrap());
assert_eq!(result.ttl, 7200);
assert_eq!(result.name, "test.example.com".parse().unwrap());
assert_eq!(result.parameters.len(), 3);
let mut parameters = result.parameters.iter();
assert!(matches!(parameters.next().unwrap(),
ServiceParameter::MANDATORY{ key_ids } if key_ids.len() == 1 && key_ids[ 0 ] == 1 ));
assert!(matches!(parameters.next().unwrap(),
ServiceParameter::ALPN { alpn_ids } if alpn_ids.len() == 2 && alpn_ids[0] == "h2" && alpn_ids[1] == "h3-19"));
assert!(matches!(parameters.next().unwrap(),
ServiceParameter::IPV4_HINT { hints } if hints.len() == 1 && hints[0] == Ipv4Addr::from_str("192.0.2.1").unwrap()));
}
#[test]
fn test_service_binding_escaped_presentation_format() {
let mut bytes: Vec<u8> = vec![];
bytes.extend_from_slice(b"\x00\x10"); bytes.extend_from_slice(b"\x03foo\x07example\x03org\x00"); bytes.extend_from_slice(b"\x00\x01"); bytes.extend_from_slice(b"\x00\x0c"); bytes.extend_from_slice(b"\x08"); bytes.extend_from_slice(b"f\\oo,bar"); bytes.extend_from_slice(b"\x02"); bytes.extend_from_slice(b"h2");
let mut decoder = Decoder::main(Bytes::from(bytes));
let header = Header {
domain_name: "test.example.com".parse().unwrap(),
class: 1,
ttl: 7200,
};
let result = decoder.rr_service_binding(header, false).unwrap();
assert_eq!(result.priority, 16);
assert_eq!(result.target_name, "foo.example.org".parse().unwrap());
assert_eq!(result.ttl, 7200);
assert_eq!(result.name, "test.example.com".parse().unwrap());
assert_eq!(result.parameters.len(), 1);
assert!(matches!(result.parameters.iter().next().unwrap(),
ServiceParameter::ALPN { alpn_ids } if alpn_ids.len() == 2 && alpn_ids[0] == "f\\oo,bar" && alpn_ids[1] == "h2"));
}
#[test]
fn test_service_binding_ech_length_mismatch() {
let mut bytes: Vec<u8> = vec![];
bytes.extend_from_slice(b"\x00\x01"); bytes.extend_from_slice(b"\x03foo\x07example\x03com\x00"); bytes.extend_from_slice(b"\x00\x05"); bytes.extend_from_slice(b"\x00\x07"); bytes.extend_from_slice(b"\x00\x07"); bytes.extend_from_slice(b"Hello"); let mut decoder = Decoder::main(Bytes::from(bytes));
let header = Header {
domain_name: "test.example.com".parse().unwrap(),
class: 1,
ttl: 7200,
};
let result = decoder.rr_service_binding(header, false);
assert!(matches!(result,
Err(decode_error) if matches!(decode_error,
ECHLengthMismatch(expected, actual) if expected == 7 && actual == 5)));
}