caddy-l4 icon indicating copy to clipboard operation
caddy-l4 copied to clipboard

FR: Allow the dns parser to handle and pass EDNS0 payloads.

Open dschaper opened this issue 2 months ago • 6 comments

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!

dschaper avatar Sep 19 '25 18:09 dschaper

Sure, probably! I don't know much about this -- do you want to send a PR and I'll take a look?

mholt avatar Sep 19 '25 19:09 mholt

@dschaper, let me first explain you how the current DNS-related functionality works:

  1. caddy-l4 receives the first packet of a new connection
    • It checks if this packet contains something that caddy-l4 knows how to route
    • In particular, there is dns matcher that can detect DNS requests
    • Under the hood dns matcher uses miekg/dns to parse the incoming bytes
  2. If any matcher returns true, i.e. successfully matches this packet, caddy-l4 runs 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 proxy handler that basically copies bytes between connections
  3. 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.

vnxme avatar Sep 21 '25 19:09 vnxme

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

Monviech avatar Oct 07 '25 19:10 Monviech

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.

dschaper avatar Nov 23 '25 21:11 dschaper

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.

mholt avatar Nov 24 '25 21:11 mholt

@dschaper, @mholt, please see https://github.com/mholt/caddy-l4/pull/347.

vnxme avatar Nov 25 '25 11:11 vnxme

Amazing work @vnxme -- VERY cool!

mholt avatar Dec 04 '25 22:12 mholt