cdns
A DNS forwarder with query logging, blocklist support, and a real-time web dashboard.
By default it forwards queries to SUNET's DNS server (89.32.32.32). It logs queries to local Redis and can display them in a live web dashboard with GeoIP enrichment.
Features
- DNS query forwarding with caching
- Domain blocklist support (EasyList format)
- Real-time web dashboard with WebSocket updates
- GeoIP enrichment (organization, country, city) for resolved IPs
- Query aggregation by domain/type with request counts
- Redis logging for query history
Prerequisites
- Go 1.18+
- Redis server running locally on port 6379
- just task runner
- Root/sudo access for binding to port 53
- (Optional) MaxMind GeoLite2 databases for IP enrichment
Building
just build
Running
Make sure Redis server is running locally first.
Basic usage (DNS only)
sudo ./cdns
This starts the DNS server on port 53, forwarding to 89.32.32.32.
With web dashboard
sudo ./cdns --webport 8080
Open http://localhost:8080 to view the live query dashboard.
With GeoIP enrichment
Download free GeoLite2 databases from MaxMind and place them in the data/ directory:
sudo ./cdns --webport 8080 --geodb data/GeoLite2-City.mmdb --asndb data/GeoLite2-ASN.mmdb
The dashboard will show organization names, countries, and cities for resolved IP addresses.
Command Line Options
| Flag |
Default |
Description |
--port |
53 |
DNS server port |
--remote |
89.32.32.32:53 |
Upstream DNS server from SUNET |
--webport |
8080 |
Web dashboard port (0 to disable) |
--geodb |
|
Path to GeoLite2-City.mmdb |
--asndb |
|
Path to GeoLite2-ASN.mmdb |
Web Dashboard
The dashboard displays DNS queries in real-time:
- Last Seen: Timestamp of most recent query
- Count: Number of requests for this domain+type
- Domain: Queried domain name
- Type: Record type (A, AAAA, etc.)
- Resolved IPs: IP addresses returned
- Organization: Company/ISP owning the IP (requires GeoIP)
- Location: Country and city (requires GeoIP)
- Source: Cache or Upstream
- Status: OK or Blocked
Queries are aggregated by domain+type - repeated queries update the existing row and increment the count.
Blocklists
Place blocklist files in the blocklists/ directory. Files must be named clean-*.txt with one domain per line. Use scripts/easylist.py to convert EasyList format files.
Systemd Service Example
[Unit]
Description=cdns
After=network.target
[Service]
Type=simple
ExecStart=/usr/sbin/cdns --webport 8080 --geodb /var/lib/cdns/data/GeoLite2-City.mmdb --asndb /var/lib/cdns/data/GeoLite2-ASN.mmdb
Restart=always
AmbientCapabilities=cap_net_bind_service
[Install]
WantedBy=multi-user.target
License
GPL-3.0-or-later