# dns-helper Development Guidelines ## Project Overview dns-helper — a Go CLI tool that resolves hostnames against a specified DNS server and writes the resulting IP-to-hostname mappings into the local hosts file. It manages a clearly delimited block within the hosts file so it can cleanly add and remove only its own entries. Built as a single static binary with no runtime dependencies. ## Go Toolchain — CRITICAL **Always use `go1.20` instead of `go` for ALL Go toolchain operations.** The system default `go` command may be a newer version that is incompatible with this project. ```powershell # CORRECT — use these commands: go1.20 build . go1.20 test ./... go1.20 vet ./... go1.20 fmt ./... # WRONG — do NOT use bare 'go': go build . # May use incompatible Go version go test ./... # May use incompatible Go version ``` **Go 1.21+ features that MUST NOT be used:** - `min`, `max`, `clear` builtins - Range-over-int (`for i := range 10`) - `slices`, `maps`, `cmp` packages - `log/slog` package - Any other Go 1.21+ standard library additions ## Building ```powershell # Standard debug build for Windows .\build.ps1 # Optimized release build for all platforms .\build.ps1 -Release # Clean build .\build.ps1 -Clean # Cross-compile for all platforms .\build.ps1 -CrossCompile # Create release packages (requires binaries already built) .\build.ps1 -Release -Package ``` Output: `build\dns-helper.exe` (default), `build\dns-helper--[.exe]` (cross-compile). Release packages: `releases\dns-helper---.zip` / `.tar.gz` ## Running dns-helper dns-helper has two commands: `add` and `delete` (with short aliases `a` and `d`/`del`). ```powershell # Add one or more hostnames (resolves via the given DNS server, writes to hosts file) .\build\dns-helper.exe add -host hostname.example.com -server dns.example.com .\build\dns-helper.exe a -host hostname.example.com -server dns.example.com # Add multiple hostnames at once (comma-separated) .\build\dns-helper.exe add -host "host1.example.com,host2.example.com" -server dns.example.com # Delete a specific hostname from the managed block .\build\dns-helper.exe delete -host hostname.example.com .\build\dns-helper.exe del -host hostname.example.com .\build\dns-helper.exe d -host hostname.example.com # Delete multiple hostnames (comma-separated) .\build\dns-helper.exe delete -host "host1.example.com,host2.example.com" # Delete ALL entries added by dns-helper .\build\dns-helper.exe delete all .\build\dns-helper.exe delete a ``` ### Flag Reference | Command | Flag | Required | Description | |---------|------|----------|-------------| | `add` | `-host` | Yes | Comma-separated list of hostnames to resolve and add | | `add` | `-server` | Yes | DNS resolver to query (e.g. `dns.example.com`) | | `delete` | `-host` | Yes (unless `all`) | Comma-separated list of hostnames to remove | | `delete all` | — | — | Removes every entry dns-helper has written | ### Exit Codes | Code | Meaning | |------|---------| | 0 | Success | | 1 | Error or partial failure (e.g. one hostname failed to resolve) | ### Hosts File Management dns-helper wraps its entries between two marker lines: ``` # DNSHelper <<-> START CONFIG 192.0.2.1 hostname.example.com # DNSHelper <->> END CONFIG ``` Only lines within this managed block are ever modified or removed. The rest of the hosts file is preserved exactly. A backup of the hosts file is written to the executable's directory before every write. ## Testing ```powershell # Run all tests go1.20 test ./... # Run with coverage go1.20 test -cover ./... # Run a specific package go1.20 test ./hostfile/... go1.20 test ./resolver/... go1.20 test ./lockfile/... go1.20 test ./platform/... # Vet all code go1.20 vet ./... ``` ## Project Structure ``` main.go CLI entry point (add / delete commands, flag parsing) hostfile/ hostfile.go Hosts file parsing, DNSEntry type, add/remove helpers managed.go Managed block read/write logic filesystem.go FileSystem interface + OSFileSystem implementation hostfile_test.go managed_test.go lockfile/ lockfile.go File-based mutex to prevent concurrent modifications lockfile_test.go platform/ platform.go Platform interface — GetHostsFilePath() platform_windows.go Windows implementation platform_darwin.go macOS implementation platform_linux.go Linux implementation platform_test.go resolver/ resolver.go DNS resolution via golang.org/x/net/dns/dnsmessage resolver_test.go ``` ## Code Style - **Go 1.20 only** — no Go 1.21+ features - **Standard library first** — only `golang.org/x/*` dependencies allowed; no `github.com/*` third-party packages - **Error wrapping**: `fmt.Errorf("context: %w", err)` - **CGO disabled**: `CGO_ENABLED=0` for static binaries - **Table-driven tests** preferred ## Dependencies From `go.mod`: - `golang.org/x/net` — DNS message parsing (`golang.org/x/net/dns/dnsmessage`) ## After Every Implementation After completing any code change, validate in this order: 1. Run tests for changed packages: ```powershell go1.20 test ./hostfile/... ./resolver/... # example ``` 2. Run the full suite: ```powershell go1.20 test ./... ``` 3. Build the project: ```powershell .\build.ps1 ``` 4. **Update `README.md`** — Review the root `README.md` and update it with any information an admin or end-user would need to know as a result of the changes. This includes but is not limited to: - New or changed CLI commands, flags, or aliases - New or changed exit codes - New dependencies - Changes to build steps or requirements - New environment variables or configuration - Changes to supported platforms - Changes to the project structure (new packages, renamed files) - Any new prerequisites or setup steps - Security-relevant changes (e.g. new permissions required) 5. Report test pass/fail counts and build outcome before considering the task complete.