# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview nxdns is a DNS sinkhole written in Zig. It denies ads/trackers/malware by returning 0.0.0.0 for denied domains and forwards allowed queries to upstream DoH/DoT servers. ## Build Commands ```bash zig build # Build the project zig build run # Run nxdns zig build test # Run all tests zig fmt src/ # Format code ``` Validate config without running: ```bash NXDNS_CONFIG=./config.example.toml ./zig-out/bin/nxdns check ``` ## Architecture ``` src/ ├── main.zig # Entry point, CLI, server orchestration ├── events.zig # Event signaling (denylist reload via eventfd) ├── util.zig # Utility functions ├── dns/ # DNS protocol (RFC 1035) │ ├── packet.zig # Full packet parse/encode │ ├── header.zig # 12-byte DNS header │ ├── name.zig # Domain name with compression │ ├── question.zig # Query section │ ├── record.zig # Resource records (A, AAAA, CNAME, etc.) │ ├── edns.zig # EDNS (OPT record) support │ └── types.zig # Enums: QType, QClass, RCode ├── server/ │ ├── udp.zig # UDP listener (port 53) │ ├── tcp.zig # TCP listener (length-prefixed) │ ├── handler.zig # Core logic: deny check → cache → upstream │ ├── shutdown.zig # Graceful shutdown coordination │ └── rate_limiter.zig # Per-client rate limiting ├── upstream/ │ ├── doh.zig # DNS-over-HTTPS client │ ├── dot.zig # DNS-over-TLS client │ ├── pool.zig # Failover across upstreams │ └── connection_pool.zig # Connection pooling ├── filter/ │ ├── denylist.zig # HashMap with parent-walking lookup │ ├── fetcher.zig # Download and parse denylist URLs │ └── safe_search.zig # Rewrite domains to force safe search ├── cache/ │ └── dns_cache.zig # TTL-based response cache ├── storage/ │ ├── db.zig # SQLite wrapper │ ├── schema.zig # Tables and migrations │ └── logger.zig # Async batched query logging ├── config/ │ ├── config.zig # TOML config loading │ ├── toml.zig # TOML parser │ └── watcher.zig # inotify + signalfd for hot reload ├── logging/ │ └── logger.zig # Structured logging └── web/ ├── server.zig # HTTP server ├── response.zig # HTTP response helpers ├── json.zig # JSON serialization ├── auth.zig # Session-based authentication └── api/ # REST API handlers ├── stats.zig ├── queries.zig ├── clients.zig ├── groups.zig ├── denylists.zig ├── rules.zig └── settings.zig ``` ## Key Data Flow 1. Query arrives (UDP/TCP) → `handler.handle()` 2. Check denylist (parent-walking: `ads.google.com` → `google.com` → `com`) 3. If denied: return 0.0.0.0 response 4. If allowed: check cache → query upstream (DoH/DoT) → cache response 5. Log query to SQLite asynchronously ## Code Patterns **Database transactions** - Use RAII pattern for safety: ```zig var tx = try db.begin(); defer tx.deinit(); // Auto-rollback if not committed // ... do work ... try tx.commit(); ``` ## Design Principles - **Lean**: No bloat, only what's needed - **Pragmatic**: Real-world patterns that work - **Simple**: Easy to understand and extend ## Implementation Status See PLAN.md for the full spec. Current state: - ✅ DNS protocol parsing/encoding (with EDNS) - ✅ UDP/TCP servers - ✅ Denylist with parent-walking - ✅ DNS cache - ✅ DoH client - ✅ DoT client (with connection pooling) - ✅ Web UI with REST API - ✅ Config hot reload (inotify + signalfd) - ✅ Denylist fetching and auto-reload - ✅ Safe search enforcement - ✅ Log retention enforcement (startup + daily cleanup) - ✅ Integration tests ## Reference Zig 0.15.2 stdlib source is at `.ignore/zig/` for API verification.