Skip to content
This repository was archived by the owner on May 9, 2026. It is now read-only.

Release/0.3.5#52

Merged
frankovo merged 4 commits into
mainfrom
release/0.3.5
May 1, 2026
Merged

Release/0.3.5#52
frankovo merged 4 commits into
mainfrom
release/0.3.5

Conversation

@frankovo
Copy link
Copy Markdown
Member

@frankovo frankovo commented May 1, 2026

No description provided.

frankovo added 4 commits May 1, 2026 02:55
…ocol/DNSSEC handling

- Add _doh_clients dict (AsyncClient per resolver) and _get_doh_client() so
  DoH queries reuse HTTP/2 connections instead of opening a new TLS handshake
  per query. Measured improvement: ~350ms avg down to ~170ms avg on mobile.

- Add _dot_connections dict (StreamReader/Writer per resolver) and
  _get_dot_connection() so DoT queries reuse TLS connections instead of
  handshaking on every query. Measured improvement: 795-1759ms avg down to
  200-460ms avg on mobile hotspot.

- Add close() to drain both pools. Must be awaited after run_benchmark.
  Used via single _run() coroutine in CLI to avoid closed event loop errors.

- Add TLS_ERROR to QueryStatus enum for ssl.SSLError in query_single_dot.
  Previously mapped to CONNECTION_REFUSED which was misleading.

- Evict pooled DoT connection on timeout, SSL error, and unknown errors so
  retries always get a clean connection.

- Fix double time.time() calls in DoH/DoT timeout and exception handlers.
  Two consecutive calls produced inconsistent end_time and latency_ms values.
  Capture end_time once at the top of each handler.

- Add httpx.HTTPStatusError handler in query_single_doh mapped to SERVFAIL
  with HTTP status code in error_message. Previously fell through to the
  generic Exception handler and returned UNKNOWN_ERROR.

- Pass protocol and doh_urls to _run_warmup and _run_fast_warmup so warmup
  queries use the same protocol as the benchmark. Previously always used
  plain UDP, meaning DoH/DoT warmup did not prime the right connections.

- Validate DoH URL presence early in run_benchmark before dispatching tasks
  so a missing URL raises a clear ValueError upfront instead of mid-benchmark.

- Change enable_dnssec=True hardcoded to enable_dnssec=dnssec_validate so
  the DO bit and RRSIG overhead only apply when --dnssec-validate is passed.
  Plain benchmarks no longer pay the extra latency unconditionally.

- Add Tuple to typing imports required by _dot_connections type annotation.

- Remove dead commented-out import dns.query.
…y stats and fix typo

- Add completed column to _create_dataframe that is True for both SUCCESS
  and DNSSEC_FAILED. A DNSSEC_FAILED query completed successfully at the
  network level — only the AD flag validation failed client-side — so its
  latency is valid and should be included in all latency statistics.

- Switch all latency filters from success==True to completed==True across
  get_resolver_statistics, get_overall_statistics, get_domain_statistics,
  get_record_type_statistics, and get_protocol_statistics. Success rate
  reporting remains on success only so the two metrics stay separate.

  Before this fix, using --dnssec-validate against unsigned domains caused
  all queries to return DNSSEC_FAILED, making avg/median/p95 show 0.0 and
  fastest/slowest resolver show N/A in the summary.

- Fix typo: "interation" -> "iteration" in _create_dataframe. The wrong
  column name silently produced NaN in all downstream CSV and Excel exports
  for the iteration column.
…tion cleanup, and UX fixes

benchmark:
- Move _resolve_protocol_and_doh_urls before benchmark_started flag so bad
  --doh/--dot flag combos fail before any output or side effects.
- Add explicit except click.UsageError: raise so Click formats usage errors
  cleanly without triggering the feedback prompt or error message.
- Merge two asyncio.run calls into single _run() coroutine to fix
  RuntimeError: Event loop is closed from calling asyncio.run(engine.close())
  after asyncio.run(run_benchmark()) had already closed the loop.
- Skip DNSSEC signed-domain warning for custom domain files. The check
  compared user domains against DOMAINS_DATABASE which has no knowledge of
  user-supplied domains, producing near-constant false positive warnings.
  Warning now only shown with --use-defaults where signed status is known.
- Fix PDF export catching RuntimeError with wrong error message. Changed to
  broad Exception with "PDF export failed" message. Progress bar now advances
  even on PDF failure to keep the bar consistent.
- Remove redundant bare print() showing DNSSEC ENABLED/DISABLED. Duplicated
  the config block line, used print instead of click.echo, and ignored --quiet.
- Update DNSSEC config message to reflect enable_dnssec=dnssec_validate:
  off means no DO bit and no collection; enforced means DO bit set with a
  note that success rate and DNSSEC outcome are separate metrics.
- Rename summary line from "DNSSEC validated" to "DNSSEC AD validated" so
  users understand this is specifically the AD flag count, not query success.
- Update enable_dnssec comment to reflect that DO bit is only set when
  --dnssec-validate is passed, not unconditionally.

top:
- Wire doh, dot, doh_url, dnssec_validate into _resolve_protocol_and_doh_urls,
  DNSQueryEngine, and run_benchmark. Flags were declared but silently ignored.
- Switch domain loading from load_domains_from_file to parse_domains_input
  so --domains accepts both file paths and inline comma-separated lists.
- Merge asyncio.run and engine.close into single _run() coroutine.
- Add except click.UsageError: raise to let Click handle usage errors cleanly.

compare:
- Same protocol/DNSSEC wiring as top.
- Same parse_domains_input fix as top.
- Same _run() coroutine fix as top.
- Guard sorted() against nan avg_latency using math.isnan check with
  float("inf") fallback. Resolvers with zero successes produce nan which
  raises TypeError in Python 3.12 comparisons.
- Add protocol field to JSON export output.

monitoring:
- Same protocol/DNSSEC wiring as top and compare.
- Move DNSQueryEngine construction outside the while loop. Previously a new
  engine was created every check interval, discarding the connection pool and
  paying full TLS handshake cost on every check.
- Fix RuntimeError: Event loop is closed on Ctrl+C. asyncio.run() closes the
  loop on each iteration. The finally block called asyncio.run(engine.close())
  on the already-closed loop and printed a full traceback. Fixed by creating
  a fresh event loop in finally specifically for cleanup, wrapped in
  try/except to suppress residual errors on exit.
- Remove bare raise from except Exception so all errors show a clean click
  error message instead of a traceback to the user.
- Switch resolver loading from load_resolvers_from_file to
  parse_resolvers_input so --resolvers accepts names, IPs, and file paths.
… new protocol and dnssec changes

- Update tests to reflect enable_dnssec=dnssec_validate (no longer hardcoded True).
- Add coverage for TLS_ERROR status returned on ssl.SSLError in query_single_dot.
- Add coverage for httpx.HTTPStatusError mapped to SERVFAIL in query_single_doh.
- Add coverage for completed column in BenchmarkAnalyzer including DNSSEC_FAILED
  queries in latency statistics.
- Update warmup tests to verify protocol is passed through to _run_warmup
  and _run_fast_warmup.
@frankovo frankovo merged commit 9470dc8 into main May 1, 2026
4 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant