Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Proxy Protocol between dnsdist and the recursor #8874

Merged
merged 36 commits into from
Mar 17, 2020

Conversation

rgacogne
Copy link
Member

Short description

This PR implements:

  • outgoing Proxy Protocol (UDP, TCP, healthchecks) in dnsdist ;
  • incoming Proxy Protocol (UDP, TCP) in the recursor.

It allows dnsdist to pass the initial source and destination addresses and ports to the recursor, along with custom values.
Compared to the (ab)use of EDNS Client Subnet, this doesn't prevent preserving an existing ECS value (zeo scope, notably) and provides the ports, along with custom values.
Compared to ECS and XPF, this prevents having to parse the existing payload and inject either an EDNS option or a new record, preserving TSIG-signatures.

Based on a rebased version of #8448.

Could use a good review :)

Checklist

I have:

  • read the CONTRIBUTING.md document
  • compiled this code
  • tested this code
  • included documentation (including possible behaviour changes)
  • documented the code
  • added or modified regression test(s)
  • added or modified unit test(s)

Copy link
Member

@Habbie Habbie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did one skim, looks good so far! I'll test the code, and will do a careful review of the tests you wrote, and post another review.

pdns/pdns_recursor.cc Outdated Show resolved Hide resolved
@rgacogne
Copy link
Member Author

rgacogne commented Mar 2, 2020

I realized that the current logic of trying to reuse TCP backend connections is completely flawed when the proxy protocol is enabled. I'm working on a fix.

@rgacogne
Copy link
Member Author

rgacogne commented Mar 2, 2020

It's in fact more complicated than that because of the custom values. Currently they can be set per-query which works for UDP but doesn't match the fact that they can only be sent once per backend connection over TCP. We could disable connection reuse when the proxy protocol is enabled, but that would be quite bad for performances. On the other hand, if we keep it, we at least need to ensure that the same backend connection can only be used for the same incoming client connection which is a bit better for performances but cumbersome.

@Habbie
Copy link
Member

Habbie commented Mar 2, 2020

I realized that the current logic of trying to reuse TCP backend connections is completely flawed when the proxy protocol is enabled. I'm working on a fix.

I've been wondering if the protocol should come with some framing, but that's another rabbit hole.

@rgacogne
Copy link
Member Author

rgacogne commented Mar 2, 2020

Fixed by disabling TCP connection reuse in dnsdist when a backend has the proxy protocol feature enabled. We could try to still reuse the connection for the same client, as long as the TLV values are empty, but it's error-prone since in that case we should not add the proxy protocol payload for subsequent queries, except if the connection breaks at some point and we need to open a new one.

Copy link
Contributor

@gibson042 gibson042 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm very excited about this, but surprised to see the asymmetry of dnsdist being able to send PROXY messages but not receive them. Do you think it could also get settings like the recursor's proxy-protocol-from and proxy-protocol-maximum-size in this PR?

@rgacogne
Copy link
Member Author

rgacogne commented Mar 3, 2020

I'm very excited about this, but surprised to see the asymmetry of dnsdist being able to send PROXY messages but not receive them. Do you think it could also get settings like the recursor's proxy-protocol-from and proxy-protocol-maximum-size in this PR?

Yes, we are planning on adding support for incoming proxy protocol payload! Unfortunately our time is finite so we had to make some choices. This PR will not extend beyond outgoing proxy protocol, and I'm not sure yet whether we will be able to implement incoming support before 1.5.0, but it will definitely be there in 1.6.0 at the latest.

@rgacogne
Copy link
Member Author

rgacogne commented Mar 4, 2020

Rebased on master to fix a conflict with #8851.

@rgacogne rgacogne requested a review from omoerbeek March 12, 2020 09:32
@rgacogne
Copy link
Member Author

@omoerbeek I requested a review from you mostly for the recursor-related bits, although your review on the rest of the code would be nice to have as well :-)

pdns/proxy-protocol.cc Outdated Show resolved Hide resolved
pdns/pdns_recursor.cc Outdated Show resolved Hide resolved
pdns/pdns_recursor.cc Outdated Show resolved Hide resolved
pdns/pdns_recursor.cc Outdated Show resolved Hide resolved
pdns/sdig.cc Outdated Show resolved Hide resolved
Copy link
Member

@omoerbeek omoerbeek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • It should be documented how the proxy protocol and allow-from interact. AFAKS, if a request is proxied, the from address in the proxy header is used to check against allow-from.
  • I don't know if the recursor packer parsing is subject to being fuzzed, but it would be nice, especially with these additions.
  • A check for interoperability with another implementation would really be nice.

More comments inline.

@rgacogne
Copy link
Member Author

I have fixed most of the reported shortcomings.

It should be documented how the proxy protocol and allow-from interact. AFAKS, if a request is proxied, the from address in the proxy header is used to check against allow-from.

Done!

I don't know if the recursor packer parsing is subject to being fuzzed, but it would be nice, especially with these additions.

I'm planning on adding a fuzzing target for the proxy protocol parser itself, but if you are thinking of the TCP handling code it's a bit complicated because it's event-based, with a state machine.

A check for interoperability with another implementation would really be nice.

Agreed, I'll try to do that.

rgacogne and others added 21 commits March 17, 2020 14:12
Co-Authored-By: Otto Moerbeek <otto.moerbeek@open-xchange.com>
Co-Authored-By: Otto Moerbeek <otto.moerbeek@open-xchange.com>
@omoerbeek
Copy link
Member

I couldn't find any implementation to test incoming or outgoing support over UDP, Cloudflare's Spectrum is supposed to support it but it requires an enterprise plan.
So unless someone disagrees, I'll rebase this PR to fix the regression test issue and then merge it as it is.

Did you manage to do a TCP test? That is at least something...

@rgacogne
Copy link
Member Author

Did you manage to do a TCP test? That is at least something...

I did, see #8874 (comment)

@omoerbeek
Copy link
Member

Did you manage to do a TCP test? That is at least something...

I did, see #8874 (comment)

Great! I missed that comment earlier. LGTM!

@rgacogne rgacogne merged commit bbdaaa7 into PowerDNS:master Mar 17, 2020
@rgacogne rgacogne deleted the ddist-proxy-protocol branch March 17, 2020 15:55
@Habbie Habbie mentioned this pull request Apr 15, 2020
14 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants