https://github.com/cbuijs/sdproxy
DNS Proxy that is simple and fast with not so simple features. Focused on routed DNS forwarding, filtering and parental control.
https://github.com/cbuijs/sdproxy
ads blocking control dns doh doh3 doq filtering forwarding golang https openwrt parental-control proxy quic security tcp tls tracking udp
Last synced: 4 days ago
JSON representation
DNS Proxy that is simple and fast with not so simple features. Focused on routed DNS forwarding, filtering and parental control.
- Host: GitHub
- URL: https://github.com/cbuijs/sdproxy
- Owner: cbuijs
- License: mit
- Created: 2026-02-27T20:12:16.000Z (about 1 month ago)
- Default Branch: main
- Last Pushed: 2026-03-31T08:26:11.000Z (6 days ago)
- Last Synced: 2026-03-31T10:24:37.302Z (6 days ago)
- Topics: ads, blocking, control, dns, doh, doh3, doq, filtering, forwarding, golang, https, openwrt, parental-control, proxy, quic, security, tcp, tls, tracking, udp
- Language: Go
- Homepage:
- Size: 183 KB
- Stars: 24
- Watchers: 1
- Forks: 2
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# sdproxy
A DNS proxy that gives you real control over your home network.
---
**Note:** The [full_reference_config.yaml](https://github.com/cbuijs/sdproxy/blob/main/full_reference_config.yaml) is always more up to date than this README. When in doubt, check there.
---
DNS is the [phonebook of the internet](https://en.wikipedia.org/wiki/Domain_Name_System) - every device on your network looks up a name before it connects anywhere.
**sdproxy** sits in the middle of that, on your router, and lets you decide what happens next: cache it, block it, route it to a different resolver, or apply time limits per child. No cloud subscription, no monthly fee, no external service that goes down.
It's written in Go, compiles to a single binary, and is lean enough to run on cheap home routers (OpenWrt on a TP-Link or Netgear, pfSense, OPNsense, or just a plain Linux box).
---
## What it does
### Speaks every flavour of DNS
Plain old UDP/TCP (port 53), encrypted DNS-over-TLS (DoT), DNS-over-HTTPS (DoH), DNS-over-QUIC (DoQ), and the HTTP/3 variant. You pick what you want to listen on and what you want to forward to.
### Caches aggressively
Answered something recently? Serve it from cache. That means faster browsing and fewer queries leaving your network. If a record expires while it's still popular, sdproxy refreshes it silently in the background so your devices never notice a miss. Stale records are served instantly while the refresh is in flight.
### Knows your local network
Point it at your DHCP lease files and `/etc/hosts` and it will answer local name lookups (your NAS, your printer, your Pi) without bothering an upstream resolver. Works with dnsmasq, ISC DHCP, Kea, and odhcpd - whatever your router uses.
### Routes different devices differently
Map a device's MAC address to a different upstream resolver group. The kid's tablet goes through a filtered resolver, your work laptop goes somewhere else, guests go through a basic default.
You can also route by domain suffix - queries for `.lan` stay local, queries for your company VPN domains go to your VPN's resolver.
### Parental controls - per child, per category
Set up a profile per child, assign their devices by MAC address, and configure:
- **A schedule** - internet only between 07:00 and 21:00, for example. Different hours for school days vs weekends.
- **A daily time budget** - 2 hours total, with sub-limits per category (1 hour games, 30 minutes social media).
- **Category blocking** - social media completely blocked for one child, educational sites always allowed regardless of budget.
Categories (games, streaming, social media, etc.) are loaded from public domain lists. Only the categories you actually use are loaded - if you don't define a budget for "gambling", that list is never touched.
Time is tracked via DNS heartbeat: categorised domains get a short TTL so devices keep checking in. Accuracy is roughly plus or minus 5 minutes per session - more than good enough for home use.
Usage is snapshotted to disk so a router reboot doesn't wipe the day's counters.
See [CATEGORY_SOURCES.md](https://github.com/cbuijs/sdproxy/blob/main/CATEGORY_SOURCES.md) for some good domain-lists that can be used for different purposes.
### Web admin panel
Optional "operations only" browser-based UI (enable it with a password in the config). No restart needed to flip a group into a different mode:
| Mode | What it does |
|---|---|
| **DEFAULT** | Normal - schedule and budget apply as configured. |
| **ALLOW** | Gate wide open - no schedule, no budget, no blocks. For "I need internet right now" moments. |
| **FREE** | Suspend the schedule and budget, but keep everything else. Good for supervised homework time. |
| **BLOCK** | Cut internet entirely for that group. |
And some stats:
### Encrypts and anonymises your DNS traffic
Queries going upstream are stripped of client subnet info (EDNS ECS) and padded to standard sizes so they don't leak which domains you're querying by size alone. Cookies are stripped too.
### DDR - clients auto-upgrade to encrypted DNS
With DDR (RFC 9462) enabled, any client that supports it (iOS, Android, modern Windows/macOS) will automatically discover and switch to encrypted DNS. No need to configure each device individually.
### Throttles itself under load
Built-in adaptive admission control monitors memory pressure, goroutine counts, and cache miss rate. If the router is getting hammered it backs off gracefully instead of falling over. Zero configuration needed.
---
## Quick start
```bash
git clone https://github.com/cbuijs/sdproxy
cd sdproxy
go build -o sdproxy .
./sdproxy -config config.yaml
```
Requires Go 1.25+. No CGo, no external libraries.
### Minimal config
```yaml
server:
listen_udp: ["0.0.0.0:53"]
cache:
enabled: true
size: 1024
min_ttl: 60
upstreams:
default:
- "udp://1.1.1.1:53"
- "udp://9.9.9.9:53"
```
That's enough to get a caching DNS proxy running. Add sections as you need them.
### Build for your router
```bash
# OpenWrt MIPS (TP-Link, Netgear, etc.)
GOOS=linux GOARCH=mipsle GOMIPS=softfloat go build -ldflags="-s -w" -o sdproxy .
# OpenWrt ARM (Linksys, Asus, etc.)
GOOS=linux GOARCH=arm GOARM=7 go build -ldflags="-s -w" -o sdproxy .
# OpenWrt x86_64
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o sdproxy .
```
The `-s -w` flags strip debug symbols - saves 30-40% binary size, which matters on small flash storage.
---
## Configuration
Everything lives in one YAML file. The `full_reference_config.yaml` in this repo documents every single option inline - that file is the manual. Copy it, strip what you don't need, adjust the rest.
---
## Log output
```
2026/03/16 14:23:01 [DNS] [UDP] 192.168.1.42 (alice-iphone) -> google.com A | ROUTE: kids | UPSTREAM: doh://cloudflare-dns.com | OK
2026/03/16 14:23:02 [DNS] [UDP] 192.168.1.42 (alice-iphone) -> google.com A | ROUTE: kids | CACHE HIT
2026/03/16 14:23:05 [DNS] [UDP] 192.168.1.10 -> nas.lan A | LOCAL IDENTITY
2026/03/16 14:23:10 [DNS] [UDP] 192.168.1.42 (alice-iphone) -> youtube.com A | PARENTAL BLOCK
```
Disable with `logging.log_queries: false`. Strip timestamps for systemd/procd with `logging.strip_time: true`.
---
**Note:** The [full_reference_config.yaml](https://github.com/cbuijs/sdproxy/blob/main/full_reference_config.yaml) is always more up to date than this README. When in doubt, check there.