From 49585d74d62a63fbf05303fab84da6e08157fb3b Mon Sep 17 00:00:00 2001 From: cbaugus Date: Tue, 16 Dec 2025 12:01:18 -0600 Subject: [PATCH 1/2] Add DNS caching control feature for testing DNS failover scenarios MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds the DNS_CACHE_ENABLED environment variable to control DNS caching behavior during load tests. By default (false), DNS caching is disabled to ensure immediate detection of backend DNS changes. Changes: - Add DNS_CACHE_ENABLED configuration (default: false) - When disabled, connection pooling is turned off to force DNS lookups on each request (pool_max_idle_per_host=0, pool_idle_timeout=0) - When enabled, normal connection pooling and DNS caching apply - Add startup logging to show DNS cache status - Document DNS_CACHE_ENABLED in README with usage examples - Add detailed "DNS Caching Behavior" section explaining trade-offs This feature is critical for testing: - Blue/green deployments with DNS switchovers - Failover scenarios with DNS redirection - Any situation where backend IPs change during a test Trade-offs: - Disabled (default): Higher DNS load, TCP overhead, but immediate DNS change detection - Enabled: Better performance, but may miss DNS changes during test Resolves #12 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- README.md | 35 +++++++++++++++++++++++++++++++++++ src/main.rs | 19 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/README.md b/README.md index ceecb70..4308657 100644 --- a/README.md +++ b/README.md @@ -45,8 +45,43 @@ The load testing tool is configured primarily through environment variables pass * SKIP_TLS_VERIFY (Optional, default: false): Set to "true" to skip TLS/SSL certificate verification for HTTPS endpoints. Use with caution, primarily for testing environments with self-signed certificates. * CLIENT_CERT_PATH (Optional): Path to the client's PEM-encoded public certificate file for mTLS. * CLIENT_KEY_PATH (Optional): Path to the client's PEM-encoded PKCS#8 private key file for mTLS. Both `CLIENT_CERT_PATH` and `CLIENT_KEY_PATH` must be provided to enable mTLS. +* DNS_CACHE_ENABLED (Optional, default: false): Controls DNS caching behavior during load tests. + - "false" (default): Disables connection pooling, forcing fresh DNS lookups on each request. Use this when testing DNS failover scenarios or when backend IPs may change during the test. Note: This increases load on DNS servers and adds TCP handshake overhead. + - "true": Enables normal connection pooling and DNS caching. Better performance but DNS changes during the test may not be detected immediately. * RESOLVE_TARGET_ADDR (Optional): Allows overriding DNS resolution for the `TARGET_URL`. The format is `"hostname:ip_address:port"`. For example, if `TARGET_URL` is `http://example.com/api` and `RESOLVE_TARGET_ADDR` is set to `"example.com:192.168.1.50:8080"`, all requests to `example.com` will be directed to `192.168.1.50` on port `8080`. This is useful for targeting services not in DNS or for specific routing during tests. +### DNS Caching Behavior + +By default (`DNS_CACHE_ENABLED=false`), this load tester disables DNS caching to ensure that DNS changes are detected immediately during tests. This is important for testing: +- Blue/green deployments where DNS switches to new infrastructure +- Failover scenarios where DNS redirects to backup systems +- Any situation where backend IPs change during a load test + +**How it works:** +- When `DNS_CACHE_ENABLED=false`: Connection pooling is disabled, forcing each HTTP request to establish a new TCP connection, which triggers a fresh DNS lookup +- When `DNS_CACHE_ENABLED=true`: Normal connection pooling applies, connections are reused, and DNS may be cached + +**Trade-offs:** +- Disabling DNS caching (default) increases load on DNS servers and adds TCP handshake latency, but ensures immediate detection of DNS changes +- Enabling DNS caching improves performance but may cause the load tester to continue hitting old IPs even after DNS records are updated + +**Example - Testing DNS Failover:** +```bash +docker run --rm \ + -e TARGET_URL="https://api.example.com/endpoint" \ + -e DNS_CACHE_ENABLED="false" \ + -e NUM_CONCURRENT_TASKS="100" \ + -e TEST_DURATION="30m" \ + -e LOAD_MODEL_TYPE="RampRps" \ + -e MIN_RPS="50" \ + -e MAX_RPS="500" \ + cbaugus/rust-loadtester:latest +``` + +During this test, if you change the DNS record for `api.example.com`, the load tester will immediately start sending requests to the new IP address. + +**Note:** This setting works independently from `RESOLVE_TARGET_ADDR`. If you manually override DNS with `RESOLVE_TARGET_ADDR`, that takes precedence and DNS lookups are bypassed entirely. + Load Model Specific Environment Variables The behavior of the load test is determined by LOAD_MODEL_TYPE and its associated variables: diff --git a/src/main.rs b/src/main.rs index ae066de..3039b17 100644 --- a/src/main.rs +++ b/src/main.rs @@ -219,6 +219,21 @@ async fn main() -> Result<(), Box> { let mut client_builder = reqwest::Client::builder(); + // --- DNS Caching Configuration --- + let dns_cache_enabled_str = env::var("DNS_CACHE_ENABLED").unwrap_or_else(|_| "false".to_string()); + let dns_cache_enabled = dns_cache_enabled_str.to_lowercase() == "true"; + + if !dns_cache_enabled { + // Disable connection pooling to force DNS resolution on each request + client_builder = client_builder + .pool_max_idle_per_host(0) + .pool_idle_timeout(Duration::from_secs(0)); + println!("DNS caching DISABLED: Fresh DNS lookups will occur on each request (higher DNS load, detects DNS changes immediately)"); + } else { + println!("DNS caching ENABLED: Connection pooling active (better performance, DNS changes may not be detected immediately)"); + } + // --- END DNS Caching Configuration --- + // --- NEW: DNS Override Configuration --- // Reads RESOLVE_TARGET_ADDR="hostname:ip_address:port" // Example: "example.com:192.168.1.10:8080" @@ -481,6 +496,10 @@ async fn main() -> Result<(), Box> { println!(" Overall Test Duration: {:?}", overall_test_duration); println!(" Load Model: {:?}", load_model); println!(" Skip TLS Verify: {}", skip_tls_verify); + println!(" DNS Cache Enabled: {}", dns_cache_enabled); + if !dns_cache_enabled { + println!(" Note: Connection pooling disabled - each request will trigger DNS resolution"); + } if env::var("CLIENT_CERT_PATH").is_ok() && env::var("CLIENT_KEY_PATH").is_ok() { println!(" mTLS Enabled: Yes (using CLIENT_CERT_PATH and CLIENT_KEY_PATH)"); } else { From f60bfba6526592fce56e5ee138822e567f96724d Mon Sep 17 00:00:00 2001 From: cbaugus Date: Wed, 17 Dec 2025 11:26:49 -0600 Subject: [PATCH 2/2] Add apt-get upgrade to fix Ubuntu package CVEs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds 'apt-get upgrade -y' to the runtime image build process to ensure all Ubuntu base packages are updated to their latest patched versions. Fixes the following CVEs: - CVE-2024-41996 (openssl) - N/A severity - CVE-2025-45582 (tar) - N/A severity - CVE-2025-8941 (pam) - N/A severity - CVE-2024-56433 (shadow) - N/A severity - CVE-2024-2236 (libgcrypt20) - N/A severity - CVE-2022-3219 (gnupg2) - 3.3 severity Note: CVE-2016-2781 (coreutils, 6.5 severity) from 2016 is marked as "won't fix" by Ubuntu and has low exploitability in container contexts. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index b1bd591..9d78ea1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,6 +7,7 @@ RUN cargo install --path . # Use a minimal base image for the final runtime FROM ubuntu:latest RUN apt-get update \ + && apt-get upgrade -y \ && apt-get install -y --no-install-recommends \ libssl3 \ ca-certificates \