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

Replace dns "resolver" calls with "dns.Exchange" func #339

Merged
merged 6 commits into from
Sep 18, 2024

Conversation

evidolob
Copy link
Contributor

This PR is trying to simplify DNS server implementation, by replacing parsing query message and pass it to different resolver.* function calls with single dns.Exchange() function.

The downside of this, is getting DNS configuration on Windows is quite difficult, as it is required syscall.

Copy link
Contributor

@cfergeau cfergeau left a comment

Choose a reason for hiding this comment

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

Haven't looked yet at the 3rd commit, the amount of code needed for Windows is a bit scary :-/
Very happy to see all this code gone in the 2nd commit though ^^

pkg/services/dns/dns.go Show resolved Hide resolved
pkg/services/dns/dns.go Outdated Show resolved Hide resolved
pkg/services/dns/dns.go Outdated Show resolved Hide resolved
resolver := net.Resolver{
PreferGo: false,
// need to create new message struct, as reusing original message struct leading
// to request errors
Copy link
Contributor

Choose a reason for hiding this comment

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

I was quite confused by this for a long while, imo this is a good opportunity to rework handle and addAnswers .
The reason the copy is needed is because r is a "reply" message, sending it as a "query" message with Exchange won't work as expected. The copy you do will clear the m.Response boolean which is set to true.

Looking at handle, we have:

func (h *dnsHandler) handle(w dns.ResponseWriter, r *dns.Msg, responseMessageSize int) {
	m := new(dns.Msg)
	m.SetReply(r)
	m.RecursionAvailable = true
	h.addAnswers(m)

It gets a "query" message in the r parameter, it creates a "reply" message as m, and passes it to addAnswers so that m.Answers gets filled, and then the m "reply" is sent to back.

However, addAnswers does not limit itself to filling the Answers of the "reply" message. It used to reuse the Query field from that message to generate some go DNS lookups, and now with your changes, we need a full dns.Msg instance to forward to the system DNS server as a "query". So we have a "reply" message which we try to turn into a "query" message, which you did through this struct copying.

In my opinion, it would be cleaner to forward the initial request in Exchange, ie the r argument to the handle method, and to keep m strictly as a "reply" message.
I'd also argue that a lot of the confusion comes from the one-letter variables, r, m, ... :-/

I've done some work towards this in https://github.com/cfergeau/gvisor-tap-vsock/tree/replace-dns
This includes a new test which is useful to test this code.
If you agree with the approach, feel free to take this code over and rework it in the way you like, the code in my branch is not final, just a way for me to check this can work :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have add your code in this PR

pkg/services/dns/dns.go Outdated Show resolved Hide resolved
pkg/services/dns/dns.go Outdated Show resolved Hide resolved
pkg/services/dns/dns.go Outdated Show resolved Hide resolved
pkg/services/dns/dns.go Outdated Show resolved Hide resolved
pkg/services/dns/dns.go Outdated Show resolved Hide resolved
pkg/services/dns/dns.go Outdated Show resolved Hide resolved
pkg/services/dns/dns.go Outdated Show resolved Hide resolved
pkg/services/dns/dns_config_windows.go Outdated Show resolved Hide resolved
@evidolob evidolob force-pushed the replace-dns branch 2 times, most recently from 5579f34 to bcea6b1 Compare August 5, 2024 08:16
@evidolob evidolob requested a review from cfergeau August 5, 2024 08:16
@evidolob evidolob force-pushed the replace-dns branch 2 times, most recently from b7bf0a7 to f2ae1d9 Compare August 5, 2024 12:00
@cfergeau
Copy link
Contributor

(note for myself) I was wondering about the 'no ipv6/AAAA support' mention in the commit log, it's a preexisting issue, support for AAAA requests is only in the ipv6 PR 964d113

)

func GetDNSHostAndPort() (string, string, error) {
conf, err := dns.ClientConfigFromFile("/etc/resolv.conf")
Copy link
Member

Choose a reason for hiding this comment

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

It might be better to in future specify the location of this file as systems are moving away from using this; eg. systemd-resolvd

Copy link
Contributor

Choose a reason for hiding this comment

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

For now, systemd-resolved provides a stub resolv.conf with a DNS resolver listening on 127.0.0.53


var nameserver netip.AddrPort
for _, n := range nameservers {
// return first non ipv6 nameserver
Copy link
Member

Choose a reason for hiding this comment

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

same 'issue' (limitation) here? only a single nameserver is handled

Copy link
Member

@gbraad gbraad left a comment

Choose a reason for hiding this comment

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

Overall looks OK, especially as testcases are added.
However, there are limitations in how multiple nameservers are handled; this needs to be a follow-up.

evidolob and others added 4 commits August 28, 2024 14:41
… has multiple records

Signed-off-by: Yevhen Vydolob <yvydolob@redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
This adds a new test which sets up a DNS server using gvisor-tap-vsock
code listening on localhost tcp and udp, and then compare its answers
with the one from the default go resolver.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
This is the beginning of a refactor of addAnswers to make it easier to
understand.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
It would be used to get DNS configuration on windows, as it requires to deals with syscall to windows kernel

Signed-off-by: Yevhen Vydolob <yvydolob@redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
@cfergeau
Copy link
Contributor

I did a few changes in https://github.com/cfergeau/gvisor-tap-vsock/commits/replace-dns/ , but overall it looks good to me!
There is a possibly significant change with this approach though. Before, if I had 1.2.3.4 some.host.example.com in /etc/hosts on my host machine, then the guest would resolve some.host.example.com to 1.2.3.4.
After these changes, /etc/hosts will no longer be considered. I tested this on macOS.
I don't know if it's going to be problematic or not :-/

Changes I did:

  • rebased on top of main
  • merged readAndCreateClient in newDNSHandler as it imo made things more complicated rather than easier to read
  • made getDNSHostAndPort private
  • split the test case addition and the addLocalAnswers addition as this simplifies the 'main' commit (the one adding h.dnsClient.Exchange())
  • fixed the FIXME in handleTCP/handleUDP

@cfergeau
Copy link
Contributor

cfergeau commented Aug 29, 2024

Before, if I had 1.2.3.4 some.host.example.com in /etc/hosts on my host machine, then the guest would resolve some.host.example.com to 1.2.3.4.
After these changes, /etc/hosts will no longer be considered. I tested this on macOS.
I don't know if it's going to be problematic or not :-/

CRC relies on the crc.testing and apps-crc.testing entries in the host /etc/hosts file, so I think this is going to cause a problem :-/ Any idea how/if we could address this?

@evidolob
Copy link
Contributor Author

@cfergeau @gbraad I add 'hosts' file records handling in evidolob#2
Pls, give a look on it

@cfergeau
Copy link
Contributor

@cfergeau @gbraad I add 'hosts' file records handling in evidolob#2 Pls, give a look on it

Looks like a good way forward! Let's merge this PR which has waited for far too long, and then we'll add /etc/hosts support as a follow-up.

evidolob and others added 2 commits September 18, 2024 10:32
This highly simplify resolving DNS code.
Also, DNS will work only for IPv4
Signed-off-by: Yevhen Vydolob <yvydolob@redhat.com>
Co-authored-by: Christophe Fergeau <cfergeau@redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
At the moment, the forwarded DNS requests all go over TCP. This commit
uses 2 different dns clients so that we can forward UDP requests over
UDP instead of TCP.
This removes FIXMEs in the code.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
@cfergeau
Copy link
Contributor

/lgtm

@openshift-ci openshift-ci bot added the lgtm label Sep 18, 2024
@cfergeau
Copy link
Contributor

/approve
/hold
(waiting for the tests to run)

Copy link
Contributor

openshift-ci bot commented Sep 18, 2024

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: cfergeau, evidolob

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@cfergeau
Copy link
Contributor

win-sshproxy-tests failing is unfortunately expected :-/
/unhold

@openshift-merge-bot openshift-merge-bot bot merged commit 3c875de into containers:main Sep 18, 2024
20 of 21 checks passed
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.

3 participants