Skip to main content

macos_resolver/
lib.rs

1//! # macos-resolver
2//!
3//! Manage macOS `/etc/resolver/` files for custom DNS domain resolution.
4//!
5//! macOS reads files under `/etc/resolver/<domain>` to route DNS queries for
6//! specific domain suffixes to designated nameservers. This crate provides a
7//! safe, idempotent API to register, unregister, and list these resolver
8//! entries — with built-in orphan cleanup for crash recovery.
9//!
10//! ## Quick start
11//!
12//! ```rust,ignore
13//! use macos_resolver::{FileResolver, ResolverConfig};
14//!
15//! let resolver = FileResolver::new();
16//!
17//! // Register (requires root).
18//! resolver.register(&ResolverConfig::new("myapp.local", "127.0.0.1", 5553))?;
19//!
20//! // Query state.
21//! assert!(resolver.is_registered("myapp.local"));
22//! let domains = resolver.list()?;
23//!
24//! // Unregister on shutdown.
25//! resolver.unregister("myapp.local")?;
26//! ```
27//!
28//! ## Crash recovery
29//!
30//! Each resolver file records the PID of the process that created it.
31//! On next startup, call [`FileResolver::cleanup_orphaned`] to remove stale
32//! files left by processes that exited without cleaning up:
33//!
34//! ```rust,ignore
35//! let resolver = FileResolver::new();
36//! let removed = resolver.cleanup_orphaned()?;
37//! ```
38//!
39//! ## Verification
40//!
41//! Changes take effect immediately — no daemon restart needed. Verify with:
42//!
43//! ```bash
44//! scutil --dns              # show all registered resolvers
45//! dscacheutil -q host -a name test.myapp.local
46//! ```
47//!
48//! **Note:** `dig` bypasses the macOS system resolver and will *not* show
49//! these entries. Use `scutil`, `dscacheutil`, or `ping` instead.
50//!
51//! ## Permissions
52//!
53//! Writing to `/etc/resolver/` requires root. The caller is responsible for
54//! privilege elevation (`sudo`, `launchd` helper, `SMAppService`, etc.).
55
56#![warn(clippy::all, clippy::pedantic, clippy::nursery)]
57#![allow(clippy::module_name_repetitions)]
58
59pub mod config;
60pub mod error;
61pub mod file_resolver;
62pub mod util;
63
64pub use config::ResolverConfig;
65pub use error::{ResolverError, Result};
66pub use file_resolver::FileResolver;