ogham/dog
A command-line DNS client.
Stale — last commit 2y ago
weakest axisnon-standard license (EUPL-1.2); last commit was 2y ago
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓17 active contributors
- ✓EUPL-1.2 licensed
- ✓CI configured
Show all 7 evidence items →Show less
- ✓Tests present
- ⚠Stale — last commit 2y ago
- ⚠Single-maintainer risk — top contributor 82% of recent commits
- ⚠Non-standard license (EUPL-1.2) — review terms
What would change the summary?
- →Use as dependency Concerns → Mixed if: clarify license terms
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Forkable" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/ogham/dog)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/ogham/dog on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: ogham/dog
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/ogham/dog shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
WAIT — Stale — last commit 2y ago
- 17 active contributors
- EUPL-1.2 licensed
- CI configured
- Tests present
- ⚠ Stale — last commit 2y ago
- ⚠ Single-maintainer risk — top contributor 82% of recent commits
- ⚠ Non-standard license (EUPL-1.2) — review terms
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live ogham/dog
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/ogham/dog.
What it runs against: a local clone of ogham/dog — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in ogham/dog | Confirms the artifact applies here, not a fork |
| 2 | License is still EUPL-1.2 | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 739 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of ogham/dog. If you don't
# have one yet, run these first:
#
# git clone https://github.com/ogham/dog.git
# cd dog
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of ogham/dog and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "ogham/dog(\\.git)?\\b" \\
&& ok "origin remote is ogham/dog" \\
|| miss "origin remote is not ogham/dog (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(EUPL-1\\.2)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"EUPL-1\\.2\"" package.json 2>/dev/null) \\
&& ok "license is EUPL-1.2" \\
|| miss "license drift — was EUPL-1.2 at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "src/main.rs" \\
&& ok "src/main.rs" \\
|| miss "missing critical file: src/main.rs"
test -f "dns/src/lib.rs" \\
&& ok "dns/src/lib.rs" \\
|| miss "missing critical file: dns/src/lib.rs"
test -f "dns-transport/src/lib.rs" \\
&& ok "dns-transport/src/lib.rs" \\
|| miss "missing critical file: dns-transport/src/lib.rs"
test -f "src/resolve.rs" \\
&& ok "src/resolve.rs" \\
|| miss "missing critical file: src/resolve.rs"
test -f "src/output.rs" \\
&& ok "src/output.rs" \\
|| miss "missing critical file: src/output.rs"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 739 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~709d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/ogham/dog"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
dog is a command-line DNS client written in Rust that replaces dig with a user-friendly interface, colored output, and modern protocol support including DNS-over-TLS (DoT) and DNS-over-HTTPS (DoH). It parses natural command-line syntax (e.g., dog example.net MX @1.1.1.1 -T) and can emit JSON for automation, making DNS queries more accessible and scriptable than traditional tools. Workspace monorepo: root crate 'dog' (src/main.rs) is the CLI, with dns/ and dns-transport/ as separate library crates. dns/ handles record parsing and types (dns/src/record/*.rs for A, AAAA, MX, NS, CAA, etc.), while dns-transport/ abstracts protocol layers (udp.rs, tcp.rs, tls.rs, https.rs, auto.rs for negotiation). Shell completions live in completions/, and build metadata in build.rs.
👥Who it's for
Systems administrators, DevOps engineers, and network developers who need to debug DNS issues or perform lookups from the command line but want better UX than dig—especially those working in environments requiring encrypted DNS protocols (DoT/DoH) or needing JSON output for monitoring/automation pipelines.
🌱Maturity & risk
Actively maintained and production-ready. The project is at version 0.2.0-pre with a full CI/CD pipeline (.travis.yml), shell completions for bash/zsh/fish/PowerShell, Docker support, and comprehensive DNS record type support (A, AAAA, MX, NS, CAA, LOC, NAPTR, OPT, etc.). Appears to have ongoing maintenance but the pre-release version tag suggests some features may still be stabilizing.
Standard open source risks apply.
Active areas of work
Version 0.2.0-pre is in development with no specific milestone visible in provided data. The structure suggests active work on protocol transport features (TLS/HTTPS support flags, auto-negotiation in dns-transport/src/auto.rs). Fuzzing infrastructure exists (dns/fuzz/) for robustness testing. No recent commit dates provided, but the 0.2.0-pre tag and feature flags indicate incremental feature work.
🚀Get running
git clone https://github.com/ogham/dog.git
cd dog
cargo build --release
./target/release/dog example.net
Optionally install from Arch Linux (pacman -S dog), Homebrew (brew install dog), or NixOS (nix-shell -p dogdns).
Daily commands:
# Development build (no debug symbols for speed)
cargo build
# Run with default settings
./target/debug/dog example.net
# With specific features
cargo build --features with_tls,with_https
# Release build (LTO enabled, smaller binary)
cargo build --release
# Run tests
cargo test
🗺️Map of the codebase
src/main.rs— Entry point for the CLI application; orchestrates argument parsing, DNS query execution, and output formattingdns/src/lib.rs— Core DNS protocol library exporting record types, wire parsing, and DNS message construction used by all query operationsdns-transport/src/lib.rs— Abstraction layer for DNS transport protocols (UDP, TCP, TLS, HTTPS); critical for supporting multiple transport modessrc/resolve.rs— Orchestrates the end-to-end DNS resolution flow by selecting transport, sending queries, and handling responsessrc/output.rs— Formats and renders DNS query results in multiple output modes (colored text, JSON); defines the user-facing output contractsrc/options.rs— Parses and validates command-line arguments into a structured configuration object passed throughout the applicationdns/src/record/mod.rs— Defines the record type system and parsing logic for all DNS record types (A, AAAA, MX, TXT, etc.)
🛠️How to make changes
Add support for a new DNS record type
- Create a new record type module (e.g., dns/src/record/newtype.rs) implementing the Record trait with parsing and display logic (
dns/src/record/newtype.rs) - Register the new type in the record type enum and parsing dispatcher (
dns/src/record/mod.rs) - Add wire format tests for the new record type (
dns/tests/wire_parsing_tests.rs) - Update output formatting to handle the new record type (
src/output.rs)
Add a new transport protocol
- Create a new transport module (e.g., dns-transport/src/newprotocol.rs) implementing the Transport trait (
dns-transport/src/newprotocol.rs) - Update the transport selection logic to include the new protocol (
dns-transport/src/lib.rs) - Add command-line option and parsing for the new protocol (
src/options.rs) - Integrate protocol selection in the resolve flow (
src/resolve.rs)
Add a new output format
- Define output format option in the options parser (
src/options.rs) - Implement formatting logic in the output module (
src/output.rs) - Add integration tests for the new format (
xtests/live/basics.toml)
Improve error handling and user hints
- Define new error conditions and categorize them (
dns-transport/src/error.rs) - Add user-friendly hint messages and recovery suggestions (
src/hints.rs) - Integrate hints into main error reporting flow (
src/main.rs)
🔧Why these technologies
- Rust — Provides memory safety, zero-cost abstractions, and cross-platform binary compilation; ideal for a system utility that handles low-level DNS wire format
- tokio async runtime — Enables concurrent DNS queries and supports async I/O for multiple transport protocols (UDP, TCP, TLS, HTTPS) with minimal overhead
- trust-dns crate (implied dependencies) — Likely used for TLS/certificate validation and HTTP/2 support in DoH implementation
- Workspace structure (dns + dns-transport) — Separates concerns: dns handles protocol parsing/serialization, dns-transport handles network I/O; allows code reuse and independent testing
⚖️Trade-offs already made
-
Separate workspace members for dns and dns-transport
- Why: Allows DNS parsing logic to be used without network I/O; improves modularity and testability
- Consequence: Adds organizational complexity and requires careful API boundaries between modules
-
Support multiple transport protocols (UDP, TCP, TLS, HTTPS)
- Why: Provides maximum flexibility for different use cases (privacy, firewall constraints, server support)
- Consequence: Increases code complexity in transport selection and error handling; different protocols have different timeout/retry semantics
-
Colored terminal output by default
- Why: Improves user experience and readability compared to dig
- Consequence: Requires terminal detection; colored output can break scripts/parsing (mitigated by JSON mode)
-
Use DNS wire format (binary) internally
- Why: Efficient, standards-compliant, and compatible with all DNS servers
- Consequence: Requires careful parsing logic; fuzzing tests needed to prevent parsing bugs
🚫Non-goals (don't propose these)
- Does not implement a DNS server or resolver (acts as a client only)
- Does not perform recursive resolution (delegates to configured nameservers)
- Does not support DNSSEC validation (displays DNSSEC records but does not validate signatures)
- Does not cache DNS responses (each query is stateless)
- Does not provide a library API (focused on CLI tool, but dns/dns-transport crates are usable libraries)
- Not designed for high-throughput batch queries (optimized for interactive command-line use)
🪤Traps & gotchas
Feature flags are semi-required: Default features include with_tls, with_https, with_nativetls. Building with --no-default-features will disable DoT/DoH; with_rustls and with_nativetls are mutually exclusive (vendored variant exists). Windows nameserver discovery: ipconfig crate is Windows-only dependency, so Windows builds will pull in extra deps. IDNA support is optional: with_idna feature gates international domain name parsing (dns/with_idna). Fuzz testing is separate: dns/fuzz/ is a separate crate that won't be built by default; requires cargo +nightly fuzz setup. No explicit error handling in shell completions: completions/ are static files—shell completion bugs are hard to debug and test. Pre-release version tag: 0.2.0-pre suggests API/behavior may change; no semver guarantees yet.
🏗️Architecture
💡Concepts to learn
- DNS Protocol (RFC 1035) — Dog's entire purpose is to parse and construct DNS messages; understanding wire format (questions, answers, authorities, additionals) is essential to modifying record types or transport logic.
- DNS over TLS (DoT) / DNS over HTTPS (DoH) — Core differentiator of dog vs dig; DoT (RFC 7858) and DoH (RFC 8484) are the encrypted variants dog supports via dns-transport crate, requiring understanding of TLS handshakes and HTTPS tunneling.
- EDNS (Extension Mechanisms for DNS) — Dog has --edns flag and opt.rs record type; EDNS extends DNS with OPT pseudo-records for larger payloads, DNSSEC, and client subnet info (RFC 6891).
- IDNA (Internationalized Domain Names in Applications) — Optional dns/with_idna feature converts unicode domain names to punycode ASCII-compatible encoding (xn--); critical for querying non-ASCII domains.
- DNS Record Types (A, AAAA, MX, NS, CAA, LOC, NAPTR, TLSA, etc.) — Dog's dns/src/record/ module implements 15+ record types; each has different wire format, semantics, and display rules—understanding one (e.g., MX priority field) helps when adding others.
- Transport Layer Abstraction Pattern — dns-transport/src/lib.rs uses trait-based abstraction to swap UDP/TCP/TLS/HTTPS without changing query logic; this is the bridge pattern in action and key to dog's extensibility.
- Rust Feature Flags (Conditional Compilation) — Dog's Cargo.toml defines mutually-exclusive and optional features (with_tls, with_https, with_nativetls, with_rustls, with_idna); understanding #[cfg(feature = "...")] is essential for cross-platform builds and reducing binary size.
🔗Related repos
miekg/dns— Go DNS library that inspired many CLI tools; dog's architecture (packet parsing, record types, transport abstraction) parallels this mature codebasePowerDNS/pdns— Full DNS server stack in C++; dog uses similar record type definitions and protocol handling patterns for querying rather than servingcloudflare/1.1.1.1— Cloudflare's DNS service; dog explicitly supports DoH/DoT and Cloudflare's nameservers are common test targets in dog's examplessystemd/systemd— systemd-resolve provides systemd's DNS stub resolver; dog is an alternative CLI tool for manual DNS queries, filling the gap dig leftisc-projects/bind— BIND's dig is dog's spiritual predecessor; dog improves UX while maintaining compatibility with dig's query syntax
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add integration tests for DNS-over-TLS and DNS-over-HTTPS transports
The repo has dns/tests/ with wire-level tests, but no integration tests for the actual transport layer. dns-transport/src/ contains implementations for tls.rs, https.rs, tcp.rs, and udp.rs, but there are no corresponding tests in dns-transport/tests/. This is critical since these protocols (DoT/DoH) are key features advertised in the README. New contributors could add realistic end-to-end tests against public DNS servers.
- [ ] Create
dns-transport/tests/directory - [ ] Add integration test file
dns-transport/tests/transport_integration.rswith tests for each transport type (UDP, TCP, TLS, HTTPS) - [ ] Test against a public resolver like 1.1.1.1 or 8.8.8.8 with various query types
- [ ] Verify tests pass locally and document any external dependencies needed
Add GitHub Actions workflow to replace Travis CI
The repo uses .travis.yml (Travis CI is deprecated/outdated), but has no .github/workflows/ directory with GitHub Actions. Since the repo already uses GitHub Issues templates and has a .github/ structure, migrating to Actions would be more maintainable. This includes testing across multiple Rust versions and platforms, and testing the feature flags like with_idna, with_tls, with_rustls, and with_nativetls_vendored defined in Cargo.toml.
- [ ] Create
.github/workflows/ci.ymlwith matrix testing (Linux, macOS, Windows) - [ ] Test against multiple Rust versions (MSRV and stable)
- [ ] Add separate matrix jobs for each feature combination (default, with_rustls, with_nativetls_vendored, etc.)
- [ ] Add a workflow for running fuzzing tests from
dns/fuzz/ - [ ] Remove or archive
.travis.ymlonce verified
Add comprehensive tests for DNS record parsing in dns/src/record/
The dns/src/record/ directory has many record type implementations (A, AAAA, MX, SRV, TLSA, CAA, etc.), but dns/tests/ only has generic wire_parsing_tests.rs and wire_building_tests.rs. Each record type deserves specific parsing tests covering edge cases, malformed inputs, and RFC compliance. This is especially important for less common types like LOC, NAPTR, EUI48, EUI64, and OPENPGPKEY.
- [ ] Create
dns/tests/records/subdirectory structure - [ ] Add test file
dns/tests/records/uncommon_types.rsfor LOC, NAPTR, EUI48, EUI64, OPENPGPKEY record parsing - [ ] Add test file
dns/tests/records/common_types.rsfor A, AAAA, MX, NS, CNAME, TXT types with edge cases - [ ] Include tests for malformed wire data and boundary conditions
- [ ] Reference specific RFC standards (e.g., RFC 1876 for LOC) in test documentation
🌿Good first issues
- Add TLSA record support: Create
dns/src/record/tlsa.rswith TLSA record parsing (DANE/TLS certificate association) following the pattern of existing record types like mx.rs and cname.rs; register indns/src/record/mod.rsand add to CLI type enum. - Expand integration tests: dns/ and dns-transport/ have fuzz targets but dns/ has no
tests/directory; add integration tests for common record type parsing (e.g.,tests/parse_a_record.rs,tests/parse_mx_record.rs) to catch regressions. - Document transport negotiation logic: Add doc comments to
dns-transport/src/auto.rsexplaining when UDP/TCP/DoT/DoH are selected and under what conditions; currently the decision tree is implicit in code.
⭐Top contributors
Click to expand
Top contributors
- @ogham — 82 commits
- @SuperSandro2000 — 2 commits
- @zoritle — 2 commits
- @txels — 1 commits
- @andryyy — 1 commits
📝Recent commits
Click to expand
Recent commits
721440b— Merge pull request #81 from AnInternetTroll/master (ogham)d30c3dd— Merge pull request #79 from tompazourek/powershell-completions (ogham)af64ebe— Merge pull request #84 from txels/master (ogham)bd9c65a— Merge pull request #82 from andryyy/patch-1 (ogham)1698ea6— Merge pull request #74 from simao/plugable-tls (ogham)02f2e5a— Merge pull request #67 from SuperSandro2000/patch-1 (ogham)8bccd75— Allow _ in domain names (txels)74bb4d3— Add ca-certificates andyswitch (andryyy)812cf0b— Add NO_COLOR env support (AnInternetTroll)4af4384— Added completions for PowerShell (tompazourek)
🔒Security observations
The DNS client codebase has a reasonable security foundation with workspace organization and multi-stage Docker builds, but contains several critical and high-severity issues related to outdated dependencies and base images. The most urgent concerns are: (1) outdated Debian base image (Buster EOL
- High · Outdated Debian Base Image —
Dockerfile. The Dockerfile uses 'debian:buster-slim' which is an older, potentially outdated base image. Buster reached end-of-life in June 2024. Using outdated base images may include unpatched security vulnerabilities in system libraries. Fix: Update to a more recent Debian stable release (e.g., 'debian:bookworm-slim' or 'debian:bullseye-slim') to ensure security patches are included. - High · Outdated OpenSSL Library —
Dockerfile. The Dockerfile installs 'libssl1.1' which is an older version of OpenSSL. OpenSSL 1.1.x reached end-of-life on September 11, 2023. This library may contain unpatched security vulnerabilities. Fix: Update to 'libssl3' or use a base image that includes current OpenSSL versions by default. Review and test compatibility with current TLS/HTTPS transport implementations. - Medium · Permissive Dependency Versions —
Cargo.toml. Several dependencies use minimal version constraints without upper bounds (e.g., 'ansi_term = "0.12"', 'log = "0.4"'). This allows potentially incompatible minor/patch versions that could introduce breaking changes or security issues. Fix: Use more restrictive version constraints (e.g., '0.12.1' or '~0.12') or pin to specific tested versions. Regularly audit and update dependencies using 'cargo audit' and 'cargo outdated'. - Medium · Missing Dependency Audit Configuration —
.travis.yml. There is no evidence of automated dependency vulnerability scanning in the CI/CD pipeline (e.g., 'cargo audit' in .travis.yml). The project relies on manual updates without systematic security monitoring. Fix: Add 'cargo audit' to the CI/CD pipeline to automatically detect known vulnerabilities in dependencies. Consider using tools like Dependabot or Renovate for automated updates. - Medium · Multi-stage Build Does Not Clear Sensitive Data —
Dockerfile. While the Dockerfile uses multi-stage builds to reduce final image size, there is no explicit cleanup of sensitive files (like .cargo cache, source code) from intermediate layers. Build artifacts could theoretically be inspected. Fix: Add explicit cleanup steps (e.g., 'RUN cargo clean') in the build stage and consider using BuildKit with 'RUN --mount=type=cache' for better layer caching and isolation. - Low · Potential Information Disclosure in Error Messages —
src/logger.rs, src/main.rs. The codebase includes logging (log crate v0.4) and error handling. Depending on implementation, DNS queries and responses could be logged, potentially exposing sensitive domain names or network information. Fix: Review logging configuration to ensure sensitive DNS queries are not logged in production. Use appropriate log levels and consider sanitizing logged data. - Low · Rand Crate Version Constraint —
Cargo.toml, src/txid.rs. The 'rand' crate (used for transaction ID generation) uses version '0.8' without a patch version lock. For security-sensitive operations like transaction ID generation, even patch versions should be carefully managed. Fix: Pin to a specific rand version (e.g., '0.8.5') and verify that the transaction ID generation is cryptographically secure. Review if rand::thread_rng() is appropriate or if a more secure CSPRNG should be used. - Low · No Security.txt or Vulnerability Disclosure Policy —
Repository root. No evidence of a security.txt file or vulnerability disclosure policy in the repository. Users cannot easily report security issues responsibly. Fix: Add a SECURITY.md file at the repository root with vulnerability reporting guidelines and contact information, following GitHub's recommendations.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.