properly extract both IPv6 and IPv4 addresses for named tests

This commit is contained in:
Benjamin Fry 2024-01-03 20:49:00 -08:00
parent f8d67265eb
commit 4d292515a6
7 changed files with 88 additions and 44 deletions

View File

@ -19,6 +19,7 @@ use std::sync::Arc;
use hickory_client::client::*;
use hickory_proto::h2::HttpsClientStreamBuilder;
use hickory_proto::iocompat::AsyncIoTokioAsStd;
use hickory_server::server::Protocol;
use rustls::{Certificate, ClientConfig, OwnedTrustAnchor, RootCertStore};
use tokio::net::TcpStream as TokioTcpStream;
use tokio::runtime::Runtime;
@ -31,8 +32,9 @@ fn test_example_https_toml_startup() {
const ALPN_H2: &[u8] = b"h2";
named_test_harness("dns_over_https.toml", move |_, _, _, https_port, _| {
named_test_harness("dns_over_https.toml", move |socket_ports| {
let mut cert_der = vec![];
let https_port = socket_ports.get_v4(Protocol::Https);
let server_path = env::var("TDNS_WORKSPACE_ROOT").unwrap_or_else(|_| "..".to_owned());
println!("using server src path: {server_path}");

View File

@ -14,6 +14,7 @@ use std::{env, fs::File, io::*, net::*};
use hickory_client::client::*;
use hickory_proto::quic::QuicClientStream;
use hickory_server::server::Protocol;
use rustls::{Certificate, ClientConfig, OwnedTrustAnchor, RootCertStore};
use tokio::runtime::Runtime;
@ -23,8 +24,9 @@ use server_harness::{named_test_harness, query_a};
fn test_example_quic_toml_startup() {
// env_logger::try_init().ok();
named_test_harness("dns_over_quic.toml", move |_, _, _, _, quic_port| {
named_test_harness("dns_over_quic.toml", move |socket_ports| {
let mut cert_der = vec![];
let quic_port = socket_ports.get_v4(Protocol::Quic);
let server_path = env::var("TDNS_WORKSPACE_ROOT").unwrap_or_else(|_| "..".to_owned());
println!("using server src path: {server_path} and quic_port: {quic_port:?}");

View File

@ -16,6 +16,7 @@ use std::io::*;
use std::net::*;
use std::sync::Arc;
use hickory_server::server::Protocol;
use rustls::Certificate;
use rustls::ClientConfig;
use rustls::RootCertStore;
@ -32,8 +33,9 @@ use server_harness::{named_test_harness, query_a};
fn test_example_tls_toml_startup() {
named_test_harness(
"dns_over_tls_rustls_and_openssl.toml",
move |_, _, tls_port, _, _| {
move |socket_ports| {
let mut cert_der = vec![];
let tls_port = socket_ports.get_v4(Protocol::Tls);
let server_path = env::var("TDNS_WORKSPACE_ROOT").unwrap_or_else(|_| "..".to_owned());
println!("using server src path: {server_path}");

View File

@ -9,6 +9,7 @@ use std::io::Read;
use std::net::*;
use std::path::Path;
use hickory_server::server::Protocol;
use tokio::net::TcpStream as TokioTcpStream;
use tokio::runtime::Runtime;
@ -81,8 +82,9 @@ fn generic_test(config_toml: &str, key_path: &str, key_format: KeyFormat, algori
let server_path = env::var("TDNS_WORKSPACE_ROOT").unwrap_or_else(|_| "..".to_owned());
let server_path = Path::new(&server_path);
named_test_harness(config_toml, |_, tcp_port, _, _, _| {
named_test_harness(config_toml, |socket_ports| {
let mut io_loop = Runtime::new().unwrap();
let tcp_port = socket_ports.get_v4(Protocol::Tcp);
// verify all records are present
let client = standard_tcp_conn(tcp_port.expect("no tcp port"));

View File

@ -20,6 +20,7 @@ use hickory_client::op::ResponseCode;
use hickory_client::rr::*;
use hickory_client::tcp::TcpClientStream;
use hickory_client::udp::UdpClientStream;
use hickory_server::server::Protocol;
// TODO: Needed for when TLS tests are added back
// #[cfg(feature = "dns-over-openssl")]
@ -30,8 +31,9 @@ use server_harness::{named_test_harness, query_a};
#[test]
fn test_example_toml_startup() {
named_test_harness("example.toml", |_, tcp_port, _, _, _| {
named_test_harness("example.toml", |socket_ports| {
let mut io_loop = Runtime::new().unwrap();
let tcp_port = socket_ports.get_v4(Protocol::Tcp);
let addr: SocketAddr = SocketAddr::new(
Ipv4Addr::new(127, 0, 0, 1).into(),
tcp_port.expect("no tcp_port"),
@ -61,8 +63,9 @@ fn test_example_toml_startup() {
#[test]
fn test_ipv4_only_toml_startup() {
named_test_harness("ipv4_only.toml", |_, tcp_port, _, _, _| {
named_test_harness("ipv4_only.toml", |socket_ports| {
let mut io_loop = Runtime::new().unwrap();
let tcp_port = socket_ports.get_v4(Protocol::Tcp);
let addr: SocketAddr = SocketAddr::new(
Ipv4Addr::new(127, 0, 0, 1).into(),
tcp_port.expect("no tcp_port"),
@ -99,8 +102,9 @@ fn test_ipv4_only_toml_startup() {
// #[ignore]
// #[test]
// fn test_ipv6_only_toml_startup() {
// named_test_harness("ipv6_only.toml", |port, _| {
// named_test_harness("ipv6_only.toml", |socket_ports| {
// let mut io_loop = Runtime::new().unwrap();
// let tcp_port = socket_ports.get_v4(Protocol::Tcp);
// let addr: SocketAddr = ("127.0.0.1", port).to_socket_addrs().unwrap().next().unwrap();
// let (stream, sender) = TcpClientStream::new(addr);
// let client = AsyncClient::new(stream, sender, None);
@ -123,8 +127,9 @@ fn test_ipv4_only_toml_startup() {
#[test]
fn test_ipv4_and_ipv6_toml_startup() {
named_test_harness("ipv4_and_ipv6.toml", |_, tcp_port, _, _, _| {
named_test_harness("ipv4_and_ipv6.toml", |socket_ports| {
let mut io_loop = Runtime::new().unwrap();
let tcp_port = socket_ports.get_v4(Protocol::Tcp);
let addr: SocketAddr = SocketAddr::new(
Ipv4Addr::new(127, 0, 0, 1).into(),
tcp_port.expect("no tcp_port"),
@ -137,6 +142,7 @@ fn test_ipv4_and_ipv6_toml_startup() {
// ipv4 should succeed
query_a(&mut io_loop, &mut client);
let tcp_port = socket_ports.get_v6(Protocol::Tcp);
let addr: SocketAddr = SocketAddr::new(
Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).into(),
tcp_port.expect("no tcp_port"),
@ -153,8 +159,9 @@ fn test_ipv4_and_ipv6_toml_startup() {
#[test]
fn test_nodata_where_name_exists() {
named_test_harness("example.toml", |_, tcp_port, _, _, _| {
named_test_harness("example.toml", |socket_ports| {
let io_loop = Runtime::new().unwrap();
let tcp_port = socket_ports.get_v4(Protocol::Tcp);
let addr: SocketAddr = SocketAddr::new(
Ipv4Addr::new(127, 0, 0, 1).into(),
tcp_port.expect("no tcp_port"),
@ -178,8 +185,9 @@ fn test_nodata_where_name_exists() {
#[test]
fn test_nxdomain_where_no_name_exists() {
named_test_harness("example.toml", |_, tcp_port, _, _, _| {
named_test_harness("example.toml", |socket_ports| {
let io_loop = Runtime::new().unwrap();
let tcp_port = socket_ports.get_v4(Protocol::Tcp);
let addr: SocketAddr = SocketAddr::new(
Ipv4Addr::new(127, 0, 0, 1).into(),
tcp_port.expect("no tcp_port"),
@ -203,8 +211,9 @@ fn test_nxdomain_where_no_name_exists() {
#[test]
fn test_server_continues_on_bad_data_udp() {
named_test_harness("example.toml", |udp_port, _, _, _, _| {
named_test_harness("example.toml", |socket_ports| {
let mut io_loop = Runtime::new().unwrap();
let udp_port = socket_ports.get_v4(Protocol::Udp);
let addr: SocketAddr = SocketAddr::new(
Ipv4Addr::new(127, 0, 0, 1).into(),
udp_port.expect("no udp_port"),
@ -241,8 +250,9 @@ fn test_server_continues_on_bad_data_udp() {
#[test]
fn test_server_continues_on_bad_data_tcp() {
named_test_harness("example.toml", |_, tcp_port, _, _, _| {
named_test_harness("example.toml", |socket_ports| {
let mut io_loop = Runtime::new().unwrap();
let tcp_port = socket_ports.get_v4(Protocol::Tcp);
let addr: SocketAddr = SocketAddr::new(
Ipv4Addr::new(127, 0, 0, 1).into(),
tcp_port.expect("no tcp_port"),
@ -284,8 +294,9 @@ fn test_forward() {
//env_logger::init();
named_test_harness("example_forwarder.toml", |_, tcp_port, _, _, _| {
named_test_harness("example_forwarder.toml", |socket_ports| {
let mut io_loop = Runtime::new().unwrap();
let tcp_port = socket_ports.get_v4(Protocol::Tcp);
let addr: SocketAddr = SocketAddr::new(
Ipv4Addr::new(127, 0, 0, 1).into(),
tcp_port.expect("no tcp_port"),

View File

@ -1,6 +1,7 @@
pub mod mut_message_client;
use std::{
collections::HashMap,
env,
io::{stdout, BufRead, BufReader, Write},
net::SocketAddr,
@ -16,10 +17,50 @@ use hickory_client::{client::*, proto::xfer::DnsResponse};
#[cfg(feature = "dnssec")]
use hickory_proto::rr::dnssec::*;
use hickory_proto::rr::{rdata::A, *};
use hickory_server::server::Protocol;
use regex::Regex;
use tokio::runtime::Runtime;
use tracing::{info, warn};
#[derive(Debug, Default)]
pub struct SocketPort {
v4: u16,
v6: u16,
}
#[derive(Debug, Default)]
pub struct SocketPorts(HashMap<Protocol, SocketPort>);
impl SocketPorts {
/// This will overwrite the existing value
pub fn put(&mut self, protocol: Protocol, addr: SocketAddr) {
let entry = self.0.entry(protocol).or_default();
if addr.is_ipv4() {
entry.v4 = addr.port();
} else {
entry.v6 = addr.port();
}
}
/// Assumes there is only one V4 addr for the IP based on the usage in the Server
pub fn get_v4(&self, protocol: Protocol) -> Option<u16> {
self.0
.get(&protocol)
.iter()
.find_map(|ports| if ports.v4 == 0 { None } else { Some(ports.v4) })
}
/// Assumes there is only one V4 addr for the IP based on the usage in the Server
#[allow(unused)]
pub fn get_v6(&self, protocol: Protocol) -> Option<u16> {
self.0
.get(&protocol)
.iter()
.find_map(|ports| if ports.v6 == 0 { None } else { Some(ports.v6) })
}
}
#[cfg(feature = "dnssec")]
use self::mut_message_client::MutMessageHandle;
@ -37,7 +78,7 @@ fn collect_and_print<R: BufRead>(read: &mut R, output: &mut String) {
#[allow(dead_code)]
pub fn named_test_harness<F, R>(toml: &str, test: F)
where
F: FnOnce(Option<u16>, Option<u16>, Option<u16>, Option<u16>, Option<u16>) -> R + UnwindSafe,
F: FnOnce(SocketPorts) -> R + UnwindSafe,
{
let server_path = env::var("TDNS_WORKSPACE_ROOT").unwrap_or_else(|_| "..".to_owned());
println!("using server src path: {server_path}");
@ -104,12 +145,7 @@ where
.expect("could not start thread killer");
// These will be collected from the server startup'
// FIXME: create a wrapper type for all of these params
let mut test_udp_port = Option::<u16>::None;
let mut test_tcp_port = Option::<u16>::None;
let mut test_tls_port = Option::<u16>::None;
let mut test_https_port = Option::<u16>::None;
let mut test_quic_port = Option::<u16>::None;
let mut socket_ports = SocketPorts::default();
// we should get the correct output before 1000 lines...
let mut output = String::new();
@ -137,20 +173,19 @@ where
collect_and_print(&mut named_out, &mut output);
if let Some(addr) = addr_regex.captures(&output) {
let proto = dbg!(dbg!(&addr).get(1).expect("missing protocol").as_str());
let socket_addr = dbg!(addr.get(2).expect("missing socket addr").as_str());
let proto = addr.get(1).expect("missing protocol").as_str();
let socket_addr = addr.get(2).expect("missing socket addr").as_str();
let socket_addr = SocketAddr::from_str(socket_addr)
.expect("could not parse socket_addr")
.port();
let socket_addr =
SocketAddr::from_str(socket_addr).expect("could not parse socket_addr");
match proto {
"UDP" => test_udp_port = Some(socket_addr),
"TCP" => test_tcp_port = Some(socket_addr),
"TLS" => test_tls_port = Some(socket_addr),
"HTTPS" => test_https_port = Some(socket_addr),
"QUIC" => test_quic_port = Some(socket_addr),
_ => panic!("unknown protocol: {proto}"),
"UDP" => socket_ports.put(Protocol::Udp, socket_addr),
"TCP" => socket_ports.put(Protocol::Tcp, socket_addr),
"TLS" => socket_ports.put(Protocol::Tls, socket_addr),
"HTTPS" => socket_ports.put(Protocol::Https, socket_addr),
"QUIC" => socket_ports.put(Protocol::Quic, socket_addr),
_ => panic!("unsupported protocol: {proto}"),
}
} else if output.contains("awaiting connections...") {
found = true;
@ -160,9 +195,7 @@ where
stdout().flush().unwrap();
assert!(found);
println!(
"Test server started. ports: udp {test_udp_port:?}, tcp {test_tcp_port:?}, tls {test_tls_port:?}, https {test_https_port:?}, quic {test_quic_port:?}",
);
println!("Test server started. ports: {socket_ports:?}",);
// spawn a thread to capture stdout
let succeeded_clone = succeeded.clone();
@ -188,15 +221,7 @@ where
println!("running test...");
let result = catch_unwind(move || {
test(
test_udp_port,
test_tcp_port,
test_tls_port,
test_https_port,
test_quic_port,
)
});
let result = catch_unwind(move || test(socket_ports));
println!("test completed");
succeeded.store(true, atomic::Ordering::Relaxed);

View File

@ -9,7 +9,7 @@ use std::fmt;
/// For tracking purposes of inbound requests, which protocol was used
#[non_exhaustive]
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
pub enum Protocol {
/// User Datagram Protocol, the default for all DNS requests
Udp,