{"id":13687849,"url":"https://github.com/lukaspustina/mhost","last_synced_at":"2026-02-18T15:02:14.597Z","repository":{"id":25687971,"uuid":"103970107","full_name":"lukaspustina/mhost","owner":"lukaspustina","description":"More than host - A modern take on the classic host DNS lookup utility including an easy to use and very fast Rust lookup library.","archived":false,"fork":false,"pushed_at":"2024-03-11T19:46:45.000Z","size":6453,"stargazers_count":32,"open_issues_count":8,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-11-12T11:39:57.073Z","etag":null,"topics":["cli","dns","dns-queries","mhost","network","rust","tools"],"latest_commit_sha":null,"homepage":"https://mhost.pustina.de","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lukaspustina.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-09-18T17:28:17.000Z","updated_at":"2024-08-09T15:52:04.000Z","dependencies_parsed_at":"2024-01-14T15:23:27.060Z","dependency_job_id":"a1bc1ecb-ebc5-4e0b-9044-d18085f8e24a","html_url":"https://github.com/lukaspustina/mhost","commit_stats":{"total_commits":464,"total_committers":5,"mean_commits":92.8,"dds":0.3642241379310345,"last_synced_commit":"6e90de8293a542c5180ea4ec78ecfef8f9e1a871"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukaspustina%2Fmhost","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukaspustina%2Fmhost/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukaspustina%2Fmhost/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukaspustina%2Fmhost/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lukaspustina","download_url":"https://codeload.github.com/lukaspustina/mhost/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228547854,"owners_count":17935141,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","dns","dns-queries","mhost","network","rust","tools"],"created_at":"2024-08-02T15:01:01.820Z","updated_at":"2026-02-18T15:02:14.591Z","avatar_url":"https://github.com/lukaspustina.png","language":"Rust","funding_links":[],"categories":["cli"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ch1\u003e\u003cimg src=\"docs/images/logo.png\" alt=\"mhost\" /\u003e mhost\u003c/h1\u003e\n  \u003cp\u003e\u003cstrong\u003eMore than host\u003c/strong\u003e -- a modern, high-performance DNS Swiss Army knife and Rust library.\u003c/p\u003e\n  \u003cp\u003e\n    \u003ca href=\"https://github.com/lukaspustina/mhost/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://github.com/lukaspustina/mhost/actions/workflows/ci.yml/badge.svg\" alt=\"CI build\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://crates.io/crates/mhost\"\u003e\u003cimg src=\"https://img.shields.io/crates/v/mhost.svg\" alt=\"mhost on crates.io\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://docs.rs/mhost\"\u003e\u003cimg src=\"https://docs.rs/mhost/badge.svg\" alt=\"Documentation on docs.rs\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/lukaspustina/mhost/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/release/lukaspustina/mhost.svg\" alt=\"GitHub release\" /\u003e\u003c/a\u003e\n    \u003cimg src=\"https://img.shields.io/badge/license-MIT-blue.svg\" alt=\"License: MIT\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/license-Apache_2.0-blue.svg\" alt=\"License: Apache 2.0\" /\u003e\n  \u003c/p\u003e\n  \u003cp\u003e\n    \u003ca href=\"#why-mhost\"\u003eFeatures\u003c/a\u003e |\n    \u003ca href=\"#quick-start\"\u003eQuick Start\u003c/a\u003e |\n    \u003ca href=\"#mdive--interactive-tui\"\u003emdive TUI\u003c/a\u003e |\n    \u003ca href=\"#installation\"\u003eInstallation\u003c/a\u003e |\n    \u003ca href=\"#using-mhost-as-a-rust-library\"\u003eLibrary API\u003c/a\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\n![Multi lookup for all available records of github.com.](docs/images/multi-lookup-all-records-github.png)\n\nmhost queries many DNS servers in parallel and aggregates their answers. It supports UDP, TCP, DNS-over-TLS, and DNS-over-HTTPS, understands 20+ record types, and ships with 80+ pre-configured public resolvers. Beyond simple lookups it can profile an entire domain, discover subdomains, trace the delegation chain, validate your DNS configuration, check propagation, diff records across nameservers, and verify live DNS against a zone file -- all from a single binary.\n\n**Two binaries, one toolkit:** `mhost` is a powerful CLI for scripts, pipelines, and quick one-liners. [`mdive`](#mdive--interactive-tui) is an interactive TUI that lets you explore DNS like a file manager -- drill into subdomains, discover hidden records, and chase references across domains, all without leaving your terminal.\n\n## Why mhost?\n\nMost DNS tools do one thing. `dig` does lookups. `subfinder` discovers subdomains. `dnschecker.org` checks propagation. `dog` gives you pretty output. **mhost does all of them** -- and they compose, because they share the same resolver engine, output formats, and server configurations.\n\n| | dig | dog | doggo | q | subfinder | **mhost** |\n|---|:---:|:---:|:---:|:---:|:---:|:---:|\n| Multi-server parallel queries | | | | | | **80+ built-in** |\n| UDP, TCP, DoT, DoH | UDP, TCP | DoT, DoH | DoT, DoH, DoQ | DoT, DoH, DoQ | | **all four** |\n| Subdomain discovery | | | | | passive | **10+ strategies** |\n| DNS configuration linting | | | | | | **13 checks** |\n| Delegation trace (all servers per hop) | `+trace` (1/hop) | | | | | **parallel, all servers** |\n| Propagation checking | | | | | | **across 6 providers** |\n| Diff between nameservers / snapshots | | | | | | **live, file, or mixed** |\n| Zone file verification (CI-ready) | | | | | | **BIND zone file support** |\n| Interactive TUI | | | | | | **mdive** |\n| JSON output | | | | | | **every command** |\n| Reusable Rust library | | | | | | **async, builder API** |\n| WHOIS / geolocation | | | | | | **IP-level** |\n\n**Pro tip:** `alias host=\"mhost l\"` and never look back.\n\n## Quick Start\n\n```sh\n# Install (pick one)\nbrew install lukaspustina/mhost/mhost          # macOS\ncargo install --features app mhost             # Rust toolchain (CLI only)\ncargo install --features tui mhost             # Rust toolchain (CLI + TUI)\ndocker run lukaspustina/mhost:latest mhost l github.com   # Try without installing\n\n# Look up github.com using your system nameservers\nmhost l github.com\n\n# Add 80+ public resolvers from 6 providers for broader results\nmhost -p l github.com\n\n# Get ALL record types + WHOIS info in one shot\nmhost -p l --all -w github.com\n\n# Validate your domain's DNS configuration\nmhost -p check example.com\n\n# Discover subdomains (CT logs, wordlists, NSEC walking, ...)\nmhost -p discover example.com\n\n# Verify live DNS matches your zone file (CI-friendly, non-zero on mismatch)\nmhost verify example.com.zone\n\n# Pipe to jq for scripting\nmhost -q -p --output json l --all github.com \\\n  | jq '.lookups[] | .result.Response.records[]? | select(.type == \"A\") | .data.A'\n\n# Or just dive in interactively\nmdive github.com\n```\n\n## Who Is This For?\n\n**DevOps / SRE** -- Verify DNS changes landed with `mhost verify`, check propagation across public resolvers with `mhost propagation`, diff before/after with JSON snapshots. Non-zero exit codes for CI/CD pipelines.\n\n**Security professionals** -- Discover subdomains via 10+ strategies (CT logs, NSEC walking, AXFR attempts, wordlists, permutation). Validate DNSSEC chains, detect zone transfer exposure, check for open resolvers.\n\n**DNS administrators** -- Lint your configuration against 13 best-practice checks. Trace the full delegation chain querying all servers at each hop. Compare records across nameserver sets to catch inconsistencies.\n\n**Developers** -- Use mhost as a Rust library with an ergonomic async builder API. JSON output on every command for scripting. 80+ built-in resolvers so you never have to hardcode IPs.\n\n## What Can mhost Do?\n\n| Command | Alias | What it does |\n|---------|-------|--------------|\n| [`lookup`](#lookup) | `l` | Look up DNS records for a domain, IP address, or CIDR block |\n| [`domain-lookup`](#domain-lookup) | `domain` | Profile a domain -- apex + 68 well-known subdomains in one operation |\n| [`discover`](#discover) | `d` | Find subdomains using 10+ strategies (wordlists, CT logs, AXFR, NSEC walking, ...) |\n| [`check`](#check) | `c` | Validate DNS configuration against 13 lints (SOA, NS, SPF, DMARC, DNSSEC, ...) |\n| [`trace`](#trace) | `t` | Trace the delegation path from root servers, querying all servers at each hop |\n| [`dnssec`](#dnssec) | -- | Visualize the DNSSEC trust chain from root to target domain |\n| [`propagation`](#propagation) | `prop` | Check whether a DNS change has propagated across public resolvers |\n| [`verify`](#verify) | `v` | Verify live DNS matches a BIND zone file -- catch drift before it bites |\n| [`diff`](#diff) | -- | Compare DNS records between nameservers or JSON snapshots |\n| [`info`](#info) | -- | Built-in reference for record types, TXT sub-types, and well-known subdomains |\n| `server-lists` | -- | Download public nameserver lists for large-scale queries |\n| `completions` | -- | Generate shell completions (bash, zsh, fish) |\n\n---\n\n## mdive -- Interactive TUI\n\nWhile `mhost` is built for scripts and one-liners, `mdive` is built for humans. It's an interactive terminal UI that turns DNS exploration into something that actually feels good -- think \"file manager for DNS.\" Type a domain, watch records stream in from multiple servers in real time, then drill into anything interesting.\n\n```sh\nmdive example.com                        # Dive right in\nmdive -p example.com                     # Use 80+ public resolvers for broader coverage\nmdive -s 8.8.8.8 -s 1.1.1.1 example.com # Pick your own nameservers\n```\n\n![mdive main view github.com.](docs/images/mdive-main-view-github.png)\n\n**A live, sortable record table.** All DNS records for a domain -- apex plus dozens of well-known subdomains across 10 categories (email auth, TLS/DANE, SRV services, infrastructure, and more). Results stream in progressively as servers respond, with a real-time progress bar in the status line. Toggle between raw DNS wire format and human-readable values with a single keypress.\n\n**Drill-down navigation.** See a CNAME pointing somewhere interesting? Press `l` to follow it. Found a subdomain in the results? Hit Enter to dive in. Every query is pushed onto a history stack, so Backspace takes you right back. It's like `cd` and `cd ..` but for DNS.\n\n![mdive discovery empty github.com.](docs/images/mdive-discovery-view-empty-github.png)\n\n**Five discovery strategies, one keypress away.** Press `d` to open the discovery panel, then launch any combination:\n\n| Key | Strategy | What it does |\n|-----|----------|--------------|\n| `c` | CT Logs | Search Certificate Transparency logs via crt.sh |\n| `w` | Wordlist | Brute-force 424 common subdomain names (with automatic wildcard filtering) |\n| `s` | SRV Probing | Probe 22 well-known SRV service records |\n| `t` | TXT Mining | Extract referenced domains from SPF includes and DMARC URIs |\n| `p` | Permutation | Generate variations of already-discovered labels (dev-, staging-, -prod, ...) |\n| `a` | All | Run everything at once |\n\n![mdive discovery full github.com.](docs/images/mdive-discovery-view-full-github.png)\n\nDiscovered subdomains appear in the main table as they're found. Wildcard detection runs automatically to filter false positives.\n\n**Built-in DNS health checks.** Press `c` to run best-practice lints against the current domain -- CNAME-at-apex detection, NS redundancy, SPF/DMARC validation, DNSSEC chain verification, HTTPS/SVCB mode checks, CAA coverage, TTL sanity, and more. Each result shows pass/warning/fail with a clear explanation.\n\n**WHOIS and geolocation.** Press `w` and mdive fetches WHOIS data for every IP in your results -- AS numbers, network prefixes, organizations, countries, and geolocations. Handy for understanding where a domain's infrastructure actually lives.\n\n**Server response dashboard.** Press `s` to see every nameserver that responded, sorted by latency -- protocol, response counts, error counts, and min/avg/max timing. The stats panel (`S`) shows a compact summary right in the status bar: record type distribution, query health, DNSSEC status, and response time ranges.\n\n**Regex filtering.** Press `/` and type a pattern. Matches against record names, types, and values in real time. Quickly zero in on that one TXT record in a sea of results.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eKeybindings\u003c/strong\u003e\u003c/summary\u003e\n\nmdive uses vi-style navigation with a few extras:\n\n| Key | Action | Key | Action |\n|-----|--------|-----|--------|\n| `j`/`k` | Move down/up | `i` | Enter domain query |\n| `gg`/`G` | First/last row | `/` | Filter (regex) |\n| `22gg` | Jump to line 22 | `C` | Clear filter |\n| PgUp/PgDn | Scroll by 10 | `r` | Re-run query |\n| Enter | Drill into subdomain | `h` | Toggle human view |\n| `l`/Right | Follow value target | `S` | Toggle stats |\n| Left/BS | Go back in history | Tab | Cycle grouping |\n| `1`-`0` | Toggle categories | `a`/`n` | All/none categories |\n| `o` | Record detail popup | `?` | Help |\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eCategory Toggles\u003c/strong\u003e\u003c/summary\u003e\n\nRecords are organized into 10 categories. Toggle any with number keys, or press `a` for all / `n` for none:\n\n| Key | Category | Key | Category |\n|-----|----------|-----|----------|\n| `1` | Email Auth (DMARC, SPF, ...) | `6` | Infrastructure (LDAP, Kerberos) |\n| `2` | Email Services (IMAP, SMTP) | `7` | Modern Protocols (STUN, TURN) |\n| `3` | TLS / DANE | `8` | Verification \u0026 Metadata |\n| `4` | Communication (SIP, XMPP, Matrix) | `9` | Legacy |\n| `5` | Calendar \u0026 Contacts (CalDAV) | `0` | Gaming |\n\nCycle the grouping mode with Tab: **Category** (default) -\u003e **Record Type** -\u003e **Name** -\u003e **Server**.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003emdive CLI Options\u003c/strong\u003e\u003c/summary\u003e\n\n```\nmdive [OPTIONS] [DOMAIN]\n\nOptions:\n  -s, --nameserver \u003cSPEC\u003e          Add a nameserver (repeatable)\n  -p, --predefined                 Add predefined public nameservers\n      --predefined-filter \u003cPROTO\u003e  Filter predefined by protocol [udp, tcp, tls, https]\n  -S, --no-system-lookups          Skip system nameservers\n  -t, --timeout \u003cSECS\u003e             Query timeout [default: 5] (1-30)\n  -4, --ipv4-only                  IPv4 only\n  -6, --ipv6-only                  IPv6 only\n  -h, --help                       Print help\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eBuilding mdive\u003c/strong\u003e\u003c/summary\u003e\n\nmdive lives behind the `tui` feature flag to keep the default build lean:\n\n```sh\ncargo build --features tui         # Build both mhost and mdive\ncargo run --bin mdive --features tui -- example.com\n```\n\n\u003c/details\u003e\n\n---\n\n## CLI Use Cases\n\n### Simple Lookup\n\n```sh\nmhost l github.com\n```\n\n![Default lookup for github.com.](docs/images/default-lookup-github.png)\n\nThis uses your system nameservers and queries the default record types (A, AAAA, CNAME, MX).\n\n### More Nameservers, More Answers\n\n```sh\nmhost -p l github.com\n```\n\n![Default lookup with predefined servers for github.com.](docs/images/default-lookup-predefined-servers-github.png)\n\n`-p` adds mhost's predefined public nameservers from Cloudflare, Google, Quad9, Mullvad, Wikimedia, and DNS4EU. More servers means more confidence that you're seeing the full picture.\n\n### Go Big -- Thousands of Nameservers\n\n```sh\nmhost server-lists public-dns -o servers.txt\nmhost --limit 6000 --max-concurrent-servers 1000 --timeout 1 -f servers.txt l www.github.com\n```\n\n![Default lookup with servers list for github.com.](docs/images/default-lookup-servers-list-github.png)\n\nDownload a community-maintained list of public resolvers, then fire queries at all of them. These settings are intentionally aggressive -- mhost defaults are much more cautious.\n\n### All Four Protocols at Once\n\n```sh\nmhost \\\n  -s 1.1.1.1 \\\n  -s tcp:1.1.1.1 \\\n  -s tls:1.1.1.1:853,tls_auth_name=cloudflare-dns.com \\\n  -s https:1.1.1.1:443,tls_auth_name=cloudflare-dns.com,name=Cloudflare \\\n  l github.com\n```\n\n![Default lookup with all protocols for github.com.](docs/images/default-lookup-all-protocols-github.png)\n\nNameserver spec format: `protocol:host:port,tls_auth_name=hostname,name=label`\n\n### Profile an Entire Domain\n\n```sh\nmhost -p domain-lookup example.com         # ~42 well-known entries\nmhost -p domain-lookup --all example.com   # ~68 entries (extended set)\n```\n\nOne command queries the apex plus dozens of well-known subdomains: email auth (DMARC, MTA-STS, BIMI, TLS-RPT), SRV services (IMAP, SMTP, CalDAV, XMPP, Matrix, ...), DANE/TLSA records, and more.\n\n### Discover Subdomains\n\n```sh\nmhost -p d github.com\n```\n\n![Discover github.com.](docs/images/discover-github.png)\n\nmhost chains 10+ discovery strategies automatically:\n\n1. Standard DNS record lookups\n2. Certificate Transparency logs (crt.sh)\n3. TXT record mining for referenced domains\n4. SRV service probing\n5. Wildcard detection via random subdomain probes\n6. Zone transfer (AXFR) attempts\n7. NSEC walking\n8. Wordlist brute force (424 built-in entries, or supply your own with `-w`)\n9. Subdomain permutation on discovered names\n10. Recursive discovery on found subdomains (`--depth 1..3`)\n11. Reverse DNS lookups on discovered IPs\n\nYou can also explore a domain's autonomous systems:\n\n```sh\nmhost -p l --all -w github.com\nmhost -p l --all 140.82.121.0/24\n```\n\n![Discover AS of github.com.](docs/images/discover-as-github.png)\n\n### Validate DNS Configuration\n\n```sh\nmhost -p c github.com\n```\n\n![Check github.com.](docs/images/check-github.png)\n\nThe `check` command runs 13 lints against a domain's DNS records:\n\n| Lint | What it checks |\n|------|---------------|\n| SOA | Start of Authority record validity |\n| NS | NS delegation, lame delegation, network diversity |\n| CNAME | CNAME usage rules |\n| MX | Null MX, duplicate preferences, target resolution |\n| SPF | SPF record syntax and policy |\n| DMARC | DMARC policy validation |\n| CAA | Certificate Authority Authorization tags |\n| TTL | TTL consistency across records |\n| DNSSEC | DNSSEC presence and configuration |\n| HTTPS/SVCB | Service binding record well-formedness |\n| AXFR | Zone transfer exposure |\n| Open Resolver | Open resolver detection |\n| Delegation | Delegation consistency |\n\nDisable any lint individually: `--no-soa`, `--no-spf`, `--no-dnssec`, etc.\n\n### Trace the Delegation Chain\n\n```sh\nmhost trace example.com\nmhost trace -t AAAA --show-all-servers example.com\n```\n\n![trace-github.com.](docs/images/trace-github.png)\n\nUnlike `dig +trace` which queries one server per hop, mhost's `trace` command queries **all nameservers at each delegation level in parallel**. It detects referral divergence (where different root/TLD servers disagree), reports per-server latency, and resolves missing glue records automatically.\n\n### Check DNS Propagation\n\n```sh\nmhost -p propagation example.com\nmhost -p prop --all example.com\n```\n\n![propagation-github.com.-1](docs/images/propagation-github_1.png)\n![propagation-github.com.-2](docs/images/propagation-github_2.png)\n\nAfter making a DNS change, check whether it has reached all the major public resolvers. Uses the predefined nameserver set (Cloudflare, Google, Quad9, Mullvad, Wikimedia, DNS4EU).\n\n### Diff Records Between Nameservers\n\n```sh\nmhost diff --left 8.8.8.8 --right 1.1.1.1 example.com\nmhost diff --left 8.8.8.8 --right 1.1.1.1 --all example.com\n```\n\nCompare what two different nameserver sets return for the same domain. Useful for debugging inconsistencies or verifying migrations.\n\nYou can also diff against saved JSON snapshots for migration validation and change tracking:\n\n```sh\n# Save a snapshot\nmhost lookup -s 8.8.8.8 -q -t A,AAAA,MX example.com --output json \u003e before.json\n\n# Later, diff snapshot against live DNS\nmhost diff --left-from-file before.json --right 1.1.1.1 example.com\n\n# Or compare two snapshots offline\nmhost diff --left-from-file before.json --right-from-file after.json example.com\n```\n\n### Verify DNS Against a Zone File\n\n```sh\nmhost verify example.com.zone\n```\n\nPushed a DNS change and wondering if it actually landed? `verify` reads a BIND zone file -- the most widely used format for DNS zone specification -- compares every record against live DNS, and tells you exactly what matches, what's missing, and what showed up unexpectedly. Non-zero exit code on mismatch, so it drops straight into CI pipelines.\n\n```sh\n# Verify against your authoritative nameserver\nmhost -s ns1.example.com verify example.com.zone\n\n# Check propagation to public resolvers\nmhost -p verify example.com.zone\n\n# Strict mode: also flag TTL differences\nmhost verify --strict example.com.zone\n\n# Only check mail-related records\nmhost verify --only-type MX,TXT example.com.zone\n\n# CI one-liner\nmhost verify zones/example.com.zone || notify_team \"DNS drift detected\"\n```\n\n**Don't have a zone file?** BIND zone format is the universal lingua franca of DNS -- almost every DNS provider can export to it, and tools like `dig`, `nsd`, and BIND itself all speak it natively. If your DNS lives in Terraform, Pulumi, CloudFormation, or any other IaC tool, just ask an LLM to convert the state to a BIND zone file. For example, feed `terraform show -json` output to your favorite LLM and ask for a zone file -- it takes seconds and gives you a portable, version-controllable source of truth you can verify against at any time.\n\n### Look Up Record Type Info\n\n```sh\nmhost info            # List all supported types\nmhost info MX         # Details about MX records\nmhost info SPF        # Details about SPF TXT sub-type\nmhost info _dmarc     # Details about the _dmarc well-known subdomain\n```\n\nBuilt-in reference with summaries, details, and RFC references for every supported record type, TXT sub-type, and well-known subdomain.\n\n---\n\n## Installation\n\n### Homebrew (macOS)\n\n```sh\nbrew install lukaspustina/mhost/mhost\n```\n\n### Docker\n\n```sh\ndocker run lukaspustina/mhost:latest mhost l example.com\n```\n\n### Debian / Ubuntu\n\nDownload the `.deb` from the [latest GitHub Release](https://github.com/lukaspustina/mhost/releases):\n\n```sh\ndpkg -i mhost.deb\n```\n\n### Redhat / Fedora\n\nDownload the `.rpm` from the [latest GitHub Release](https://github.com/lukaspustina/mhost/releases):\n\n```sh\nrpm -i mhost.rpm\n```\n\n### Cargo (Rust developers)\n\n```sh\ncargo install --features app mhost       # CLI only\ncargo install --features tui mhost       # CLI + interactive TUI (mdive)\n```\n\n### From Source\n\n```sh\ngit clone https://github.com/lukaspustina/mhost\ncd mhost\nmake install                             # CLI only\ncargo install --features tui --path .    # CLI + TUI\n```\n\n---\n\n## Using mhost as a Rust Library\n\nmhost is also a reusable library. Build without the CLI:\n\n```sh\ncargo build --lib   # no CLI dependencies\n```\n\n### Builder API (recommended)\n\n```rust\nuse mhost::resolver::{ResolverGroupBuilder, MultiQuery};\nuse mhost::resolver::lookup::Uniquify;\nuse mhost::nameserver::predefined::PredefinedProvider;\nuse mhost::RecordType;\nuse std::time::Duration;\n\n#[tokio::main]\nasync fn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    let resolvers = ResolverGroupBuilder::new()\n        .system()\n        .predefined(PredefinedProvider::Google)\n        .timeout(Duration::from_secs(3))\n        .build()\n        .await?;\n\n    let query = MultiQuery::multi_record(\n        \"example.com\",\n        vec![RecordType::A, RecordType::AAAA],\n    )?;\n    let lookups = resolvers.lookup(query).await?;\n    let a_records = lookups.a().unique().to_owned();\n    println!(\"A records: {:?}\", a_records);\n    Ok(())\n}\n```\n\n### Manual Construction\n\n```rust\nuse mhost::nameserver::NameServerConfig;\nuse mhost::resolver::{MultiQuery, Resolver, ResolverConfig, ResolverGroup};\nuse mhost::resolver::lookup::Uniquify;\nuse mhost::RecordType;\nuse std::net::SocketAddr;\n\n#[tokio::main]\nasync fn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    let mut resolvers = ResolverGroup::from_system_config(Default::default()).await?;\n\n    let sock_addr: SocketAddr = \"8.8.8.8:53\".parse()?;\n    let config = ResolverConfig::new(NameServerConfig::udp(sock_addr));\n    let google = Resolver::new(config, Default::default()).await?;\n    resolvers.add(google);\n\n    let query = MultiQuery::multi_record(\n        \"example.com\",\n        vec![RecordType::A, RecordType::AAAA, RecordType::TXT],\n    )?;\n    let lookups = resolvers.lookup(query).await?;\n    let a_records = lookups.a().unique().to_owned();\n    println!(\"A records: {:?}\", a_records);\n    Ok(())\n}\n```\n\n### Running DNS Lints\n\nThe core library includes 9 pure lint checks (CAA, CNAME, DMARC, DNSSEC, HTTPS/SVCB, MX, NS, SPF, TTL) that analyse `Lookups` results for common misconfigurations — no `app-*` features required:\n\n```rust\nuse mhost::resolver::{ResolverGroupBuilder, MultiQuery};\nuse mhost::lints::{check_spf, check_caa, CheckResult};\nuse mhost::RecordType;\nuse std::time::Duration;\n\n#[tokio::main]\nasync fn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    let resolvers = ResolverGroupBuilder::new()\n        .system()\n        .timeout(Duration::from_secs(3))\n        .build()\n        .await?;\n\n    let query = MultiQuery::multi_record(\n        \"example.com\",\n        vec![RecordType::TXT, RecordType::CAA],\n    )?;\n    let lookups = resolvers.lookup(query).await?;\n\n    for result in check_spf(\u0026lookups).iter().chain(check_caa(\u0026lookups).iter()) {\n        match result {\n            CheckResult::Ok(msg) =\u003e println!(\"  OK: {}\", msg),\n            CheckResult::Warning(msg) =\u003e println!(\"  WARN: {}\", msg),\n            CheckResult::Failed(msg) =\u003e println!(\"  FAIL: {}\", msg),\n            CheckResult::NotFound() =\u003e println!(\"  (not found)\"),\n        }\n    }\n    Ok(())\n}\n```\n\nSee [docs.rs/mhost](https://docs.rs/mhost) for the full API documentation.\n\n---\n\n## JSON Output\n\nEvery command supports `--output json` for machine-readable output. Combine with `-q` (quiet) to suppress status messages:\n\n```sh\nmhost -q --output json l --all example.com | jq .\nmhost -q --output json trace example.com | jq '.hops[] | .zone_name'\nmhost -q --output json c example.com | jq '.results[] | select(.status != \"Ok\")'\n```\n\n---\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eGlobal Options\u003c/strong\u003e\u003c/summary\u003e\n\nmhost has a rich set of options that apply to all commands:\n\n```\nNameserver selection:\n  -s, --nameserver \u003cSPEC\u003e           Add a nameserver (IP, or protocol:host:port,...)\n  -p, --predefined                  Add predefined public nameservers\n      --predefined-filter \u003cPROTO\u003e   Filter predefined by protocol [udp, tcp, tls, https]\n      --list-predefined             Show all predefined nameservers\n  -f, --nameservers-from-file \u003cF\u003e   Load nameservers from file\n      --no-system-nameservers       Skip /etc/resolv.conf nameservers\n  -S, --no-system-lookups           Skip system nameservers for lookups\n\nIP version filtering:\n  -4, --ipv4-only                   Only use IPv4 nameservers and return IPv4 results\n  -6, --ipv6-only                   Only use IPv6 nameservers and return IPv6 results\n\nConcurrency \u0026 resilience:\n      --limit \u003cN\u003e                   Max nameservers to query [default: 100] (1-10000)\n      --max-concurrent-servers \u003cN\u003e  Max concurrent nameservers [default: 10] (1-100)\n      --max-concurrent-requests \u003cN\u003e Max concurrent requests per server [default: 5] (1-50)\n      --retries \u003cN\u003e                 Retries per server [default: 0] (0-10)\n      --timeout \u003cSECS\u003e              Response timeout [default: 5] (1-300)\n      --continue-on-error           Continue on server errors\n      --continue-on-timeout         Continue on server timeouts\n      --wait-multiple-responses     Wait for additional responses until timeout\n\nOutput:\n  -o, --output \u003cFORMAT\u003e             Output format: summary or json [default: summary]\n  -q, --quiet                       Only print results (no status messages)\n      --no-color                    Disable colored output\n      --ascii                       ASCII-only output (no Unicode symbols)\n      --show-errors                 Show error counts\n  -v                                Increase verbosity (repeat for more)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eCommand Reference\u003c/strong\u003e\u003c/summary\u003e\n\n### Lookup\n\n```sh\nmhost l [OPTIONS] \u003cDOMAIN | IP | CIDR | SERVICE SPEC\u003e\n```\n\n```\n  -t, --record-type \u003cTYPE\u003e   Record types [default: A,AAAA,CNAME,MX]\n      --all                  Query all record types\n  -s, --service              Parse argument as SRV service spec\n  -w, --whois                Include WHOIS information for A/AAAA/PTR results\n```\n\nAccepts domain names, IPv4/IPv6 addresses, CIDR blocks (reverse lookup of all IPs in range), and SRV service specs (`smtp:tcp:example.com` or `dns:udp:example.com`).\n\n### Domain Lookup\n\n```sh\nmhost domain-lookup [OPTIONS] \u003cDOMAIN\u003e\n```\n\n```\n      --all                     Include extended well-known subdomains (~68 total)\n  -p, --show-partial-results    Show results incrementally\n```\n\nQueries the apex plus well-known subdomains covering:\n- **Apex**: A, AAAA, MX, NS, SOA, CAA, HTTPS, TXT, CNAME, SVCB, NAPTR, SSHFP\n- **Email auth**: DMARC, MTA-STS, TLS-RPT, BIMI\n- **Email services**: submission, IMAP, POP3, autodiscover (SRV)\n- **TLS/DANE**: TLSA for ports 443, 25, 587, 993, etc.\n- **Communication**: SIP, XMPP, Matrix (SRV)\n- **Calendar/Contacts**: CalDAV, CardDAV (SRV)\n- **Infrastructure**: LDAP, Kerberos (SRV)\n- **Modern protocols**: STUN, TURN (SRV)\n- **Verification**: ACME challenge, AT Protocol, DNSLink, domain verification TXT records\n\n### Discover\n\n```sh\nmhost d [OPTIONS] \u003cDOMAIN\u003e\n```\n\n```\n  -s, --subdomains-only            Show only subdomains\n  -w, --wordlist-from-file \u003cF\u003e     Custom wordlist file\n      --no-ct-logs                 Skip Certificate Transparency queries\n      --depth \u003cN\u003e                  Recursive discovery depth [default: 0] (0-3)\n      --rnd-names-number \u003cN\u003e       Random names for wildcard check [default: 3] (1-20)\n      --rnd-names-len \u003cN\u003e          Random name length [default: 32] (8-128)\n  -p, --show-partial-results       Show results incrementally\n```\n\n### Check\n\n```sh\nmhost c [OPTIONS] \u003cDOMAIN\u003e\n```\n\n```\n  -p, --show-partial-results         Show results after each lint\n  -i, --show-intermediate-lookups    Show all DNS lookups made during checks\n      --no-soa                       Disable SOA check\n      --no-ns                        Disable NS delegation check\n      --no-cnames                    Disable CNAME lint\n      --no-mx                        Disable MX check\n      --no-spf                       Disable SPF check\n      --no-dmarc                     Disable DMARC check\n      --no-caa                       Disable CAA check\n      --no-ttl                       Disable TTL check\n      --no-dnssec                    Disable DNSSEC check\n      --no-https-svcb                Disable HTTPS/SVCB check\n      --no-axfr                      Disable AXFR check\n      --no-open-resolver             Disable open resolver check\n      --no-delegation                Disable delegation check\n```\n\n### Trace\n\n```sh\nmhost trace [OPTIONS] \u003cDOMAIN\u003e\n```\n\n```\n  -t, --record-type \u003cTYPE\u003e       Record type to query [default: A]\n      --max-hops \u003cN\u003e             Maximum delegation hops [default: 10] (1-20)\n      --show-all-servers         Show per-server details (IP, latency, outcome)\n  -p, --show-partial-results     Show each hop as it completes\n```\n\n### Propagation\n\n```sh\nmhost -p propagation [OPTIONS] \u003cDOMAIN\u003e\n```\n\n```\n  -t, --record-type \u003cTYPE\u003e       Record types [default: A,AAAA,CNAME,MX]\n      --all                      Check all record types\n  -p, --show-partial-results     Show results incrementally\n```\n\n### Diff\n\n```sh\nmhost diff [OPTIONS] \u003cDOMAIN\u003e\n```\n\n```\n      --left \u003cSERVER\u003e            Left nameserver(s) (repeatable)\n      --right \u003cSERVER\u003e           Right nameserver(s) (repeatable)\n      --left-from-file \u003cFILE\u003e    Load left side from a JSON snapshot file (from lookup --output json)\n      --right-from-file \u003cFILE\u003e   Load right side from a JSON snapshot file (from lookup --output json)\n  -t, --record-type \u003cTYPE\u003e       Record types [default: A,AAAA,CNAME,MX,NS,SOA,TXT]\n      --all                      Compare all record types\n```\n\nEach side requires either `--left`/`--right` (live query) or `--left-from-file`/`--right-from-file` (snapshot). You can mix: one side live, the other from file.\n\n### Verify\n\n```sh\nmhost verify [OPTIONS] \u003cZONE_FILE\u003e\n```\n\n```\n  \u003cZONE_FILE\u003e                      Path to BIND zone file (required)\n      --origin \u003cNAME\u003e              Override zone origin ($ORIGIN)\n      --strict                     Report TTL differences as mismatches\n      --only-type \u003cTYPE\u003e           Only verify these record types (repeatable, comma-delimited)\n      --ignore-type \u003cTYPE\u003e         Skip these record types (repeatable, comma-delimited)\n      --ignore-extra               Suppress extra-record reporting (live records not in zone file)\n      --ignore-soa                 Skip SOA serial comparison\n```\n\nBy default, SOA, DNSSEC records (RRSIG, DNSKEY, DS, NSEC, NSEC3, NSEC3PARAM), and apex NS records are skipped. Wildcard records are reported as skipped since they can't be verified via simple lookups. Exit code `0` means all records verified; non-zero means mismatches or missing records.\n\n### DNSSEC\n\n```sh\nmhost dnssec [OPTIONS] \u003cDOMAIN\u003e\n```\n\n```\n      --max-hops \u003cN\u003e             Maximum delegation hops [default: 10] (1-20)\n  -p, --show-partial-results     Show each delegation level as it completes\n```\n\nWalks the DNS delegation chain from root servers to the target domain, querying DNSKEY, DS, and RRSIG records at each level. Renders a color-coded trust chain tree showing key roles (KSK/ZSK), algorithm strength, signature expiry, and DS-to-DNSKEY linkage.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003ePredefined Nameservers\u003c/strong\u003e\u003c/summary\u003e\n\nmhost ships with 84 configurations across 6 providers. All use **unfiltered endpoints** (no content filtering or blocking). Each provider is available over UDP, TCP, DoT, and DoH.\n\n| Provider | Primary IPv4 | Secondary IPv4 | IPv6 | TLS/HTTPS Hostname |\n|----------|-------------|---------------|------|-------------------|\n| Cloudflare | 1.1.1.1 | 1.0.0.1 | 2606:4700:4700::1111 / ::1001 | cloudflare-dns.com |\n| Google | 8.8.8.8 | 8.8.4.4 | 2001:4860:4860::8888 / ::8844 | dns.google |\n| Quad9 | 9.9.9.10 | 149.112.112.10 | 2620:fe::10 / ::fe:10 | dns10.quad9.net |\n| Mullvad | 194.242.2.2 | 193.19.108.2 | 2a07:e340::2 | dns.mullvad.net |\n| Wikimedia | 185.71.138.138 | 185.71.139.139 | 2001:67c:930::1 / ::2 | wikimedia-dns.org |\n| DNS4EU | 185.134.197.54 | 185.134.196.54 | -- | unfiltered.joindns4.eu |\n\nUse `mhost --list-predefined` to see every configuration.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eSupported Record Types\u003c/strong\u003e\u003c/summary\u003e\n\n| Type | Description | Type | Description |\n|------|-------------|------|-------------|\n| A | IPv4 address | NS | Name server |\n| AAAA | IPv6 address | OPENPGPKEY | OpenPGP public key |\n| ANAME | ANAME / ALIAS | PTR | Pointer (reverse DNS) |\n| ANY | Query all types | SOA | Start of Authority |\n| CAA | CA Authorization | SRV | Service locator |\n| CNAME | Canonical name | SSHFP | SSH fingerprint |\n| HINFO | Host information | SVCB | Service binding |\n| HTTPS | HTTPS service binding | TLSA | TLS/DANE certificate |\n| MX | Mail exchange | TXT | Text record |\n| NAPTR | Naming Authority Pointer | DNSSEC | DNSKEY, DS, RRSIG, NSEC, ... |\n\n\u003c/details\u003e\n\n---\n\n## Changelog\n\nSee the [CHANGELOG](CHANGELOG.md) for a full release history.\n\n## Limitations\n\n- Only DNS class `IN` is supported.\n\n## Architecture Design Records\n\nThe [docs/adr/](docs/adr/) directory contains Architecture Decision Records for the project.\n\n## Thanks\n\nThanks to [Benjamin Fry](https://github.com/bluejekyll) for [Hickory DNS](https://github.com/hickory-dns/hickory-dns) (formerly Trust-DNS), which does all the heavy DNS lifting.\n\n## License\n\nMIT or Apache-2.0, at your option.\n\n## Postcardware\n\nYou're free to use `mhost`. If you find it useful, I would highly appreciate you sending me a postcard from your hometown mentioning how you use `mhost`. My work address is\n\n```\nLukas Pustina\nCenterDevice GmbH\nRheinwerkallee 3\n53227 Bonn\nGermany\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukaspustina%2Fmhost","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flukaspustina%2Fmhost","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukaspustina%2Fmhost/lists"}