mirror of
https://github.com/hickory-dns/hickory-dns.git
synced 2026-04-25 11:15:54 +03:00
[GH-ISSUE #184] [Resolver] Allow CNAME returns on Resolver requests for Records #382
Labels
No labels
blocked
breaking-change
bug
bug:critical
bug:tests
cleanup
compliance
compliance
compliance
crate:all
crate:client
crate:native-tls
crate:proto
crate:recursor
crate:resolver
crate:resolver
crate:rustls
crate:server
crate:util
dependencies
docs
duplicate
easy
easy
enhance
enhance
enhance
feature:dns-over-https
feature:dns-over-quic
feature:dns-over-tls
feature:dnsssec
feature:global_lb
feature:mdns
feature:tsig
features:edns
has workaround
ops
perf
platform:WASM
platform:android
platform:fuchsia
platform:linux
platform:macos
platform:windows
pull-request
question
test
tools
tools
trust
unclear
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/hickory-dns#382
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @bluejekyll on GitHub (Sep 11, 2017).
Original GitHub issue: https://github.com/hickory-dns/hickory-dns/issues/184
From:
github.com/bluejekyll/trust-dns@b68318e2b9 (commitcomment-24233884)BTW, I ran into an issue where if I do a lookup for RecordType::A, I only get back A records. It'd be super handy to get back any intermediate CNAME records too. (I want both, and would like to be able to grab them in one query instead of making two every time.) I tried reading the code to see if it was filtering those by the RecordType I passed in but I have to admit I got lost in all the async code.
Are you on the #rust IRC channel by any chance? I'm NfNitLoop there. I don't want to bloat your commit with too much conversation. :p
@bluejekyll commented on GitHub (Sep 11, 2017):
@NfNitLoop, thanks for the feedback.
I'll start with this, the best form of feedback for me is not realtime. As I can't often spend long amounts of it in IRC or other comms channels. Though if you really want to chat directly there, I can join, we'd have to setup a shared time though.
Returning CNAMEs with the RData on A record lookups. We're getting close to the territory of crossing over from the responsibility of a resolver and the basic client. And I want to make sure the the Resolver remains easy to use, but the Client allows for anything. For reference this is the Client library: https://docs.rs/trust-dns/0.11.2/trust_dns/
That being said, maybe the Resolver should return CNAME RDatas. Can you describe your use case in a little more detail? Also, for reference, the filtering on RData type happens here in the generic lookup case:
https://github.com/bluejekyll/trust-dns/blob/master/resolver/src/lookup_state.rs#L207-L216
p.s. you might notice my comments about CNAME lookups at the top of that function.
@NfNitLoop commented on GitHub (Sep 11, 2017):
I'm doing a (so far: proof-of-concept) rewrite of a tool that does bulk DNS queries of our customers' domains to make sure they've got CNAME/A records set up properly, so I want it to be as efficient as possible. In the C code, or using
dig, making an A-record query will return both the A and CNAME records, so it's easy to see w/ one query whether a given domain was an A or CNAME.So, when I found the
Resolver::lookup(...)method I just assumed it worked like those tools. Especially since the LookupIter returns RData which can be both of those types.I'd expect "lookup" to give me back all the data that the DNS server sent back to me as a result of that lookup.
@NfNitLoop commented on GitHub (Sep 11, 2017):
But as you said, "as efficient as possible" may fall out of the scope of the higher-level resolver crate. If you'd decide that, it would be nice to:
@bluejekyll commented on GitHub (Sep 11, 2017):
Yes, that makes sense. I'm just trying to limit people's exposure to the inner workings of DNS as much as possible. There are many other records generally returned as well which I wouldn't want a general purpose resolver to return, though we could debate if it should in the generic lookup function... maybe it should return all records and not limit to just the ones requested. The issue with that is that RData isn't the entire record, it doesn't return the labels (name) associated with each records RData.
For example, a DNS request will often contain in the Authority section of the Message the Nameservers to use as authorities for the domain, and then in the Additionals section it might include actual name resolutions. It varies, and it's definitely not something that I think the Resolver should return.
CNames are special of course, and I still have to workout out how to properly validate those in the Resolver. But most upstream resolvers pass back CName resolution in the Answers section, so we're getting that for free in the request. I digress a bit here though.
For what you're doing, I think you're asking for raw zone information. Have you considered doing an AXFR and just checking all the records? The TRust-DNS Client should be able to do that. You'd have to be able to connect directly to the clients NS, and they would generally need to allow you to perform AXFR requests... Then you could validate the entire zone.
p.s. thanks for the recommendation on the docs. I will definitely add that there.
@NfNitLoop commented on GitHub (Sep 11, 2017):
That's a no-go. Our customers host their own DNS at a variety of providers. Even if they wanted to give us AXFR permission, managing requesting that for all of our customers would be a procedural nightmare. :p And they host many things in their DNS servers which aren't related to the sites whose DNS we care about. We're only iterating over a list of hostnames which customers have told us that they want served on our platform.
FWIW, because I'm only at the moment aiming for parity w/ the C tool I'm hoping to replace, I've disabled validation:
Hmm, I'm not versed enough in DNS to follow here. I see the RData::CNAME(Name), though?
@bluejekyll commented on GitHub (Sep 11, 2017):
I figured... worth a shot :)
That only applies to DNSSec, and you wouldn't want that, as I strip invalidly signed DNSSec response records. Though I've been considering changing that to always return, and allow the user to decide what to do with invalid records.
So a response is generally broken up into three sections, Answer (records that match the query), Authority/Nameservers (SOA records and/or Nameservers for the zone) and Additional (SIG0, EDNS, etc.).
For CNAME responses you basically get this in the Answers section (though sometimes Answer + Additional), assuming this was an A record lookup:
Taking this example, the
www.example.comin the firstCNAMErecord is the label/name of the record,CNAMEthe type, andhost1.example.comthe RData. What I was pointing out with my comment, and the reason this interface is problematic for your use case is that I don't return the entire Record, just the RData. So what this would mean is it would look like you're getting192.168.0.1as it's associated with a query forwww.example.comand anArecord type, but in fact it's associated with the namehost1.example.com.This might mean that the interface for this function should be more generalized so that this information is more obvious. But, I am still leaning toward pushing towards the client which allows for all of this data to be viewed. Does all of that make sense?
@NfNitLoop commented on GitHub (Sep 12, 2017):
Aha, yeah, that could pose an issue for CNAME chains too. ex:
That's fine by me, though. When I lookup an A record for a domain, I want to know what IP address to use to connect to it. (AND, in this case, the cname(s) which got me to that IP address.) Are servers required to order things in
cname1 -> cname2 -> Aorder when they respond? If so, the missing labels isn't that big of a deal, because I can reconstruct it by walking the RData records in order.Yeah, it's sounding more and more like I just need to learn the client API instead. Though, one of the things that I liked about the Resolver was the ability to specify a timeout Duration. (When querying millions of hosts, I'd rather skip the slow ones than wait around for them.)
@bluejekyll commented on GitHub (Sep 12, 2017):
Ah, yeah, timeouts :)
I do have timeouts on the Client, I'm just not exposing them directly in the SyncClient. If you were interested in putting a PR in for that, it should be easy to thread it through, here's the ClientFuture: https://docs.rs/trust-dns/0.11.2/trust_dns/client/struct.ClientFuture.html#method.with_timeout
The SycnClient (easier to use that the Tokio one) just creates a ClientFuture with the default timeout: https://github.com/bluejekyll/trust-dns/blob/master/client/src/client/client.rs#L371
That default is here: https://github.com/bluejekyll/trust-dns/blob/master/client/src/client/client_future.rs#L86 (5 seconds)
These docs show how to set all of this up the client: https://docs.rs/trust-dns/0.11.2/trust_dns/#setup-a-connection
There are various spots better documentation is needed, clearly.
@mssun commented on GitHub (May 18, 2018):
Hi, I'm facing the same issue when working on a
nslookuplike utility. Here is a result ofwww.facebook.comlookup.Also the ping tool will show the last cname (star-mini.c10r.facebook.com) when there is a cname chain and its IP address (31.13.95.36).
Resolvercannot handle this case. Do I need the low-levelclienthere?PS.
I don't know why the ping util doesn't show
PING www.facebook.com (31.13.95.36): 56 data bytesin the first line.@bluejekyll commented on GitHub (May 18, 2018):
Well, it handles CNAMEs, it just doesn't return the chain. At the moment this gets folded down into a single last item in the chain:
github.com/bluejekyll/trust-dns@a2db698afc/resolver/src/lookup_state.rs (L208-L234)We'd need to capture all of that, without dropping it, as it does now. I'm still not sure where I stand on this ATM, but I understand what is being asked for here. An example at least for the lookup would probably be similar to what was done for SrvLookup, which has an iterator over the SRV rdatas as well as any returned IP addresses: https://docs.rs/trust-dns-resolver/0.9.0/trust_dns_resolver/lookup/struct.SrvLookup.html
If we were to support this we'd want something similar, where we'd return an iterator over the CNAME rdatas that may have led to the final IP address set, of course that may be empty...
@balboah commented on GitHub (Feb 18, 2020):
I'm not sure if this is related for me but when I use trust dns as a forwarder for my mac desktop, the browsers (firefox & safari) say "could not resolve hostname" for all domains which use CNAME's, for example www.amazon.com. The difference in replies from trust-dns vs original dns is that missing CNAME record
@balboah commented on GitHub (Feb 18, 2020):
just realized this is a years old thread :) but this feature seems critical for operating a forwarder to support desktops
@bluejekyll commented on GitHub (Feb 18, 2020):
That’s a pretty big gap you’ve identified. I had considered how this negatively impacts the forwarding resolution.
I’m not sure when I’ll have time to look at this. We’ll have to consider how to fix this. It might be that the resolver is the wrong choice in this particular case.
@balboah commented on GitHub (Feb 19, 2020):
Could you try to describe what has to be done to someone who hasn't seen
.flatmap()before?Is there a reason down the stream of calls that the CNAME records are stripped out or was it mainly because you didn't consider it to be needed by the majority of the resolver use cases?
I understand this happens somewhere around
github.com/bluejekyll/trust-dns@a054d5e50a/crates/resolver/src/lookup_state.rs (L235)My use case is to have a local forwarder which can also do the DoT/DoH lookups on behalf of the old school clients. And to have that I believe I would need to use this resolver.
@bluejekyll commented on GitHub (Feb 19, 2020):
This section is fairly complex. And it has an outstanding issue with SRV target resolution. (There’s a separate issue open for that: #872).
Basically there is a first pass over the answers to see if there are an CNAMES or SRVs to resolve. If there are, it follows that chain through all the answer records. Once it hits the last see name, available, it then looks for A or AAAA records based on the request. That happens after this primary loop. If the A or AAAA isn’t available, it will issue a new request.
Right now we don’t capture the entire chain, it’s assumed only the final record is of interest. I think for the case you’ve identified, we’d need to capture all the answer and additional records into the result type. The reason I opted not to do this before is because they might be large.
Does that help answer your question? flatmap by the way is basically a combination of flatten and map. It simplifies some ownership issues by combine them. Flatten essentially exposes an inner iterator as part of the original iterator, so an iterator of iterator a is “flattened” into a single iterator.