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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
# ![mhost](docs/images/logo.png) mhost

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

[![CI build](https://github.com/lukaspustina/mhost/workflows/CI%20build/badge.svg)](https://github.com/lukaspustina/mhost/actions/) [![mhost on crates.io](http://meritbadge.herokuapp.com/mhost)](https://crates.io/crates/mhost) [![Documentation on docs.rs](https://docs.rs/mhost/badge.svg)](https://docs.rs/mhost) [![GitHub release](https://img.shields.io/github/release/lukaspustina/mhost.svg)](https://github.com/lukaspustina/mhost/releases) ![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg) ![License: Apache 2.0](https://img.shields.io/badge/license-Apache_2.0-blue.svg)

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

```sh
# 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.](docs/images/multi-lookup-all-records-github.png)

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

## What Can mhost Do?

| Command | Alias | What it does |
|---------|-------|--------------|
| [`lookup`](#lookup) | `l` | Look up DNS records for a domain, IP address, or CIDR block |
| [`domain-lookup`](#domain-lookup) | `domain` | Profile a domain -- apex + 68 well-known subdomains in one operation |
| [`discover`](#discover) | `d` | Find subdomains using 10+ strategies (wordlists, CT logs, AXFR, NSEC walking, ...) |
| [`check`](#check) | `c` | Validate DNS configuration against 13 lints (SOA, NS, SPF, DMARC, DNSSEC, ...) |
| [`trace`](#trace) | `t` | Trace the delegation path from root servers, querying all servers at each hop |
| [`propagation`](#propagation) | `prop` | Check whether a DNS change has propagated across public resolvers |
| [`diff`](#diff) | -- | Compare DNS records between two sets of nameservers |
| [`info`](#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

```sh
mhost l github.com
```

![Default lookup for github.com.](docs/images/default-lookup-github.png)

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

### More Nameservers, More Answers

```sh
mhost -p l github.com
```

![Default lookup with predefined servers for github.com.](docs/images/default-lookup-predefined-servers-github.png)

`-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

```sh
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.](docs/images/default-lookup-servers-list-github.png)

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

```sh
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.](docs/images/default-lookup-all-protocols-github.png)

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

### Profile an Entire Domain

```sh
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

```sh
mhost -p d github.com
```

![Discover github.com.](docs/images/discover-github.png)

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:

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

![Discover AS of github.com.](docs/images/discover-as-github.png)

### Validate DNS Configuration

```sh
mhost -p c github.com
```

![Check github.com.](docs/images/check-github.png)

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

```sh
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

```sh
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

```sh
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

```sh
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)

```sh
brew install lukaspustina/mhost/mhost
```

### Docker

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

### Debian / Ubuntu

Download the `.deb` from the [latest GitHub Release](https://github.com/lukaspustina/mhost/releases):

```sh
dpkg -i mhost.deb
```

### Redhat / Fedora

Download the `.rpm` from the [latest GitHub Release](https://github.com/lukaspustina/mhost/releases):

```sh
rpm -i mhost.rpm
```

### Cargo (Rust developers)

```sh
cargo install --features app mhost
```

### From Source

```sh
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

```sh
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

```sh
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

```sh
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

```sh
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

```sh
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

```sh
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

```sh
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:

```sh
cargo build --lib   # no CLI dependencies
```

### Builder API (recommended)

```rust
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

```rust
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](https://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:

```sh
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](CHANGELOG.md) for a full release history.

## Limitations

- Only DNS class `IN` is supported.

## Architecture Design Records

The [docs/adr/](docs/adr/) directory contains Architecture Decision Records for the project.

## Thanks

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

## 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
```