133 lines
4.9 KiB
Rust
133 lines
4.9 KiB
Rust
//! Network testing utility functions for Zebra.
|
|
|
|
use std::env;
|
|
|
|
/// The name of the env var that skips Zebra tests which need reliable,
|
|
/// fast network connectivity.
|
|
///
|
|
/// We use a constant so that the compiler detects typos.
|
|
const ZEBRA_SKIP_NETWORK_TESTS: &str = "ZEBRA_SKIP_NETWORK_TESTS";
|
|
|
|
/// The name of the env var that skips Zebra's IPv6 tests.
|
|
///
|
|
/// We use a constant so that the compiler detects typos.
|
|
const ZEBRA_SKIP_IPV6_TESTS: &str = "ZEBRA_SKIP_IPV6_TESTS";
|
|
|
|
/// Should we skip Zebra tests which need reliable, fast network connectivity?
|
|
//
|
|
// TODO: separate "good and reliable" from "any network"?
|
|
#[allow(clippy::print_stderr)]
|
|
pub fn zebra_skip_network_tests() -> bool {
|
|
if env::var_os(ZEBRA_SKIP_NETWORK_TESTS).is_some() {
|
|
// This message is captured by the test runner, use
|
|
// `cargo test -- --nocapture` to see it.
|
|
eprintln!("Skipping network test because '$ZEBRA_SKIP_NETWORK_TESTS' is set.");
|
|
return true;
|
|
}
|
|
|
|
false
|
|
}
|
|
|
|
/// Should we skip Zebra tests which need a local IPv6 network stack and
|
|
/// IPv6 interface addresses?
|
|
///
|
|
/// Since `zebra_skip_network_tests` only disables tests which need reliable network connectivity,
|
|
/// we allow IPv6 tests even when `ZEBRA_SKIP_NETWORK_TESTS` is set.
|
|
#[allow(clippy::print_stderr)]
|
|
pub fn zebra_skip_ipv6_tests() -> bool {
|
|
if env::var_os(ZEBRA_SKIP_IPV6_TESTS).is_some() {
|
|
eprintln!("Skipping IPv6 network test because '$ZEBRA_SKIP_IPV6_TESTS' is set.");
|
|
return true;
|
|
}
|
|
|
|
// TODO: if we separate "good and reliable" from "any network",
|
|
// also skip IPv6 tests when we're skipping all network tests.
|
|
false
|
|
}
|
|
|
|
#[cfg(windows)]
|
|
/// Returns a random port number from the ephemeral port range.
|
|
///
|
|
/// Does not check if the port is already in use. It's impossible to do this
|
|
/// check in a reliable, cross-platform way.
|
|
///
|
|
/// ## Usage
|
|
///
|
|
/// If you want a once-off random unallocated port, use
|
|
/// `random_unallocated_port`. Don't use this function if you don't need
|
|
/// to - it has a small risk of port conflcits.
|
|
///
|
|
/// Use this function when you need to use the same random port multiple
|
|
/// times. For example: setting up both ends of a connection, or re-using
|
|
/// the same port multiple times.
|
|
pub fn random_known_port() -> u16 {
|
|
use rand::Rng;
|
|
// Use the intersection of the IANA/Windows/macOS ephemeral port range,
|
|
// and the Linux ephemeral port range:
|
|
// - https://en.wikipedia.org/wiki/Ephemeral_port#Range
|
|
// excluding ports less than 53500, to avoid:
|
|
// - typical Hyper-V reservations up to 52000:
|
|
// - https://github.com/googlevr/gvr-unity-sdk/issues/1002
|
|
// - https://github.com/docker/for-win/issues/3171
|
|
// - the MOM-Clear port 51515
|
|
// - https://docs.microsoft.com/en-us/troubleshoot/windows-server/networking/service-overview-and-network-port-requirements
|
|
// - the LDAP Kerberos byte-swapped reservation 53249
|
|
// - https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/ldap-kerberos-server-reset-tcp-sessions
|
|
// - macOS and Windows sequential ephemeral port allocations,
|
|
// starting from 49152:
|
|
// - https://dataplane.org/ephemeralports.html
|
|
|
|
rand::thread_rng().gen_range(53500..60999)
|
|
}
|
|
|
|
#[cfg(not(windows))]
|
|
/// Uses the "magic" port number that tells the operating system to
|
|
/// choose a random unallocated port.
|
|
///
|
|
/// The OS chooses a different port each time it opens a connection or
|
|
/// listener with this magic port number.
|
|
///
|
|
/// Creates a TcpListener to find a random unallocated port, then drops the TcpListener to close the socket.
|
|
///
|
|
/// Returns the unallocated port number.
|
|
///
|
|
/// ## Usage
|
|
///
|
|
/// If you want a once-off random unallocated port, use
|
|
/// `random_unallocated_port`. Don't use this function if you don't need
|
|
/// to - it has a small risk of port conflicts when there is a delay
|
|
/// between this fn call and binding the tcp listener.
|
|
///
|
|
/// Use this function when you need to use the same random port multiple
|
|
/// times. For example: setting up both ends of a connection, or re-using
|
|
/// the same port multiple times.
|
|
///
|
|
/// ## Panics
|
|
///
|
|
/// If the OS finds no available ports
|
|
///
|
|
/// If there is an OS error when getting the socket address
|
|
pub fn random_known_port() -> u16 {
|
|
use std::net::{Ipv4Addr, SocketAddrV4, TcpListener};
|
|
|
|
let host_ip = Ipv4Addr::new(127, 0, 0, 1);
|
|
let socket = TcpListener::bind(SocketAddrV4::new(host_ip, random_unallocated_port()))
|
|
.expect("needs an available port")
|
|
.local_addr()
|
|
.expect("OS error: could not get socket addr");
|
|
socket.port()
|
|
}
|
|
|
|
/// Returns the "magic" port number that tells the operating system to
|
|
/// choose a random unallocated port.
|
|
///
|
|
/// The OS chooses a different port each time it opens a connection or
|
|
/// listener with this magic port number.
|
|
///
|
|
/// ## Usage
|
|
///
|
|
/// See the usage note for `random_known_port`.
|
|
pub fn random_unallocated_port() -> u16 {
|
|
0
|
|
}
|