mhost 0.6.0

More than host - A modern take on the classic host DNS lookup utility including an easy to use and very fast Rust lookup library
Documentation

mhost mhost

More than host -- a modern, high-performance DNS Swiss Army knife and Rust library.

CI build mhost on crates.io Documentation on docs.rs GitHub release License: MIT License: Apache 2.0

mhost 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 84 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, and diff records across nameservers -- all from a single binary.

Quick Start

# Install (pick one)
brew install lukaspustina/mhost/mhost          # macOS
cargo install --features app mhost             # Rust toolchain
docker run lukaspustina/mhost:latest mhost l github.com   # Try without installing

# Look up github.com using your system nameservers
mhost l github.com

# Add 84 public resolvers from 6 providers for broader results
mhost -p l github.com

# Get ALL record types + WHOIS info in one shot
mhost -p l --all -w github.com

# Pipe to jq for scripting
mhost -q -p --output json l --all github.com \
  | jq '.lookups[] | .result.Response.records[]? | select(.type == "A") | .data.A'

Multi lookup for all available records of github.com.

Pro tip: alias host="mhost l" and never look back.

What Can mhost Do?

Command Alias What it does
lookup l Look up DNS records for a domain, IP address, or CIDR block
domain-lookup domain Profile a domain -- apex + 68 well-known subdomains in one operation
discover d Find subdomains using 10+ strategies (wordlists, CT logs, AXFR, NSEC walking, ...)
check c Validate DNS configuration against 13 lints (SOA, NS, SPF, DMARC, DNSSEC, ...)
trace t Trace the delegation path from root servers, querying all servers at each hop
propagation prop Check whether a DNS change has propagated across public resolvers
diff -- Compare DNS records between two sets of nameservers
info -- Built-in reference for record types, TXT sub-types, and well-known subdomains
server-lists -- Download public nameserver lists for large-scale queries
completions -- Generate shell completions (bash, zsh, fish)

Use Cases

Simple Lookup

mhost l github.com

Default lookup for github.com.

This uses your system nameservers and queries the default record types (A, AAAA, CNAME, MX).

More Nameservers, More Answers

mhost -p l github.com

Default lookup with predefined servers for github.com.

-p adds mhost's 84 predefined public nameservers from Cloudflare, Google, Quad9, Mullvad, Wikimedia, and DNS4EU. More servers means more confidence that you're seeing the full picture.

Go Big -- Thousands of Nameservers

mhost server-lists public-dns -o servers.txt
mhost --limit 6000 --max-concurrent-servers 1000 --timeout 1 -f servers.txt l www.github.com

Default lookup with servers list for github.com.

Download 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.

All Four Protocols at Once

mhost \
  -s 1.1.1.1 \
  -s tcp:1.1.1.1 \
  -s tls:1.1.1.1:853,tls_auth_name=cloudflare-dns.com \
  -s https:1.1.1.1:443,tls_auth_name=cloudflare-dns.com,name=Cloudflare \
  l github.com

Default lookup with all protocols for github.com.

Nameserver spec format: protocol:host:port,tls_auth_name=hostname,name=label

Profile an Entire Domain

mhost -p domain-lookup example.com         # ~42 well-known entries
mhost -p domain-lookup --all example.com   # ~68 entries (extended set)

One 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.

Discover Subdomains

mhost -p d github.com

Discover github.com.

mhost chains 10+ discovery strategies automatically:

  1. Standard DNS record lookups
  2. Certificate Transparency logs (crt.sh)
  3. TXT record mining for referenced domains
  4. SRV service probing
  5. Wildcard detection via random subdomain probes
  6. Zone transfer (AXFR) attempts
  7. NSEC walking
  8. Wordlist brute force (424 built-in entries, or supply your own with -w)
  9. Subdomain permutation on discovered names
  10. Recursive discovery on found subdomains (--depth 1..3)
  11. Reverse DNS lookups on discovered IPs

You can also explore a domain's autonomous systems:

mhost -p l --all -w github.com
mhost -p l --all 140.82.121.0/24

Discover AS of github.com.

Validate DNS Configuration

mhost -p c github.com

Check github.com.

The check command runs 13 lints against a domain's DNS records:

Lint What it checks
SOA Start of Authority record validity
NS NS delegation, lame delegation, network diversity
CNAME CNAME usage rules
MX Null MX, duplicate preferences, target resolution
SPF SPF record syntax and policy
DMARC DMARC policy validation
CAA Certificate Authority Authorization tags
TTL TTL consistency across records
DNSSEC DNSSEC presence and configuration
HTTPS/SVCB Service binding record well-formedness
AXFR Zone transfer exposure
Open Resolver Open resolver detection
Delegation Delegation consistency

Disable any lint individually: --no-soa, --no-spf, --no-dnssec, etc.

Trace the Delegation Chain

mhost trace example.com
mhost trace -t AAAA --show-all-servers example.com

Unlike 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.

Check DNS Propagation

mhost -p propagation example.com
mhost -p prop --all example.com

After 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).

Diff Records Between Nameservers

mhost diff --left 8.8.8.8 --right 1.1.1.1 example.com
mhost diff --left 8.8.8.8 --right 1.1.1.1 --all example.com

Compare what two different nameserver sets return for the same domain. Useful for debugging inconsistencies or verifying migrations.

Look Up Record Type Info

mhost info            # List all supported types
mhost info MX         # Details about MX records
mhost info SPF        # Details about SPF TXT sub-type
mhost info _dmarc     # Details about the _dmarc well-known subdomain

Built-in reference with summaries, details, and RFC references for every supported record type, TXT sub-type, and well-known subdomain.


Installation

Homebrew (macOS)

brew install lukaspustina/mhost/mhost

Docker

docker run lukaspustina/mhost:latest mhost l example.com

Debian / Ubuntu

Download the .deb from the latest GitHub Release:

dpkg -i mhost.deb

Redhat / Fedora

Download the .rpm from the latest GitHub Release:

rpm -i mhost.rpm

Cargo (Rust developers)

cargo install --features app mhost

From Source

git clone https://github.com/lukaspustina/mhost
cd mhost
make install

Global Options

mhost has a rich set of options that apply to all commands:

Nameserver selection:
  -s, --nameserver <SPEC>           Add a nameserver (IP, or protocol:host:port,...)
  -p, --predefined                  Add 84 predefined public nameservers
      --predefined-filter <PROTO>   Filter predefined by protocol [udp, tcp, tls, https]
      --list-predefined             Show all predefined nameservers
  -f, --nameservers-from-file <F>   Load nameservers from file
      --no-system-nameservers       Skip /etc/resolv.conf nameservers
  -S, --no-system-lookups           Skip system nameservers for lookups

IP version filtering:
  -4, --ipv4-only                   Only use IPv4 nameservers and return IPv4 results
  -6, --ipv6-only                   Only use IPv6 nameservers and return IPv6 results

Concurrency & resilience:
      --limit <N>                   Max nameservers to query [default: 100] (1-10000)
      --max-concurrent-servers <N>  Max concurrent nameservers [default: 10] (1-100)
      --max-concurrent-requests <N> Max concurrent requests per server [default: 5] (1-50)
      --retries <N>                 Retries per server [default: 0] (0-10)
      --timeout <SECS>              Response timeout [default: 5] (1-300)
      --continue-on-error           Continue on server errors
      --continue-on-timeout         Continue on server timeouts
      --wait-multiple-responses     Wait for additional responses until timeout

Output:
  -o, --output <FORMAT>             Output format: summary or json [default: summary]
  -q, --quiet                       Only print results (no status messages)
      --no-color                    Disable colored output
      --ascii                       ASCII-only output (no Unicode symbols)
      --show-errors                 Show error counts
  -v                                Increase verbosity (repeat for more)

Command Reference

Lookup

mhost l [OPTIONS] <DOMAIN | IP | CIDR | SERVICE SPEC>
  -t, --record-type <TYPE>   Record types [default: A,AAAA,CNAME,MX]
      --all                  Query all record types
  -s, --service              Parse argument as SRV service spec
  -w, --whois                Include WHOIS information for A/AAAA/PTR results

Accepts 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).

Domain Lookup

mhost domain-lookup [OPTIONS] <DOMAIN>
      --all                     Include extended well-known subdomains (~68 total)
  -p, --show-partial-results    Show results incrementally

Queries the apex plus well-known subdomains covering:

  • Apex: A, AAAA, MX, NS, SOA, CAA, HTTPS, TXT, CNAME, SVCB, NAPTR, SSHFP
  • Email auth: DMARC, MTA-STS, TLS-RPT, BIMI
  • Email services: submission, IMAP, POP3, autodiscover (SRV)
  • TLS/DANE: TLSA for ports 443, 25, 587, 993, etc.
  • Communication: SIP, XMPP, Matrix (SRV)
  • Calendar/Contacts: CalDAV, CardDAV (SRV)
  • Infrastructure: LDAP, Kerberos (SRV)
  • Modern protocols: STUN, TURN (SRV)
  • Verification: ACME challenge, AT Protocol, DNSLink, domain verification TXT records

Discover

mhost d [OPTIONS] <DOMAIN>
  -s, --subdomains-only            Show only subdomains
  -w, --wordlist-from-file <F>     Custom wordlist file
      --no-ct-logs                 Skip Certificate Transparency queries
      --depth <N>                  Recursive discovery depth [default: 0] (0-3)
      --rnd-names-number <N>       Random names for wildcard check [default: 3] (1-20)
      --rnd-names-len <N>          Random name length [default: 32] (8-128)
  -p, --show-partial-results       Show results incrementally

Check

mhost c [OPTIONS] <DOMAIN>
  -p, --show-partial-results         Show results after each lint
  -i, --show-intermediate-lookups    Show all DNS lookups made during checks
      --no-soa                       Disable SOA check
      --no-ns                        Disable NS delegation check
      --no-cnames                    Disable CNAME lint
      --no-mx                        Disable MX check
      --no-spf                       Disable SPF check
      --no-dmarc                     Disable DMARC check
      --no-caa                       Disable CAA check
      --no-ttl                       Disable TTL check
      --no-dnssec                    Disable DNSSEC check
      --no-https-svcb                Disable HTTPS/SVCB check
      --no-axfr                      Disable AXFR check
      --no-open-resolver             Disable open resolver check
      --no-delegation                Disable delegation check

Trace

mhost trace [OPTIONS] <DOMAIN>
  -t, --record-type <TYPE>       Record type to query [default: A]
      --max-hops <N>             Maximum delegation hops [default: 10] (1-20)
      --show-all-servers         Show per-server details (IP, latency, outcome)
  -p, --show-partial-results     Show each hop as it completes

Propagation

mhost -p propagation [OPTIONS] <DOMAIN>
  -t, --record-type <TYPE>       Record types [default: A,AAAA,CNAME,MX]
      --all                      Check all record types
  -p, --show-partial-results     Show results incrementally

Diff

mhost diff [OPTIONS] --left <SERVER> --right <SERVER> <DOMAIN>
      --left <SERVER>            Left nameserver(s) (repeatable)
      --right <SERVER>           Right nameserver(s) (repeatable)
  -t, --record-type <TYPE>       Record types [default: A,AAAA,CNAME,MX,NS,SOA,TXT]
      --all                      Compare all record types

Predefined Nameservers

mhost 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.

Provider Primary IPv4 Secondary IPv4 IPv6 TLS/HTTPS Hostname
Cloudflare 1.1.1.1 1.0.0.1 2606:4700:4700::1111 / ::1001 cloudflare-dns.com
Google 8.8.8.8 8.8.4.4 2001:4860:4860::8888 / ::8844 dns.google
Quad9 9.9.9.10 149.112.112.10 2620:fe::10 / ::fe:10 dns10.quad9.net
Mullvad 194.242.2.2 193.19.108.2 2a07:e340::2 dns.mullvad.net
Wikimedia 185.71.138.138 185.71.139.139 2001:67c:930::1 / ::2 wikimedia-dns.org
DNS4EU 185.134.197.54 185.134.196.54 -- unfiltered.joindns4.eu

Use mhost --list-predefined to see every configuration.

Supported Record Types

Type Description Type Description
A IPv4 address NS Name server
AAAA IPv6 address OPENPGPKEY OpenPGP public key
ANAME ANAME / ALIAS PTR Pointer (reverse DNS)
ANY Query all types SOA Start of Authority
CAA CA Authorization SRV Service locator
CNAME Canonical name SSHFP SSH fingerprint
HINFO Host information SVCB Service binding
HTTPS HTTPS service binding TLSA TLS/DANE certificate
MX Mail exchange TXT Text record
NAPTR Naming Authority Pointer DNSSEC DNSKEY, DS, RRSIG, NSEC, ...

Using mhost as a Rust Library

mhost is also a reusable library. Build without the CLI:

cargo build --lib   # no CLI dependencies

Builder API (recommended)

use mhost::resolver::{ResolverGroupBuilder, MultiQuery};
use mhost::resolver::lookup::Uniquify;
use mhost::nameserver::predefined::PredefinedProvider;
use mhost::RecordType;
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let resolvers = ResolverGroupBuilder::new()
        .system()
        .predefined(PredefinedProvider::Google)
        .timeout(Duration::from_secs(3))
        .build()
        .await?;

    let query = MultiQuery::multi_record(
        "example.com",
        vec![RecordType::A, RecordType::AAAA],
    )?;
    let lookups = resolvers.lookup(query).await?;
    let a_records = lookups.a().unique().to_owned();
    println!("A records: {:?}", a_records);
    Ok(())
}

Manual Construction

use mhost::nameserver::NameServerConfig;
use mhost::resolver::{MultiQuery, Resolver, ResolverConfig, ResolverGroup};
use mhost::resolver::lookup::Uniquify;
use mhost::RecordType;
use std::net::SocketAddr;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut resolvers = ResolverGroup::from_system_config(Default::default()).await?;

    let sock_addr: SocketAddr = "8.8.8.8:53".parse()?;
    let config = ResolverConfig::new(NameServerConfig::udp(sock_addr));
    let google = Resolver::new(config, Default::default()).await?;
    resolvers.add(google);

    let query = MultiQuery::multi_record(
        "example.com",
        vec![RecordType::A, RecordType::AAAA, RecordType::TXT],
    )?;
    let lookups = resolvers.lookup(query).await?;
    let a_records = lookups.a().unique().to_owned();
    println!("A records: {:?}", a_records);
    Ok(())
}

See docs.rs/mhost for the full API documentation.


JSON Output

Every command supports --output json for machine-readable output. Combine with -q (quiet) to suppress status messages:

mhost -q --output json l --all example.com | jq .
mhost -q --output json trace example.com | jq '.hops[] | .zone_name'
mhost -q --output json c example.com | jq '.results[] | select(.status != "Ok")'

Changelog

See the CHANGELOG for a full release history.

Limitations

  • Only DNS class IN is supported.

Architecture Design Records

The docs/adr/ directory contains Architecture Decision Records for the project.

Thanks

Thanks to Benjamin Fry for Hickory DNS (formerly Trust-DNS), which does all the heavy DNS lifting.

License

MIT or Apache-2.0, at your option.

Postcardware

You'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

Lukas Pustina
CenterDevice GmbH
Rheinwerkallee 3
53227 Bonn
Germany