Age | Commit message (Collapse) | Author |
|
supporting them
If we already degraded the feature level below DO don't bother with sending requests for DS, DNSKEY, RRSIG, NSEC, NSEC3
or NSEC3PARAM RRs. After all, we cannot do DNSSEC validation then anyway, and we better not press a legacy server like
this with such modern concepts.
This also has the benefit that when we try to validate a response we received using DNSSEC, and we detect a limited
server support level while doing so, all further auxiliary DNSSEC queries will fail right-away.
|
|
|
|
TCP or vice versa
Under the assumption that packet failures (i.e. FORMERR, SERVFAIL, NOTIMP) are caused by packet contents, not used
transport, we shouldn't switch between UDP and TCP when we get them, but only downgrade the higher levels down to UDP.
|
|
UDP ICMP errors are reported to us via recvmsg() when we read a reply. Handle this properly, and consider this a lost
packet, and retry the connection.
This also adds some additional logging for invalid incoming packets.
|
|
Previously, when we couldn't connect to a DNS server via TCP we'd abort the whole transaction using a
"connection-failure" state. This change removes that, and counts failed connections as "lost packet" events, so that
we switch back to the UDP protocol again.
|
|
If we failed to contact a DNS server via TCP, bump of the feature level to UDP again. This way we'll switch back
between UDP and TCP if we fail to contact a host.
Generally, we prefer UDP over TCP, which is why UDP is a higher feature level. But some servers only support UDP but
not TCP hence when reaching the lowest feature level of TCP and want to downgrade from there, pick UDP again. We this
keep downgrading until we reach TCP and then we cycle through UDP and TCP.
|
|
The code to retry transactions has been used over and over again, simplify it by replacing it by a new function.
|
|
|
|
|
|
This also introduces a new macro siphash24_compress_byte() which is useful to add a single byte into the hash stream,
and ports one user over to it.
|
|
response
This implements RFC 5155, Section 8.8 and RFC 4035, Section 5.3.4:
When we receive a response with an RRset generated from a wildcard we
need to look for one NSEC/NSEC3 RR that proves that there's no explicit RR
around before we accept the wildcard RRset as response.
This patch does a couple of things: the validation calls will now
identify wildcard signatures for us, and let us know the RRSIG used (so
that the RRSIG's signer field let's us know what the wildcard was that
generate the entry). Moreover, when iterating trough the RRsets of a
response we now employ three phases instead of just two.
a) in the first phase we only look for DNSKEYs RRs
b) in the second phase we only look for NSEC RRs
c) in the third phase we look for all kinds of RRs
Phase a) is necessary, since DNSKEYs "unlock" more signatures for us,
hence we shouldn't assume a key is missing until all DNSKEY RRs have
been processed.
Phase b) is necessary since NSECs need to be validated before we can
validate wildcard RRs due to the logic explained above.
Phase c) validates everything else. This phase also handles RRsets that
cannot be fully validated and removes them or lets the transaction fail.
|
|
There's now nsec3_hashed_domain_format() and nsec3_hashed_domain_make().
The former takes a hash value and formats it as domain, the latter takes
a domain name, hashes it and then invokes nsec3_hashed_domain_format().
This way we can reuse more code, as the formatting logic can be unified
between this call and another place.
|
|
|
|
validated keys list
When validating a transaction we initially collect DNSKEY, DS, SOA RRs
in the "validated_keys" list, that we need for the proofs. This includes
DNSKEY and DS data from our trust anchor database. Quite possibly we
learn that some of these DNSKEY/DS RRs have been revoked between the
time we request and collect those additional RRs and we begin the
validation step. In this case we need to make sure that the respective
DS/DNSKEY RRs are removed again from our list. This patch adds that, and
strips known revoked trust anchor RRs from the validated list before we
begin the actual validation proof, and each time we add more DNSKEY
material to it while we are doing the proof.
|
|
|
|
Instead of first iterating through all DNSKEYs in the DnsAnswer in
dns_transaction_check_revoked_trust_anchors(), and
then doing that a second time in dns_trust_anchor_check_revoked(), do so
only once in the former, and pass the dnskey we found directly to the
latter.
|
|
There's not reason to wait for checking for revoked trust anchors until
after validation, after all revoked DNSKEYs only need to be self-signed,
but not have a full trust chain.
This way, we can be sure that all trust anchor lookups we do during
validation already honour that some keys might have been revoked.
|
|
|
|
Invert an "if" check, so that we can use "continue" rather than another
code block indentation.
|
|
This increases compatibility with crappy Belkin routers.
|
|
The domain name for this NSEC3 RR was originally stored in a variable
called "suffix", which was then renamed to "zone" in
d1511b3338f431de3c95a50a9c1aca297e0c0734. Hence also rename the
RR variable accordingly.
|
|
|
|
resolved: query_process_cname - make fully recursive
|
|
This ensures we properly resolve the CNAME chain as far as we can, rather
than only CNAME chains of length one.
|
|
|
|
|
|
Now that we populate the trust database by default with a larger number
of entires, we better make sure to output a more readable version.
|
|
Let's increase compatibility with many private domains by default, and
ship a default NTA list of wel-known private domains, where it is
unlikely they will be deployed as official TLD anytime soon.
|
|
|
|
|
|
After all, when we don't support the algorithm we cannot determine
validity.
|
|
non-DNSSEC mode for them
This adds logic to detect cases like the Fritz!Box routers which serve
a private DNS domain "fritz.box" under the TLD "box" that does not
exist in the root servers. If this is detected DNSSEC validation is
turned off for this private domain, thus improving compatibility with
such private DNS zones.
This should be fairly secure as we first rely on the proof that .box
does not exist before this logic is applied. Nevertheless the logic is
only enabled for DNSSEC=allow-downgrade mode.
This logic does not work for routers that set up a full DNS zone directly
under a non-existing TLD, as in that case we cannot prove
that the domain is truly non-existing according to the root servers.
|
|
|
|
We followed the wrong connection. This only worked sometimes at all, because we
also return the wrong error code.
|
|
|
|
This adds a DNSSEC= setting to .network files, and makes resolved honour
them.
|
|
|
|
|
|
After discussing this with Tom, we figured out "allow-downgrade" sounds
nicer.
|
|
The option is already there, but wasn't exported in the configuration
file so far. Fix that.
|
|
|
|
networkd previously knew an enum "ResolveSupport" for configuring
per-interface LLMNR support, resolved had a similar enum just called
"Support", with the same value and similar pasers.
Unify this, call the enum ResolveSupport, and port both daemons to it.
|
|
In a couple of cases we maintain configuration settings that know an on
and off state, like a boolean, plus some additional states. We generally
parse them as booleans first, and if that fails check for specific
additional values.
This adds a generalized set of macros for parsing such settings, and
ports one use in resolved and another in networkd over to it.
|
|
for the root domain defined
We already skip this when the trust anchor files define a DS RR for the
root domain, now also skip it if there's a DNSKEY RR.
|
|
These files are not specific to resolved really, and this is then more
in-line with how /etc/sysctl.d and suchlike is handled.
|
|
When storing negative responses, clamp the SOA minimum TTL (as suggested
by RFC2308) to the TTL of the NSEC/NSEC3 RRs we used to prove
non-existance, if it there is any.
This is necessary since otherwise an attacker might put together a faked
negative response for one of our question including a high-ttl SOA RR
for any parent zone, and we'd use trust the TTL.
|
|
|
|
Since we honour RFC5011 revoked keys it might happen we end up with an
empty trust anchor, or one where there's no entry for the root left.
With this patch the logic is changed what to do in this case.
Before this patch we'd end up requesting the root DS, which returns with
NODATA but a signed NSEC we cannot verify, since the trust anchor is
empty after all. Thus we'd return a DNSSEC result of "missing-key", as
we lack a verified version of the key.
With this patch in place, look-ups for the root DS are explicitly
recognized, and not passed on to the DNS servers. Instead, if
downgrade-ok mode is on an unsigned NODATA response is synthesized, so
that the validator code continues under the assumption the root zone was
unsigned. If downgrade-ok mode is off a new transaction failure is
generated, that makes this case recognizable.
|
|
|
|
We already try hard not to create cyclic transaction dependencies, where
a transaction requires another one for DNSSEC validation purposes, which
in turn (possibly indirectly) pulls in the original transaction again,
thus resulting in a cyclic dependency and ultimately a deadlock since
each transaction waits for another one forever.
So far we wanted to avoid such cyclic dependencies by only going "up the
tree" when requesting auxiliary RRs and only going from one RR type to
another, but never back. However this turned out to be insufficient.
Consider a domain that publishes one or more DNSKEY but which has no DS
for it. A request for the domain's DNSKEY triggers a request for the
domain's DS, which will then fail, but return an NSEC, signed by the
DNSKEY. To validate that we'd request the DNSKEY again. Thus a DNSKEY
request results in a DS request which results in the original DNSKEY
request again. If the original lookup had been a DS lookup we'd end up
in the same cyclic dependency, hence we cannot statically break one of
them, since both requests are of course fully valid. Hence, do full
cyclic dependency checking: each time we are about to add a dependency
to a transaction, check if the transaction is already a dependency of
the dependency (recursively down the tree).
|