-
-
Notifications
You must be signed in to change notification settings - Fork 53
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
Clarify libdns API regarding DNS records names being absolute or relative #12
Comments
Previously, this DNS provider incorrectly assumed that DNS records passed to it followed the standard notation, used by the DigitalOcean API, that absolute DNS record names end with a dot, and relative DNS record names don't. This is incorrect because libdns uses de-facto implicitly absolute DNS record names with a dot suffix, which causes any DNS record added with eg certmagic to incorrectly be treated as relative, resulting in records like: _acme-challenge.example.org.example.org This fixes this issue by converting between the standard dot-suffix DNS record name notation used by the DigitalOcean API and the implicitly absolute record names used by libdns. See: libdns/libdns#12
Thanks for bringing this up. I think I had noticed this somewhere along the way but lost track of it before I did anything about it because of everything else going on recently. I can see how we'll need to standardize this... I actually was thinking of (1) when I designed these interfaces. Yet, when I implemented the new DNS solver into CertMagic recently, I used the full domain name (sans trailing dot). So if I understand correctly, you propose we standardize on relative or absolute depending on the presence of the dot suffix:
Does that sound about right? That would mean that providers need to support both, right? I wonder if it would be simpler if we always used only one of those and then the implementation can simply always transform it if necessary for their provider's API. |
@mholt I think https://github.com/go-acme/lego/tree/master/providers/dns could help there. |
@crazy-max In what way? The limitations and difficulties with that code base are the reason why I designed libdns. |
If you are a defining a zone file for use with multiple domain names then you want the relative form and the absolute form. I don't know whether libdns exposes that functionality though, but even if it doesn't the hosting provider may. |
@ncw The libdns interfaces take a zone name as input as well as the list of records to manipulate within that zone. The actual implementation is up to whatever the DNS provider APIs allow/require. |
If you wanted to fully model what bind does then you would need an extra concept. In bind the zone isn't attached to any particular host name. You do that separately. This is where the difference between relative and absolute addresses are important. Relative addresses have the current host name tacked on, absolute ones don't. I designed Memset's DNS API to model this: https://www.memset.com/apidocs/methods_dns.html
However some DNS APIs don't model this extra complexity and just provide a zone with a single hostname and attached records. This works fine of course but makes it harder to just add another domain to the zone. I guess the libdns interface could be used with either the full or simplified DNS API, the mappings of which domain going to which zone being out of scope. So to answer the original question, I think you need to allow both relative and absolute names, and using a dot in the end to distinguish seems sensible as that is what bind does. For some providers you might need to make the names absolute before passing them to the API but some could deal with both relative and absolute names and do different things with them (eg Memset's API)
I think that would be a mistake for providers which can host multiple domains from a single zone file as it would remove flexibility. Apologies for the long winded answer and also apologies if I'm teaching grandma to suck eggs ;-) |
Thanks Nick -- we don't need to completely replicate bind's model for DNS records, but we do need something that works with most DNS provider APIs and gives people the flexibility to append, set, delete, and update DNS records. Ideally we wouldn't have to add more input parameters to the interface methods. Is it OK if we just keep the zone input and then document that the implementation needs to consider whether there is a trailing dot and handle accordingly for the DNS provider? And don't worry, grandma has nothing to do with this :) |
I think that sounds fine. I note that you didn't define what the zone id actually is anywhere. I imagine it would be a host name for some providers but might be a uuid for others?
😃 |
Host name. We need it to be the same to users, regardless of providers. So probably a domain name, not a provider-specific UUID. |
From the view of API design i would vote to use only one of those.
Disclaimer: I'm pretty new to all this DNS stuff, so please correct me if i'm wrong or missed something:
So if we don't loose any flexibility with it, i personally would prefer to support only relative names. |
Names relative in Chinese DNS providers (DNSPOD,Alibaba DNS,etc.) like a standard, if you want to get an acme challenge for domain
|
Thanks for the feedback so far! It looks like the consensus is to make the record name relative. We still need to know the zone, though, correct? Can we verify that providers will not lose flexibility with regards to wildcards, for example, if we use relative names? |
Something update of sub-domain's levels,the limits of sub-domain's is depend on your DNS Provider's subscription,because of I'm using the free subscription of DNSPOD so I have only 3 levels of sub-domain. But record Names relative in Chinese DNS providers like a standard is truth. For domains with wildcards, In the free subscription of Alibaba Cloud DNS and DNSPOD,I will have at least one levels of wildcards domain record to add(likes *.yx.viscrop.top). But some domains likes |
Been giving this some thought. Currently the libdns APIs accept a Based on what hasa been said thus far, I believe this API will continue to work, and we need only to clarify that record names are relative to the given zone. As to what @ncw said:
I think I agree; I want to keep libdns simple, and I don't currently realize any significant loss of functionality with the current APIs. Multiple zones can be manipulated with multiple function calls, and mapping more domains to a zone is not a use case that we've encountered so far with these libraries, so I presume nobody has needed that functionality. So then, to summarize: I propose we update the documentation to explicitly state that:
Did I get that right? Does that sound good? |
It looks like CertMagic, the primary caller/user of |
In preparing CertMagic for this adjustment, then, I ended up with this function, which I will add to the // RelativeName makes fqdn relative to zone. For example, it transforms
// "sub.example.com" to "sub" when the zone is "example.com". It tolerates
// trailing dots but does not require them; i.e. for the prior example,
// the respective input values of "sub.example.com." and "example.com."
// would be equivalent.
func RelativeName(fqdn, zone string) string {
cleanFQDN := strings.TrimSuffix(fqdn, ".")
cleanZone := strings.TrimSuffix(zone, ".")
relative := strings.TrimSuffix(cleanFQDN, cleanZone)
return strings.Trim(relative, ".")
} I am writing tests for it now and am not sure how to handle a couple of things.
FWIW, Cloudflare's DNS API seems to accept both relative and absolute record names, equivalently. In my testing, using |
There has been no feedback so I will assume that my implementation is correct. Unless there is new feedback soon, I will go ahead and push these changes probably this week or next, at which point changes may be required in existing DNS provider packages. I will do my best to help update them, but I'd feel better about this with more feedback first. |
Hey @mholt, sry for the late response.
DOMAIN NAMES - rfc1035 states the following: A free standing @ is used to denote the current origin.
Consider the following:
This would lead to
A zone is part of the domain namespace and is associated with a particular named domain - https://www.sciencedirect.com/topics/computer-science/domain-namespace
So this means no need for a |
@matthiasng Thanks for the feedback! A bit refreshing to not be working on this in a vacuum. :)
Yeah, something like that. So which is better to use, the "@" or the empty string? Obviously, individual DNS providers will need to adjust based on what their APIs expect either way. Help me understand this:
That is a bit of an add example, since you're passing a zone of In what case would a record for
The only problem with this is that I don't think we can know if it's an error. The function is idempotent if it's already a relative name, but there's no way to know if it's outside the zone.
Well, I don't know. Records we return from the provider need to be standardized too. Cloudflare happens to return FQDN (absolute) record names, but apparently accepts either FQDN or relative as input. For input, then, the Cloudflare provider wouldn't really need the |
Maybe i messed up my thoughts a bit. I think it is fine as it is (returning the input), because you are right, my example has just an input error.
The only way i can think of to handle the input error in this case is to distinguish FQDN and relative names by the trailing dots.
If libdns accepts FQDN's, the zone argument feels a bit redundant but i thinks that's fine. I also want to add another idea: Support only absolute names an remove the zone arguments. |
Why is that? I'm probably missing something obvious, but some APIs require you to specify the zone you're working with. How can you reasonably extract the zone implicitly from the FQDN (i.e. without extra DNS lookups, API requests, TLD lists, those kinds of things).
Ah, yeah, so in libdns case we expect the caller to get this information first. CertMagic -- which is libdns' primary importer right now -- does this DNS lookup similarly to lego. It is a pain for users to configure in extraordinary network environments, though, and doesn't always work otherwise. I figure not all applications will need, or can rely on, automatic DNS lookups, as sometimes they might simply be user input. I figured keeping libdns APIs more bare-bones was important. And this way, each DNS provider doesn't have to do the DNS lookup themselves. I'm open to moving the DNS lookup code into this repo as an exported function, but it'd be used by importers of libdns providers (like CertMagic), not the providers themselves. |
I was a bit fixated to DNS Challenges. You are right. Most, if not all, DNS API's requires the fqdn/relative name and the zone.
I did a quick search through lego's dns provider implementation and i can clearly say the following: I also like the idea of always returning a FQDN by now, because it sould be easier for further processing. If you decide to support both, as you write in your first comment, FQDN and relative names should definitely be distinguished by a trailing dot. |
i think there are two styles:
and for CNAME, some dns provider need the last point(.) . i.e. sub.example.com CNAME to www.example.com. it should be www.example.com. and some dns provider do not need the last point. |
From experience with Vultr, if you type I think we can support both, i.e., if you add a record Also, I don't know much about DNS but couldn't we use an asterisk to represent the root zone instead of an empty string or |
Thanks for the discussion. This has been very helpful. I've submitted #28 which I believe should resolve this ambiguity for the most part. There are still some edge cases left like what to do about trailing dots (can we assume that |
See the discussion at the libdns issue tracker [1]. The names used in libdns.Record should be relative, nto absolute. [1]: libdns/libdns#12
Hi,
It is unclear whether the DNS record names (
libdns.Record.Name
):example.org.
thensubdomain.example.org.
->subdomain.example.org
;subdomain
->subdomain.example.org
)subdomain.example.org
->subdomain.example.org
)I think 1) is better as it directly reflects what a DNS server actually returns, but it seems that currently the API contract is implicitly 2).
Examples:
.example.org
part to get a relative notation to pass that to Gandi (notice how it expects to receivesubdomain.example.org
without an ending dot suffix) which uses the standard dot-suffix notationexample.org
, should beexample.org.
if using the dot-suffix notation, but here's it's justexample.org
)1)
)I suggest to choose which syntax/semantics we want to use for DNS record names, document it clearly and update the various libdns providers as necessary. I think using the standard absolute/relative notation depending on a final dot is better as it better correponds to what a DNS server returns.
The text was updated successfully, but these errors were encountered: