Files
Jim Meyer 8c7dd148a9 perf(net): set TCP_NODELAY on latency-sensitive TCP hops (#2220)
* perf(net): set TCP_NODELAY on all tunnel and proxy TCP hops

The sandbox tunnel added ~44 ms of latency to every small
request/response because no socket in the path disabled Nagle's
algorithm, so sub-MSS writes waited on delayed ACKs at each hop.

Set TCP_NODELAY on every latency-sensitive TCP socket:

- gateway: accepted connections on the public listener (gRPC relay
  frames and WS tunnel writes)
- CLI: edge tunnel local accept + underlying WebSocket TCP stream,
  insecure TLS connector (tonic's default connector already does
  this), and service-forward accepted sockets
- supervisor: direct-tcpip connect into the sandbox netns, TCP relay
  target dials, egress proxy accepted connections, and all upstream
  CONNECT/HTTP dials (via a new connect_upstream helper)

Setting TCP_NODELAY on connect is best-effort: a failure only costs
latency, so we log and continue rather than fail the connection.

The sandbox SSH transport rides a unix domain socket and gRPC client
channels use tonic defaults (nodelay on), so no change is needed there.

Fixes #2219

Signed-off-by: Jim Meyer <jim@meyer4hire.com>

* refactor(net): house TCP_NODELAY helper in a shared net module

Address review feedback on the TCP_NODELAY change:

- Move the shared set-nodelay helper out of supervisor_session into a
  new crate-private `net` module in openshell-supervisor-process, so
  ssh and supervisor_session no longer reach across modules through a
  pub(crate) item.
- Make the best-effort comments at each call site terse and consistent.

No behavior change; the benchmark ladder reproduces the same numbers.

Signed-off-by: Jim Meyer <jim@meyer4hire.com>

* refactor(net): consolidate TCP_NODELAY helpers into openshell_core::net

Move the best-effort TCP_NODELAY helpers into the shared openshell_core::net
module so every crate dials and configures sockets the same way:

- Add set_tcp_nodelay_best_effort (accepted/existing streams) and
  connect_tcp_nodelay_best_effort (dial + set) with unit tests.
- Migrate all call sites in openshell-cli, openshell-server, and the
  supervisor crates to the shared helpers.
- Remove the crate-private net module from openshell-supervisor-process.
- Document socket guidance in AGENTS.md (Network Sockets).

Signed-off-by: Jim Meyer <jim@meyer4hire.com>

* perf(net): set TCP_NODELAY on exec bridge and metadata server

The gateway-side single-use SSH-over-relay loopback bridge and the
sandbox IMDS metadata server were missed latency-sensitive TCP hops.
Set TCP_NODELAY on the accepted client connection and both russh client
dials of the exec bridge — interactive keystrokes and line-buffered PTY
output are the most tinygram-heavy traffic in the system — and on the
metadata server's accepted connections.

Also log unrecognized MaybeTlsStream variants in the edge tunnel so a
future TLS-backend change surfaces a silent TCP_NODELAY miss instead of
skipping it quietly.

Signed-off-by: Jim Meyer <jim@meyer4hire.com>

* perf(net): set TCP_NODELAY on openshell-sdk socket paths

The openshell-sdk crate landed on main with its own copies of the CLI's
hand-rolled sockets, which the CLI and TUI are meant to consume. Give
them the same treatment as the CLI equivalents:

- edge_tunnel: the accepted local tunnel connection and the WebSocket's
  underlying TCP socket (plain and rustls variants).
- transport: the dial in InsecureTlsConnector, tonic's custom-connector
  path.

Only these hand-rolled sockets need it. Tonic's own connector defaults
tcp_nodelay to true and applies it itself, so plain Endpoint::connect
callers were already covered.

Signed-off-by: Jim Meyer <jim@meyer4hire.com>

---------

Signed-off-by: Jim Meyer <jim@meyer4hire.com>
2026-08-04 17:59:13 +00:00

757 lines
26 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
//! Shared networking utilities for `OpenShell` crates.
//!
//! The IP-classification helpers enforce the always-blocked IP invariant
//! (loopback, link-local, unspecified) and the broader internal-IP
//! classification (adds RFC 1918 and ULA). They are used by:
//! - The sandbox proxy for runtime SSRF enforcement
//! - The mechanistic mapper for proposal filtering
//! - The gateway server for defense-in-depth validation on approval
//!
//! The socket tuning helpers ([`set_tcp_nodelay_best_effort`],
//! [`connect_tcp_nodelay_best_effort`]) help avoid the known latency
//! imposed by conflict between Nagle's algorithm and delayed ACK behaviors.
//!
use ipnet::{IpNet, Ipv4Net, Ipv6Net};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use tokio::net::TcpStream;
/// Check if a hostname is a known cloud metadata hostname that resolves to an
/// always-blocked metadata service.
///
/// This is intentionally a static name check. Do not perform DNS resolution in
/// policy validation or proposal generation paths.
pub fn is_known_metadata_hostname(host: &str) -> bool {
let normalized = host.trim().trim_end_matches('.').to_ascii_lowercase();
matches!(normalized.as_str(), "metadata.google.internal")
}
/// Check if an IP address is link-local.
///
/// Covers IPv4 `169.254.0.0/16`, IPv6 `fe80::/10`, and IPv4-mapped IPv6
/// addresses whose embedded IPv4 address is link-local (`::ffff:169.254.x.x`).
///
/// This is a point-check helper used to build the always-blocked and
/// trusted-gateway exemption predicates. For CIDR-range overlap checks see
/// [`is_always_blocked_net`].
pub fn is_link_local_ip(ip: IpAddr) -> bool {
match ip {
IpAddr::V4(v4) => v4.is_link_local(),
IpAddr::V6(v6) => {
// fe80::/10 — IPv6 link-local
if (v6.segments()[0] & 0xffc0) == 0xfe80 {
return true;
}
// ::ffff:169.254.x.x — IPv4-mapped link-local
if let Some(v4) = v6.to_ipv4_mapped() {
return v4.is_link_local();
}
false
}
}
}
/// Check if an IP address is always blocked regardless of policy.
///
/// Loopback, link-local, and unspecified addresses are never allowed even when
/// an endpoint has `allowed_ips` configured. This prevents proxy bypass
/// (loopback) and cloud metadata SSRF (link-local 169.254.x.x).
pub fn is_always_blocked_ip(ip: IpAddr) -> bool {
match ip {
IpAddr::V4(v4) => v4.is_loopback() || v4.is_link_local() || v4.is_unspecified(),
IpAddr::V6(v6) => {
if v6.is_loopback() || v6.is_unspecified() {
return true;
}
if is_link_local_ip(IpAddr::V6(v6)) {
return true;
}
// Check IPv4-mapped IPv6 (::ffff:x.x.x.x)
if let Some(v4) = v6.to_ipv4_mapped() {
return v4.is_loopback() || v4.is_unspecified();
}
false
}
}
}
/// Check if a CIDR network overlaps any always-blocked range.
///
/// Returns `true` if the network contains or overlaps loopback (`127.0.0.0/8`),
/// link-local (`169.254.0.0/16`), unspecified (`0.0.0.0`), or their IPv6
/// equivalents. A CIDR like `0.0.0.0/0` is rejected because it contains
/// always-blocked addresses.
///
/// Used at policy load time and server-side approval to reject entries that
/// would be silently blocked at runtime by [`is_always_blocked_ip`].
pub fn is_always_blocked_net(net: IpNet) -> bool {
match net {
IpNet::V4(v4net) => {
let network = v4net.network();
let broadcast = v4net.broadcast();
// Check if the range overlaps 127.0.0.0/8 (loopback)
if broadcast >= Ipv4Addr::new(127, 0, 0, 0)
&& network <= Ipv4Addr::new(127, 255, 255, 255)
{
return true;
}
// Check if the range overlaps 169.254.0.0/16 (link-local)
if broadcast >= Ipv4Addr::new(169, 254, 0, 0)
&& network <= Ipv4Addr::new(169, 254, 255, 255)
{
return true;
}
// Check if the range contains 0.0.0.0 (unspecified)
if network == Ipv4Addr::UNSPECIFIED {
return true;
}
false
}
IpNet::V6(v6net) => {
// For IPv6, check the network address itself and representative
// addresses within the range.
let network = v6net.network();
// ::1 (loopback)
if v6net.contains(&Ipv6Addr::LOCALHOST) {
return true;
}
// :: (unspecified)
if v6net.contains(&Ipv6Addr::UNSPECIFIED) {
return true;
}
// fe80::/10 (link-local) — check overlap
if (network.segments()[0] & 0xffc0) == 0xfe80 {
return true;
}
// Also check if a broad prefix contains fe80::
if v6net.contains(&Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0)) {
return true;
}
// Check IPv4-mapped IPv6 addresses. The network-address check covers
// ranges whose first address is already in a blocked range
// (e.g. ::ffff:127.0.0.1/128, ::ffff:169.254.0.1/128). The
// containment checks below catch broader prefixes that only reach
// into a blocked range further in — e.g. ::ffff:168.0.0.0/103
// has a public network address but spans ::ffff:169.254.0.0.
if network
.to_ipv4_mapped()
.is_some_and(|v4| v4.is_loopback() || v4.is_link_local() || v4.is_unspecified())
{
return true;
}
if v6net.contains(&Ipv4Addr::LOCALHOST.to_ipv6_mapped())
|| v6net.contains(&Ipv4Addr::new(169, 254, 0, 0).to_ipv6_mapped())
|| v6net.contains(&Ipv4Addr::UNSPECIFIED.to_ipv6_mapped())
{
return true;
}
false
}
}
}
const RFC1918_10_NET: Ipv4Net = Ipv4Net::new_assert(Ipv4Addr::new(10, 0, 0, 0), 8);
const RFC1918_172_NET: Ipv4Net = Ipv4Net::new_assert(Ipv4Addr::new(172, 16, 0, 0), 12);
const RFC1918_192_NET: Ipv4Net = Ipv4Net::new_assert(Ipv4Addr::new(192, 168, 0, 0), 16);
const CGNAT_NET: Ipv4Net = Ipv4Net::new_assert(Ipv4Addr::new(100, 64, 0, 0), 10);
const IETF_PROTOCOL_ASSIGNMENTS_NET: Ipv4Net = Ipv4Net::new_assert(Ipv4Addr::new(192, 0, 0, 0), 24);
const TEST_NET_1: Ipv4Net = Ipv4Net::new_assert(Ipv4Addr::new(192, 0, 2, 0), 24);
const BENCHMARKING_NET: Ipv4Net = Ipv4Net::new_assert(Ipv4Addr::new(198, 18, 0, 0), 15);
const TEST_NET_2: Ipv4Net = Ipv4Net::new_assert(Ipv4Addr::new(198, 51, 100, 0), 24);
const TEST_NET_3: Ipv4Net = Ipv4Net::new_assert(Ipv4Addr::new(203, 0, 113, 0), 24);
const LIMITED_BROADCAST_NET: Ipv4Net = Ipv4Net::new_assert(Ipv4Addr::BROADCAST, 32);
const IPV6_ULA_NET: Ipv6Net = Ipv6Net::new_assert(Ipv6Addr::new(0xfc00, 0, 0, 0, 0, 0, 0, 0), 7);
const NON_HARD_INTERNAL_V4_NETS: [Ipv4Net; 10] = [
RFC1918_10_NET,
RFC1918_172_NET,
RFC1918_192_NET,
CGNAT_NET,
IETF_PROTOCOL_ASSIGNMENTS_NET,
TEST_NET_1,
BENCHMARKING_NET,
TEST_NET_2,
TEST_NET_3,
LIMITED_BROADCAST_NET,
];
fn ipv4_nets_intersect(left: Ipv4Net, right: Ipv4Net) -> bool {
left.network() <= right.broadcast() && right.network() <= left.broadcast()
}
fn ipv6_nets_intersect(left: Ipv6Net, right: Ipv6Net) -> bool {
left.network() <= right.broadcast() && right.network() <= left.broadcast()
}
fn ipv4_net_to_mapped_ipv6(net: Ipv4Net) -> Ipv6Net {
Ipv6Net::new_assert(net.network().to_ipv6_mapped(), 96_u8 + net.prefix_len())
}
/// Check if an IP address is internal (loopback, private RFC 1918, link-local,
/// or unspecified).
///
/// This is a broader check than [`is_always_blocked_ip`] — it includes RFC 1918
/// private ranges (`10/8`, `172.16/12`, `192.168/16`), CGNAT (`100.64.0.0/10`,
/// RFC 6598), other special-use ranges, and IPv6 ULA (`fc00::/7`) which are
/// allowable via `allowed_ips` but blocked by default without one.
///
/// Used by the proxy's default SSRF path and the mechanistic mapper to detect
/// when `allowed_ips` should be populated in proposals.
pub fn is_internal_ip(ip: IpAddr) -> bool {
match ip {
IpAddr::V4(v4) => is_internal_v4(v4),
IpAddr::V6(v6) => {
if v6.is_loopback() || v6.is_unspecified() {
return true;
}
if is_link_local_ip(IpAddr::V6(v6)) {
return true;
}
// fc00::/7 — IPv6 unique local addresses (ULA)
if (v6.segments()[0] & 0xfe00) == 0xfc00 {
return true;
}
// Check IPv4-mapped IPv6 (::ffff:x.x.x.x)
if let Some(v4) = v6.to_ipv4_mapped() {
return is_internal_v4(v4);
}
false
}
}
}
/// Check if a CIDR network intersects any address range classified by
/// [`is_internal_ip`].
pub fn is_internal_net(net: IpNet) -> bool {
if is_always_blocked_net(net) {
return true;
}
match net {
IpNet::V4(net) => NON_HARD_INTERNAL_V4_NETS
.iter()
.any(|internal| ipv4_nets_intersect(net, *internal)),
IpNet::V6(net) => {
ipv6_nets_intersect(net, IPV6_ULA_NET)
|| NON_HARD_INTERNAL_V4_NETS
.iter()
.any(|internal| ipv6_nets_intersect(net, ipv4_net_to_mapped_ipv6(*internal)))
}
}
}
/// IPv4 internal address check covering RFC 1918, CGNAT (RFC 6598), and other
/// special-use ranges that should never be reachable from sandbox egress.
fn is_internal_v4(v4: Ipv4Addr) -> bool {
// Prefer the stable `Ipv4Addr` predicates. `is_documentation()` (RFC 5737)
// covers all three TEST-NET ranges, including 192.0.2.0/24 (TEST-NET-1) which
// the previous manual checks missed.
if v4.is_loopback()
|| v4.is_private()
|| v4.is_link_local()
|| v4.is_unspecified()
|| v4.is_documentation()
|| v4.is_broadcast()
{
return true;
}
let octets = v4.octets();
// The ranges below have no stable std predicate yet, so keep them manual.
// 100.64.0.0/10 — CGNAT / shared address space (RFC 6598; `is_shared` is
// unstable). Commonly used by cloud VPC peering, Tailscale, and similar overlays.
if octets[0] == 100 && (octets[1] & 0xC0) == 64 {
return true;
}
// 192.0.0.0/24 — IETF protocol assignments (RFC 6890; no stable predicate).
if octets[0] == 192 && octets[1] == 0 && octets[2] == 0 {
return true;
}
// 198.18.0.0/15 — benchmarking (RFC 2544; `is_benchmarking` is unstable).
if octets[0] == 198 && (octets[1] & 0xFE) == 18 {
return true;
}
false
}
/// Enable `TCP_NODELAY` on a stream, logging (not returning) any failure.
///
/// Disabling Nagle's algorithm keeps small writes from waiting on delayed ACKs.
/// It's a latency optimization: if it fails the connection still works, just a
/// bit slower, so there is nothing for the caller to act on — we log and move on.
pub fn set_tcp_nodelay_best_effort(stream: &TcpStream) {
if let Err(e) = stream.set_nodelay(true) {
tracing::debug!(error = %e, "failed to set TCP_NODELAY");
}
}
/// Connect to `addrs`, then enable `TCP_NODELAY` on a best-effort basis, propagating
/// any errors from `TcpStream::connect`.
///
/// The returned stream is not *guaranteed* to have `TCP_NODELAY` set.
pub async fn connect_tcp_nodelay_best_effort(addrs: &[SocketAddr]) -> std::io::Result<TcpStream> {
let stream = TcpStream::connect(addrs).await?;
set_tcp_nodelay_best_effort(&stream);
Ok(stream)
}
#[cfg(test)]
mod tests {
use super::*;
// -- is_known_metadata_hostname --
#[test]
fn test_known_metadata_hostname_accepts_gcp_variants() {
assert!(is_known_metadata_hostname("metadata.google.internal"));
assert!(is_known_metadata_hostname("METADATA.GOOGLE.INTERNAL"));
assert!(is_known_metadata_hostname("metadata.google.internal."));
}
#[test]
fn test_known_metadata_hostname_rejects_public_hosts() {
assert!(!is_known_metadata_hostname("api.github.com"));
assert!(!is_known_metadata_hostname(""));
}
// -- is_link_local_ip --
#[test]
fn test_link_local_ip_v4() {
assert!(is_link_local_ip(IpAddr::V4(Ipv4Addr::new(169, 254, 0, 1))));
assert!(is_link_local_ip(IpAddr::V4(Ipv4Addr::new(
169, 254, 169, 254
))));
assert!(is_link_local_ip(IpAddr::V4(Ipv4Addr::new(
169, 254, 255, 255
))));
}
#[test]
fn test_link_local_ip_v6_fe80() {
assert!(is_link_local_ip(IpAddr::V6(Ipv6Addr::new(
0xfe80, 0, 0, 0, 0, 0, 0, 1
))));
// Upper boundary of fe80::/10 (febf:...)
assert!(is_link_local_ip(IpAddr::V6(Ipv6Addr::new(
0xfebf, 0, 0, 0, 0, 0, 0, 1
))));
}
#[test]
fn test_link_local_ip_v6_mapped_v4() {
let mapped = Ipv4Addr::new(169, 254, 1, 2).to_ipv6_mapped();
assert!(is_link_local_ip(IpAddr::V6(mapped)));
}
#[test]
fn test_link_local_ip_not_loopback() {
assert!(!is_link_local_ip(IpAddr::V4(Ipv4Addr::LOCALHOST)));
assert!(!is_link_local_ip(IpAddr::V6(Ipv6Addr::LOCALHOST)));
}
#[test]
fn test_link_local_ip_not_unspecified() {
assert!(!is_link_local_ip(IpAddr::V4(Ipv4Addr::UNSPECIFIED)));
assert!(!is_link_local_ip(IpAddr::V6(Ipv6Addr::UNSPECIFIED)));
}
#[test]
fn test_link_local_ip_not_rfc1918() {
assert!(!is_link_local_ip(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1))));
assert!(!is_link_local_ip(IpAddr::V4(Ipv4Addr::new(192, 168, 0, 1))));
assert!(!is_link_local_ip(IpAddr::V4(Ipv4Addr::new(172, 16, 0, 1))));
}
#[test]
fn test_link_local_ip_not_public() {
assert!(!is_link_local_ip(IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8))));
assert!(!is_link_local_ip(IpAddr::V6(Ipv6Addr::new(
0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8888
))));
}
#[test]
fn test_link_local_ip_not_v6_mapped_loopback() {
let mapped = Ipv4Addr::LOCALHOST.to_ipv6_mapped();
assert!(!is_link_local_ip(IpAddr::V6(mapped)));
}
// -- is_always_blocked_ip --
#[test]
fn test_always_blocked_ip_loopback_v4() {
assert!(is_always_blocked_ip(IpAddr::V4(Ipv4Addr::LOCALHOST)));
assert!(is_always_blocked_ip(IpAddr::V4(Ipv4Addr::new(
127, 0, 0, 2
))));
}
#[test]
fn test_always_blocked_ip_link_local_v4() {
assert!(is_always_blocked_ip(IpAddr::V4(Ipv4Addr::new(
169, 254, 169, 254
))));
assert!(is_always_blocked_ip(IpAddr::V4(Ipv4Addr::new(
169, 254, 0, 1
))));
}
#[test]
fn test_always_blocked_ip_loopback_v6() {
assert!(is_always_blocked_ip(IpAddr::V6(Ipv6Addr::LOCALHOST)));
}
#[test]
fn test_always_blocked_ip_link_local_v6() {
assert!(is_always_blocked_ip(IpAddr::V6(Ipv6Addr::new(
0xfe80, 0, 0, 0, 0, 0, 0, 1
))));
}
#[test]
fn test_always_blocked_ip_unspecified_v4() {
assert!(is_always_blocked_ip(IpAddr::V4(Ipv4Addr::UNSPECIFIED)));
}
#[test]
fn test_always_blocked_ip_unspecified_v6() {
assert!(is_always_blocked_ip(IpAddr::V6(Ipv6Addr::UNSPECIFIED)));
}
#[test]
fn test_always_blocked_ip_ipv4_mapped_v6_loopback() {
let v6 = Ipv4Addr::LOCALHOST.to_ipv6_mapped();
assert!(is_always_blocked_ip(IpAddr::V6(v6)));
}
#[test]
fn test_always_blocked_ip_ipv4_mapped_v6_link_local() {
let v6 = Ipv4Addr::new(169, 254, 169, 254).to_ipv6_mapped();
assert!(is_always_blocked_ip(IpAddr::V6(v6)));
}
#[test]
fn test_always_blocked_ip_allows_rfc1918() {
assert!(!is_always_blocked_ip(IpAddr::V4(Ipv4Addr::new(
10, 0, 0, 1
))));
assert!(!is_always_blocked_ip(IpAddr::V4(Ipv4Addr::new(
172, 16, 0, 1
))));
assert!(!is_always_blocked_ip(IpAddr::V4(Ipv4Addr::new(
192, 168, 0, 1
))));
}
#[test]
fn test_always_blocked_ip_allows_public() {
assert!(!is_always_blocked_ip(IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8))));
assert!(!is_always_blocked_ip(IpAddr::V6(Ipv6Addr::new(
0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8888
))));
}
// -- is_always_blocked_net --
#[test]
fn test_always_blocked_net_loopback_v4() {
let net: IpNet = "127.0.0.0/8".parse().unwrap();
assert!(is_always_blocked_net(net));
}
#[test]
fn test_always_blocked_net_link_local_v4() {
let net: IpNet = "169.254.0.0/16".parse().unwrap();
assert!(is_always_blocked_net(net));
}
#[test]
fn test_always_blocked_net_unspecified_v4() {
let net: IpNet = "0.0.0.0/32".parse().unwrap();
assert!(is_always_blocked_net(net));
}
#[test]
fn test_always_blocked_net_loopback_v6() {
let net: IpNet = "::1/128".parse().unwrap();
assert!(is_always_blocked_net(net));
}
#[test]
fn test_always_blocked_net_link_local_v6() {
let net: IpNet = "fe80::/10".parse().unwrap();
assert!(is_always_blocked_net(net));
}
#[test]
fn test_always_blocked_net_ipv4_mapped_v6_loopback() {
let net: IpNet = "::ffff:127.0.0.1/128".parse().unwrap();
assert!(is_always_blocked_net(net));
}
#[test]
fn test_always_blocked_net_allows_rfc1918() {
let net10: IpNet = "10.0.0.0/8".parse().unwrap();
let net172: IpNet = "172.16.0.0/12".parse().unwrap();
let net192: IpNet = "192.168.0.0/16".parse().unwrap();
assert!(!is_always_blocked_net(net10));
assert!(!is_always_blocked_net(net172));
assert!(!is_always_blocked_net(net192));
}
#[test]
fn test_always_blocked_net_allows_public() {
let net: IpNet = "8.8.8.0/24".parse().unwrap();
assert!(!is_always_blocked_net(net));
}
#[test]
fn test_always_blocked_net_single_ip_loopback() {
let net: IpNet = "127.0.0.1/32".parse().unwrap();
assert!(is_always_blocked_net(net));
}
#[test]
fn test_always_blocked_net_single_ip_metadata() {
let net: IpNet = "169.254.169.254/32".parse().unwrap();
assert!(is_always_blocked_net(net));
}
#[test]
fn test_always_blocked_net_broad_cidr_containing_blocked() {
// 0.0.0.0/0 contains everything including unspecified, loopback, link-local
let net: IpNet = "0.0.0.0/0".parse().unwrap();
assert!(is_always_blocked_net(net));
}
#[test]
fn test_always_blocked_net_v6_broad_containing_loopback() {
let net: IpNet = "::/0".parse().unwrap();
assert!(is_always_blocked_net(net));
}
#[test]
fn test_always_blocked_net_v6_ipv4_mapped_loopback_single() {
let net: IpNet = "::ffff:127.0.0.1/128".parse().unwrap();
assert!(is_always_blocked_net(net));
}
#[test]
fn test_always_blocked_net_v6_ipv4_mapped_link_local_single() {
let net: IpNet = "::ffff:169.254.0.1/128".parse().unwrap();
assert!(is_always_blocked_net(net));
}
#[test]
fn test_always_blocked_net_v6_ipv4_mapped_broad_spans_link_local() {
// ::ffff:168.0.0.0/103 has a public network address (168.0.0.0) but
// the range covers 168.0.0.0–169.255.255.255, which includes the
// link-local block 169.254.0.0/16.
let net: IpNet = "::ffff:168.0.0.0/103".parse().unwrap();
assert!(is_always_blocked_net(net));
}
#[test]
fn test_always_blocked_net_v6_ipv4_mapped_broad_spans_loopback() {
// ::ffff:64.0.0.0/98 has a public network address (64.0.0.0) but the
// range covers 64.0.0.0–127.255.255.255, which includes loopback.
let net: IpNet = "::ffff:64.0.0.0/98".parse().unwrap();
assert!(is_always_blocked_net(net));
}
#[test]
fn test_always_blocked_net_v6_ipv4_mapped_allows_public() {
// ::ffff:8.8.8.8/128 is a public address — should not be blocked.
let net: IpNet = "::ffff:8.8.8.8/128".parse().unwrap();
assert!(!is_always_blocked_net(net));
}
// -- is_internal_net --
#[test]
fn test_internal_net_rfc1918_contained_and_supernet() {
for cidr in ["10.1.0.0/16", "8.0.0.0/5"] {
assert!(is_internal_net(cidr.parse().unwrap()), "{cidr}");
}
}
#[test]
fn test_internal_net_cgnat_contained_and_supernet() {
for cidr in ["100.64.0.0/10", "100.0.0.0/9"] {
assert!(is_internal_net(cidr.parse().unwrap()), "{cidr}");
}
}
#[test]
fn test_internal_net_ipv4_special_use_ranges() {
for cidr in [
"192.0.0.0/24",
"192.0.2.0/24",
"198.18.0.0/15",
"198.51.100.0/24",
"203.0.113.0/24",
"255.255.255.255/32",
] {
assert!(is_internal_net(cidr.parse().unwrap()), "{cidr}");
}
}
#[test]
fn test_internal_net_ipv6_ula() {
for cidr in ["fc00::/7", "fd00::/8"] {
assert!(is_internal_net(cidr.parse().unwrap()), "{cidr}");
}
}
#[test]
fn test_internal_net_ipv4_mapped_cgnat_supernet() {
let net: IpNet = "::ffff:100.0.0.0/105".parse().unwrap();
assert!(is_internal_net(net));
}
#[test]
fn test_internal_net_always_blocked() {
for cidr in ["127.0.0.0/8", "fe80::/10"] {
assert!(is_internal_net(cidr.parse().unwrap()), "{cidr}");
}
}
#[test]
fn test_internal_net_allows_large_public_ranges() {
for cidr in ["8.0.0.0/8", "::ffff:8.0.0.0/104"] {
assert!(!is_internal_net(cidr.parse().unwrap()), "{cidr}");
}
}
// -- is_internal_ip --
#[test]
fn test_internal_ip_rfc1918() {
assert!(is_internal_ip(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1))));
assert!(is_internal_ip(IpAddr::V4(Ipv4Addr::new(172, 16, 0, 1))));
assert!(is_internal_ip(IpAddr::V4(Ipv4Addr::new(192, 168, 0, 1))));
}
#[test]
fn test_internal_ip_loopback() {
assert!(is_internal_ip(IpAddr::V4(Ipv4Addr::LOCALHOST)));
assert!(is_internal_ip(IpAddr::V6(Ipv6Addr::LOCALHOST)));
}
#[test]
fn test_internal_ip_link_local() {
assert!(is_internal_ip(IpAddr::V4(Ipv4Addr::new(
169, 254, 169, 254
))));
}
#[test]
fn test_internal_ip_unspecified() {
assert!(is_internal_ip(IpAddr::V4(Ipv4Addr::UNSPECIFIED)));
assert!(is_internal_ip(IpAddr::V6(Ipv6Addr::UNSPECIFIED)));
}
#[test]
fn test_internal_ip_v6_ula() {
assert!(is_internal_ip(IpAddr::V6(Ipv6Addr::new(
0xfc00, 0, 0, 0, 0, 0, 0, 1
))));
assert!(is_internal_ip(IpAddr::V6(Ipv6Addr::new(
0xfd00, 0, 0, 0, 0, 0, 0, 1
))));
}
#[test]
fn test_internal_ip_allows_public() {
assert!(!is_internal_ip(IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8))));
assert!(!is_internal_ip(IpAddr::V6(Ipv6Addr::new(
0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8888
))));
}
#[test]
fn test_internal_ip_ipv4_mapped_v6() {
let v6 = Ipv4Addr::new(10, 0, 0, 1).to_ipv6_mapped();
assert!(is_internal_ip(IpAddr::V6(v6)));
let v6_public = Ipv4Addr::new(8, 8, 8, 8).to_ipv6_mapped();
assert!(!is_internal_ip(IpAddr::V6(v6_public)));
}
#[test]
fn test_internal_ip_cgnat() {
// 100.64.0.0/10 — CGNAT / shared address space (RFC 6598)
assert!(is_internal_ip(IpAddr::V4(Ipv4Addr::new(100, 64, 0, 1))));
assert!(is_internal_ip(IpAddr::V4(Ipv4Addr::new(100, 100, 50, 3))));
assert!(is_internal_ip(IpAddr::V4(Ipv4Addr::new(
100, 127, 255, 255
))));
// Just outside the /10 boundary
assert!(!is_internal_ip(IpAddr::V4(Ipv4Addr::new(100, 128, 0, 1))));
assert!(!is_internal_ip(IpAddr::V4(Ipv4Addr::new(
100, 63, 255, 255
))));
}
#[test]
fn test_internal_ip_special_use_ranges() {
// 192.0.0.0/24 — IETF protocol assignments
assert!(is_internal_ip(IpAddr::V4(Ipv4Addr::new(192, 0, 0, 1))));
// 198.18.0.0/15 — benchmarking
assert!(is_internal_ip(IpAddr::V4(Ipv4Addr::new(198, 18, 0, 1))));
assert!(is_internal_ip(IpAddr::V4(Ipv4Addr::new(198, 19, 255, 255))));
// 192.0.2.0/24 — TEST-NET-1 (RFC 5737), now covered via is_documentation()
assert!(is_internal_ip(IpAddr::V4(Ipv4Addr::new(192, 0, 2, 1))));
// 198.51.100.0/24 — TEST-NET-2
assert!(is_internal_ip(IpAddr::V4(Ipv4Addr::new(198, 51, 100, 1))));
// 203.0.113.0/24 — TEST-NET-3
assert!(is_internal_ip(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 1))));
// 255.255.255.255 — limited broadcast (RFC 919), via is_broadcast()
assert!(is_internal_ip(IpAddr::V4(Ipv4Addr::BROADCAST)));
}
#[test]
fn test_internal_ip_ipv6_mapped_cgnat() {
let v6 = Ipv4Addr::new(100, 64, 0, 1).to_ipv6_mapped();
assert!(is_internal_ip(IpAddr::V6(v6)));
}
// -- tcp_nodelay helpers --
#[tokio::test]
async fn set_tcp_nodelay_best_effort_enables_nodelay() {
let listener = tokio::net::TcpListener::bind("127.0.0.1:0")
.await
.expect("bind");
let addr = listener.local_addr().expect("local addr");
let stream = TcpStream::connect(addr).await.expect("connect");
set_tcp_nodelay_best_effort(&stream);
assert!(stream.nodelay().expect("query TCP_NODELAY"));
}
#[tokio::test]
async fn connect_tcp_nodelay_best_effort_sets_nodelay() {
let listener = tokio::net::TcpListener::bind("127.0.0.1:0")
.await
.expect("bind");
let addr = listener.local_addr().expect("local addr");
let stream = connect_tcp_nodelay_best_effort(&[addr])
.await
.expect("connect");
assert!(stream.nodelay().expect("query TCP_NODELAY"));
}
}