123 lines
4.2 KiB
Markdown
123 lines
4.2 KiB
Markdown
# 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.
|