Files
nxdns/AGENTS.md
T
2025-12-26 18:42:04 +01:00

4.2 KiB

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

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:

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.comgoogle.comcom)
  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:

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.