FR: Allow the dns parser to handle and pass EDNS0 payloads.
I've currently set up caddy-l4 to terminate DNS over TCP (DoT) and then forward the queries along to an internal DNS server. (Pi-hole but I'm biased.) Currently that means the resolver is seeing the client as the IP address of the router where Caddy is configured. Pi-hole is EDNS0 aware and can parse that to properly show the IP address of the client sending the query. I see the library used in the dns module is EDNS0 aware https://github.com/miekg/dns/blob/d495d332977200d75cfcb37669df92ecec663549/defaults.go#L121.
Is that something that can be added to the l4 module? I'm working on writing some guides for our users to be able to send their DoT queries when off the LAN and being able to pass along that EDNS0 information would be very helpful for users to administer with. I'm using opnsense as the border router/firewall and the two options I see so far are caddy or ngnix handling the TLS and then passing the payload on to the internal DNS server.
Thanks!
Sure, probably! I don't know much about this -- do you want to send a PR and I'll take a look?
@dschaper, let me first explain you how the current DNS-related functionality works:
caddy-l4receives the first packet of a new connection- It checks if this packet contains something that
caddy-l4knows how to route - In particular, there is
dnsmatcher that can detect DNS requests - Under the hood
dnsmatcher uses miekg/dns to parse the incoming bytes
- It checks if this packet contains something that
- If any matcher returns true, i.e. successfully matches this packet,
caddy-l4runs handlers one by one- If the first packet contains a DNS request, every other packet is presumed to be DNS-related as well
- This first packet is passed to the first handler completely unchanged, i.e. no matcher is capable of altering bytes
- There is
proxyhandler that basically copies bytes between connections
- If no matcher returns true, this packet is ignored, or passed through to the next listener wrapper if applicable
Thus, even though miekg/dns is EDNS0-aware, it is only used for detecting and filtering DNS requests, and nothing inside caddy-l4 is currently capable of modifying DNS requests in any way.
I think what you're requesting is most likely possible to implement. It could be a separate handler to run before proxy, just like proxy_protocol works. PRs are welcome.
Last year I worked on a DNS handler for caddy-l4, and the requested functionality could also be implemented there in a more natural and efficient way. Unfortunately, it's still unfinished and/or lacks proper testing. I'll probably submit it as a WIP PR when I have time.
A random idea, why not parse the proxy protocol header of the packets in pihole? That should contain the original IP of the client.
I think caddy-l4 can already send and parse that header?
https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
A random idea, why not parse the proxy protocol header of the packets in pihole?
That might be an option but that limits the functionality to Pi-hole. We like to give back where we can and having this in Caddy-l4 would let other DNS sinkholes have the same abilities. No need to go proprietary.
Last year I worked on a DNS handler for caddy-l4, and the requested functionality could also be implemented there in a more natural and efficient way. Unfortunately, it's still unfinished and/or lacks proper testing. I'll probably submit it as a WIP PR when I have time.
@vnxme Is there a repo with a branch that I could fork to take a look? I haven't done anything in go in a long time but this would be a good project to learn again with.
Thanks for the discussion so far.
Would love to see a DNS handler! Might start to overlap a bit with CoreDNS, but, I guess that's fine. :100: CoreDNS exposes many of its functions as libraries: https://pkg.go.dev/github.com/coredns/coredns
We can also just use miekg/dns directly; either way.
@dschaper, @mholt, please see https://github.com/mholt/caddy-l4/pull/347.
Amazing work @vnxme -- VERY cool!