A simple DNS proxy server written in Go that forwards DNS queries to an upstream DNS server.
- Listens on UDP port 53 (configurable)
- Forwards DNS queries to upstream DNS server (default: 1.1.1.1)
- Concurrent request handling using goroutines
- Configurable upstream DNS server
- Verbose logging option
- 5-second timeout for upstream responses
go build -o dns-proxysudo ./dns-proxy./dns-proxy -listen :5353sudo ./dns-proxy -upstream 8.8.8.8:53sudo ./dns-proxy -verbose./dns-proxy -listen :5353 -upstream 8.8.8.8:53 -verbose-listen: Address to listen on (default::53)-upstream: Upstream DNS server address (default:1.1.1.1:53)-verbose: Enable verbose logging (default:false)-api-port: API server port (default::9090)
You can test the DNS proxy using dig or nslookup:
# If running on port 53
dig @localhost example.com
# If running on port 5353
dig @localhost -p 5353 example.com# If running on port 53
nslookup example.com localhost
# If running on port 5353
nslookup -port=5353 example.com localhostThe DNS proxy includes a REST API server for dynamic blocklist management. The API server runs on port 9090 by default (configurable via -api-port flag).
Update the blocklist with a new set of domains to block. This replaces the current blocklist entirely.
Endpoint: POST /api/blocklist
Request Body:
{
"blocklist": [
"example.com",
"ads.example.com",
"*.tracker.com"
]
}Response:
{
"status": "success",
"message": "Blocklist updated successfully",
"count": 3
}curl -X POST http://localhost:9090/api/blocklist \
-H "Content-Type: application/json" \
-d '{
"blocklist": [
"ads.example.com",
"tracker.example.com",
"malware.com"
]
}'curl -X POST http://localhost:9090/api/blocklist \
-H "Content-Type: application/json" \
-d '{
"blocklist": [
"*.doubleclick.net",
"*.googlesyndication.com",
"*.facebook.com"
]
}'curl -X POST http://localhost:9090/api/blocklist \
-H "Content-Type: application/json" \
-d '{
"blocklist": [
"*.googleadservices.com",
"*.googlesyndication.com",
"*.doubleclick.net",
"*.amazon-adsystem.com",
"*.advertising.com",
"*.adnxs.com",
"*.adsrvr.org",
"analytics.google.com",
"*.facebook.com",
"*.twitter.com"
]
}'# Note: The API requires at least one entry, so this will return an error
# To effectively clear blocking, send a list with a non-existent domain
curl -X POST http://localhost:9090/api/blocklist \
-H "Content-Type: application/json" \
-d '{
"blocklist": ["_dummy.local"]
}'# Create a blocklist file
cat > blocklist.json <<EOF
{
"blocklist": [
"ads.example.com",
"tracker.example.com",
"*.analytics.com",
"*.telemetry.com"
]
}
EOF
# Send the file contents to the API
curl -X POST http://localhost:9090/api/blocklist \
-H "Content-Type: application/json" \
-d @blocklist.json# Start the DNS proxy with verbose logging
./dns-proxy -verbose
# In another terminal, update the blocklist
curl -X POST http://localhost:9090/api/blocklist \
-H "Content-Type: application/json" \
-d '{
"blocklist": ["test.example.com"]
}'
# You'll see detailed logs about the blocklist update in the DNS proxy outputThe blocklist supports wildcard patterns with *. prefix:
example.com- Blocks only the exact domainexample.com*.example.com- Blocks all subdomains ofexample.com(e.g.,ads.example.com,tracker.example.com)- Wildcards match any subdomain level (e.g.,
*.example.commatchesa.b.c.example.com)
200 OK- Blocklist updated successfully400 Bad Request- Invalid JSON or empty blocklist405 Method Not Allowed- Wrong HTTP method (only POST is supported)
- Running on port 53 requires root/administrator privileges
- The proxy handles UDP DNS queries only
- Maximum DNS message size is 512 bytes (standard UDP DNS limit)
- Each query is handled in a separate goroutine for concurrent processing
DNS Proxy v0.0.1
Listening on: :53
Upstream DNS: 1.1.1.1:53
Starting DNS proxy...
DNS proxy listening on :53
With verbose mode enabled:
DNS Proxy v0.0.1
Listening on: :53
Upstream DNS: 1.1.1.1:53
Starting DNS proxy...
DNS proxy listening on :53
2025/12/10 15:30:45 Received 45 bytes from 127.0.0.1:54321
2025/12/10 15:30:45 Processing query from 127.0.0.1:54321
2025/12/10 15:30:45 Forwarded query to 1.1.1.1:53
2025/12/10 15:30:45 Received 61 bytes from upstream
2025/12/10 15:30:45 Sent response to 127.0.0.1:54321