Double newlines (i.e. one empty lines) are great to structure code. But
let's avoid triple newlines (i.e. two empty lines), quadruple newlines,
quintuple newlines, …, that's just spurious whitespace.
It's an easy way to drop 121 lines of code, and keeps the coding style
of our sources a bit tigther.
Files which are installed as-is (any .service and other unit files, .conf
files, .policy files, etc), are left as is. My assumption is that SPDX
identifiers are not yet that well known, so it's better to retain the
extended header to avoid any doubt.
I also kept any copyright lines. We can probably remove them, but it'd nice to
obtain explicit acks from all involved authors before doing that.
Currently, we accept SERVFAIL after downgrading fully, cache it and move
on. Let's extend this a bit: after downgrading fully, if the SERVFAIL
logic continues to be an issue, then use a different DNS server if there
are any.
Fixes: #7147
As discussed in RFC 6762, Section 8.2 a race condition may
happen when two hosts are probing for the same name simultaniously.
Detect and handle such race conditions.
According to RFC 6762 Section 8.2 "Simultaneous Probe Tiebreaking"
probing queries' Authority Section is populated with proposed
resource records in order to resolve possible race conditions.
This is our own header, we should include use the local-include syntax
("" not <>), to make it clear we are including the one from the build tree.
All other includes of files from src/systemd/ use this scheme.
For caching negative replies we need the SOA TTL information. Hence,
let's authenticate all auxiliary SOA RRs through DS requests on all
negative requests.
This is the most important piece of information of replies, hence show
this in the first log message about it.
(Wireshark shows it too in the short summary, hence this definitely
makes sense...)
Retrying a transaction via TCP is a good approach for mitigating
packet loss. However, it's not a good away way to fix a bad RCODE if we
already downgraded to UDP level for it. Hence, don't do this.
This is a small tweak only, but shortens the time we spend on
downgrading when a specific domain continously returns a bad rcode.
When we are doing a TCP transaction the kernel will automatically resend
all packets for us, there's no need to do that ourselves. Hence:
increase the timeout for TCP transactions substantially, to give the
kernel enough time to connect to the peer, without interrupting it when
we become impatient.
Embedding sd_id128_t's in constant strings was rather cumbersome. We had
SD_ID128_CONST_STR which returned a const char[], but it had two problems:
- it wasn't possible to statically concatanate this array with a normal string
- gcc wasn't really able to optimize this, and generated code to perform the
"conversion" at runtime.
Because of this, even our own code in coredumpctl wasn't using
SD_ID128_CONST_STR.
Add a new macro to generate a constant string: SD_ID128_MAKE_STR.
It is not as elegant as SD_ID128_CONST_STR, because it requires a repetition
of the numbers, but in practice it is more convenient to use, and allows gcc
to generate smarter code:
$ size .libs/systemd{,-logind,-journald}{.old,}
text data bss dec hex filename
1265204 149564 4808 1419576 15a938 .libs/systemd.old
1260268 149564 4808 1414640 1595f0 .libs/systemd
246805 13852 209 260866 3fb02 .libs/systemd-logind.old
240973 13852 209 255034 3e43a .libs/systemd-logind
146839 4984 34 151857 25131 .libs/systemd-journald.old
146391 4984 34 151409 24f71 .libs/systemd-journald
It is also much easier to check if a certain binary uses a certain MESSAGE_ID:
$ strings .libs/systemd.old|grep MESSAGE_ID
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
$ strings .libs/systemd|grep MESSAGE_ID
MESSAGE_ID=c7a787079b354eaaa9e77b371893cd27
MESSAGE_ID=b07a249cd024414a82dd00cd181378ff
MESSAGE_ID=641257651c1b4ec9a8624d7a40a9e1e7
MESSAGE_ID=de5b426a63be47a7b6ac3eaac82e2f6f
MESSAGE_ID=d34d037fff1847e6ae669a370e694725
MESSAGE_ID=7d4958e842da4a758f6c1cdc7b36dcc5
MESSAGE_ID=1dee0369c7fc4736b7099b38ecb46ee7
MESSAGE_ID=39f53479d3a045ac8e11786248231fbf
MESSAGE_ID=be02cf6855d2428ba40df7e9d022f03d
MESSAGE_ID=7b05ebc668384222baa8881179cfda54
MESSAGE_ID=9d1aaa27d60140bd96365438aad20286
We don't actually make use of the return value for now, but it matches
our coding style elsewhere, and it actually shortens our code quite a
bit.
Also, add a missing OOM check after dns_answer_new().
Otherwise we fail an assertion down the path since t->timeout_event_source is NULL
and it's the "other" transaction that's supposed to have the event source.
Signed-off-by: Dmitry Rozhkov <dmitry.rozhkov@linux.intel.com>
Currently resolving mDNS requests doesn't work because in
dns_transaction_process_reply() no answer gets installed into
mDNS transactions.
When receiving a mDNS reply we should not check for query section
equivalence of the request and its corresponsing response. But still
we need to install answers to mDNS transactions to make it possible
to actually resolve mDNS requests.
Signed-off-by: Dmitry Rozhkov <dmitry.rozhkov@linux.intel.com>
In some cases, caching DNS results locally is not desirable, a it makes DNS
cache poisoning attacks a tad easier and also allows users on the system to
determine whether or not a particular domain got visited by another user. Thus
provide a new "Cache" resolved.conf option to disable it.
Some upstream DNS servers return SERVFAIL if we ask them for DNSSEC RRs, which
some forwarding DNS servers pass on to us as SERVFAIL (other though as
NOERROR...). This is should not be considered a problem, as long as the domain
in question didn't have DNSSEC enabled. Hence: when making use of auxiliary
transactions accept those that return SERVFAIL.
There might be two reasons why we get a SERVFAIL response from our selected DNS
server: because this DNS server itself is bad, or because the DNS server
actually serving the zone upstream is bad. So far we immediately downgraded our
server feature level when getting SERVFAIL, under the assumption that the first
case is the only possible case. However, this meant we'd downgrade immediately
even if we encountered the second case described above.
With this commit handling of SERVFAIL is reworked. As soon as we get a SERVFAIL
on a transaction we retry the transaction with a lower feature level, without
changing the feature level tracked for the DNS server itself. If that fails
too, we downgrade further, and so on. If during this downgrading the SERVFAIL
goes away we assume that the DNS server we are talking to is bad, but the zone
is fine and propagate the detected feature level to the information we track
about the DNS server. Should the SERVFAIL not go away this way we let the
transaction fail and accept the SERVFAIL.
In order to improve compatibility with local clients that speak DNS directly
(and do not use NSS or our bus API) listen locally on 127.0.0.53:53 and process
any queries made that way.
Note that resolved does not implement a full DNS server on this port, but
simply enough to allow normal, local clients to resolve RRs through resolved.
Specifically it does not implement queries without the RD bit set (these are
requests where recursive lookups are explicitly disabled), and neither queries
with DNSSEC DO set in combination with DNSSEC CD (i.e. DNSSEC lookups with
validation turned off). It also refuses zone transfers and obsolete RR types.
All lookups done this way will be rejected with a clean error code, so that the
client side can repeat the query with a reduced feature set.
The code will set the DNSSEC AD flag however, depending on whether the data
resolved has been validated (or comes from a local, trusted source).
Lookups made via this mechanisms are propagated to LLMNR and mDNS as necessary,
but this is only partially useful as DNS packets cannot carry IP scope data
(i.e. the ifindex), and hence link-local addresses returned cannot be used
properly (and given that LLMNR/mDNS are mostly about link-local communication
this is quite a limitation). Also, given that DNS tends to use IDNA for
non-ASCII names, while LLMNR/mDNS uses UTF-8 lookups cannot be mapped 1:1.
In general this should improve compatibility with clients bypassing NSS but
it is highly recommended for clients to instead use NSS or our native bus API.
This patch also beefs up the DnsStream logic, as it reuses the code for local
TCP listening. DnsStream now provides proper reference counting for its
objects.
In order to avoid feedback loops resolved will no silently ignore 127.0.0.53
specified as DNS server when reading configuration.
resolved listens on 127.0.0.53:53 instead of 127.0.0.1:53 in order to leave
the latter free for local, external DNS servers or forwarders.
This also changes the "etc.conf" tmpfiles snippet to create a symlink from
/etc/resolv.conf to /usr/lib/systemd/resolv.conf by default, thus making this
stub the default mode of operation if /etc is not populated.
When we return the full RR wire data, let's make sure the TTL included in it is
adjusted by the time the RR sat in the cache.
As an optimization we do this only for ResolveRecord() and not for
ResolveHostname() and friends, since adjusting the TTL means copying the RR
object, and we don#t want to do that if there's no reason to.
(ResolveHostname() and friends don't return the TTL hence there's no reason to
in that case)
dns_transaction_maybe_restart() is supposed to return 1 if the the transaction
has been restarted and 0 otherwise. dns_transaction_process_dnssec() relies on
this behaviour. Before this change in case of restart we'd call
dns_transaction_go() when restarting the lookup, returning its return value
unmodified. This is wrong however, as that function returns 1 if the
transaction is pending, and 0 if it completed immediately, which is a very
different set of return values. Fix this, by always returning 1 on redirection.
The wrong return value resulted in all kinds of bad memory accesses as we might
continue processing a transaction that was redirected and completed immediately
(and thus freed).
This patch also adds comments to the two functions to clarify the return values
for the future.
Most likely fixes: #2942#3475#3484
incapdns.net returns NXDOMAIN for the SOA of the zone itself but is not a
terminal. This is against the specs, but we really should be able to deal with
this.
Previously, when verifying whether an NXDOMAIN response for a SOA/NS lookup is
rightfully unsigned we'd issue a SOA lookup for the parent's domain, to derive
the state from that. If the parent SOA would get an NXDOMAIN, we'd continue
upwards, until we hit a signed top-level domain, which suggests that the domain
actually exists.
With this change whenver we need to authenticate an NXDOMAIN SOA reply, we'll
request the DS RR for the zone first, and use for validation, since that this
must be from the parent's zone, not the incorrect lower zone.
Fixes: #2894
Throughout the tree there's spurious use of spaces separating ++ and --
operators from their respective operands. Make ++ and -- operator
consistent with the majority of existing uses; discard the spaces.
When a transaction is complete, and we notify its owners, make sure we deal
correctly with the requesters removing themselves from the list of owners while
we continue iterating.
This was previously already dealt with with transactions that require other
transactions for DNSSEC purposes, fix this for other possibly transaction
owners too now.
Since iterating through "Set" objects is not safe regarding removal of entries
from it, rework the logic to use two Sets, and move each entry we notified from
one set to the other set before we dispatch the notification. This move operation
requires no additional memory, and enables us to ensure that we don't notify
any object twice.
Fixes: #2676
When the buffer is allocated on the stack we do not have to check for
failure everywhere. This is especially useful in debug statements, because
we can put dns_resource_key_to_string() call in the debug statement, and
we do not need a seperate if (log_level >= LOG_DEBUG) for the conversion.
dns_resource_key_to_string() is changed not to provide any whitespace
padding. Most callers were stripping the whitespace with strstrip(),
and it did not look to well anyway. systemd-resolve output is not column
aligned anymore.
The result of the conversion is not stored in DnsTransaction object
anymore. It is used only for debugging, so it seems fine to generate it
when needed.
Various debug statements are extended to provide more information.
Previously, if a hostanem is resolved with AF_UNSPEC specified, this would be used as indication to resolve both an
AF_INET and an AF_INET6 address. With this change this logic is altered: an AF_INET address is only resolved if there's
actually a routable IPv4 address on the specific interface, and similar an AF_INET6 address is only resolved if there's
a routable IPv6 address. With this in place, it's ensured that the returned data is actually connectable by
applications. This logic mimics glibc's resolver behaviour.
Note that if the client asks explicitly for AF_INET or AF_INET6 it will get what it asked for.
This also simplifies the logic how it is determined whether a specific lookup shall take place on a scope.
Specifically, the checks with dns_scope_good_key() are now moved out of the transaction code and into the query code,
so that we don't even create a transaction object on a specific scope if we cannot execute the resolution on it anyway.
If we encounter NXDOMAIN, but find at least one matching RR in a response, then patch it to become SUCCESS. This should
clean up handling of CNAME/DNAMEs, and makes sure broken servers and those conforming to RFC 6604 are treated the same
way. The new behaviour opposes the logic suggested in RFC 6604, but given that some servers don't implement it
correctly, and given that in some ways the CNAME/DNAME chains will be incomplete anyway, and given that DNSSEC
generally only allows us to prove the first element of a CNAME/DNAME chain, this should simplify things for us.
So far, abritrary NSEC and NSEC3 RRs were implicitly consider "primary" for any transaction, meaning we'd abort the
transaction immediately if we couldn't validate it. With this patch this logic is removed, and the NSEC/NSEC3 RRs will
not be considered primary anymore. This has the effect that they will be dropped from the message if they don't
validate, but processing continues. This is safe to do, as they are required anyway to validate positive wildcard and
negative responses, and if they are missing then, then message will be considered unsigned, which hence means the
outcome is effectively the same.
This is benefical in case the server sends us NSEC/NSEC3 RRs that are not directly related to the lookup we did, but
simply auxiliary information. Previously, if we couldn't authenticate those RRs we'd fail the entire lookup while with
this change we'll simply drop the auxiliary information and proceed without it.
Whenever we encounter an OS error we did not expect, we so far put the transaction into DNS_TRANSACTION_RESOURCES
state. Rename this state to DNS_TRANSACTION_ERRNO, and save + propagate the actual system error to the caller. This
should make error messages triggered by system errors much more readable by the user.
If we downgrade from DNSSEC to non-DNSSEC mode, let's log about this in a recognizable way (i.e. with a message ID),
after all, this is of major importance.
The LLMNR spec suggests to do do reverse address lookups by doing direct LLMNR/TCP connections to the indicated
address, instead of doing any LLMNR multicast queries. When we do this and the peer doesn't actually implement LLMNR
this will result in a TCP connection error, which we need to handle. In contrast to most LLMNR lookups this will give
us a quick response on whether we can find a suitable name. Report this as new transaction state, since this should
mostly be treated like an NXDOMAIN rcode, except that it's not one.
We already maintain statistics about positive DNSSEC proofs, and count them up by 1 for each validated RRset. Now,
update the same counters each time we validated a negative query, so that the statistics are the combined result of all
validation checks, both positive and negative.
When we restart a transaction because of an incompatible server, pick a new transaction ID.
This should increase compatibility with DNS servers that don't like if they get different requests with the same
transaction ID.
given that DNSSEC lookups may result in quite a number of auxiliary transactions, let's better be safe than sorry and
also enforce a limit on the number of total transactions, not just on the number of queries.
Previously, when getting notified about a completed auxiliary DNSSEC transaction we'd immediately act on it, and
possibly abort the main transaction. This is problematic, as DNS transactions that already completed at the time we
started using them will never get the notification event, and hence never be acted on in the same way.
Hence, introduce a new call dns_transaction_dnssec_ready() that checks the state of auxiliary DNSSEC transactions, and
returns 1 when we are ready for the actual DNSSEC validation step. Then, make sure this is invoked when the auxiliary
transactions are first acquired (and thus possibly reused) as well when the notifications explained above take place.
This fixes problems particularly when doing combined A and AAAA lookups where the auxiliary DNSSEC transactions get
reused between them, and where we got confused if we reused an auxiliary DNSSEC transaction from one when it already
got completed from the other.
If we have a signed DNAME RR response, there's no need to insist on a signature for a CNAME RR response, after all it
is unlikely to be signed, given the implicit synthethis of CNAME through DNAME RRs.
In some cases we learn something about a server's feature level through its responses. If we notice that after doing
basic checking of a response, and after collecting all auxiliary DNSSEC info the feature level of the server is lower
than where we started, restart the whole transaction.
This is useful to deal with servers that response rubbish when talked to with too high feature levels.
Let's make sure we first check if the OPT was lost in the reply, before we accept a reply as successful and use it for
verifying the current feature level.
When we restart a DNS transaction, remove all connections to any auxiliary DNSSEC transactions, after all we might
acquire completely different data this time, requiring different auxiliary DNSSEC transactions.
This adds logic to downgrade the feature level more aggressively when we have reason to. Specifically:
- When we get a response packet that lacks an OPT RR for a query that had it. If so, downgrade immediately to UDP mode,
i.e. don't generate EDNS0 packets anymore.
- When we get a response which we are sure should be signed, but lacks RRSIG RRs, we downgrade to EDNS0 mode, i.e.
below DO mode, since DO is apparently not really supported.
This should increase compatibility with servers that generate non-sensical responses if they messages with OPT RRs and
suchlike, for example the situation described here:
https://open.nlnetlabs.nl/pipermail/dnssec-trigger/2014-November/000376.html
This also changes the downgrade code to explain in a debug log message why a specific downgrade happened.
Having this information available is useful when we need to check whether various RRs are suitable for proofs. This
information is stored in the RRs as number of labels to skip from the beginning of the owner name to reach the
synthesizing source/signer. Simple accessor calls are then added to retrieve the signer/source from the RR using this
information.
This also moves validation of a a number of RRSIG parameters into a new call dnssec_rrsig_prepare() that as side-effect
initializes the two numeric values.
Given how fragile DNS servers are with some DNS types, and given that we really should avoid confusing them with
known-weird lookups, refuse doing lookups for known-obsolete RR types.
Move detection into a set of new functions, that check whether one specific server can do DNSSEC, whether a server and
a specific transaction can do DNSSEC, or whether a transaction and all its auxiliary transactions could do so.
Also, do these checks both before we acquire additional RRs for the validation (so that we can skip them if the server
doesn't do DNSSEC anyway), and after we acquired them all (to see if any of the lookups changed our opinion about the
servers).
THis also tightens the checks a bit: a server that lacks TCP support is considered incompatible with DNSSEC too.
This changes the DnsServer logic to count failed UDP and TCP failures separately. This is useful so that we don't end
up downgrading the feature level from one UDP level to a lower UDP level just because a TCP connection we did because
of a TC response failed.
This also adds accounting of truncated packets. If we detect incoming truncated packets, and count too many failed TCP
connections (which is the normal fall back if we get a trucnated UDP packet) we downgrade the feature level, given that
the responses at the current levels don't get through, and we somehow need to make sure they become smaller, which they
will do if we don't request DNSSEC or EDNS support.
This makes resolved work much better with crappy DNS servers that do not implement TCP and only limited UDP packet
sizes, but otherwise support DNSSEC RRs. They end up choking on the generally larger DNSSEC RRs and there's no way to
retrieve the full data.
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.
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.
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.
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.
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.
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).
If any of the transactions started by
dns_transaction_request_dnssec_keys() finishes promptly without
requiring asynchronous operation this is reported back to the issuing
transaction from the same stackframe. This might ultimately result in
this transaction to be freed while we are still in its
_request_dnssec_keys() stack frame. To avoid memory corruption block the
transaction GC while in the call, and manually issue a GC after it
returned.
With this patch resolved will properly handle revoked keys, but not
augment the locally configured trust anchor database with newly learned
keys.
Specifically, resolved now refuses validating RRsets with
revoked keys, and it will remove revoked keys from the configured trust
anchors (only until reboot).
This patch does not add logic for adding new keys to the set of trust
anchors. This is a deliberate decision as this only can work with
persistent disk storage, and would result in a different update logic
for stateful and stateless systems. Since we have to support stateless
systems anyway, and don't want to encourage two independent upgrade
paths we focus on upgrading the trust anchor database via the usual OS
upgrade logic.
Whenever a trust anchor entry is found revoked and removed from the
trust anchor a recognizable log message is written, encouraging the user
to update the trust anchor or update his operating system.
This adds negative trust anchor support and allows reading trust anchor
data from disk, from files
/etc/systemd/dnssec-trust-anchors.d/*.positive and
/etc/systemd/dnssec-trust-anchros.d/*.negative, as well as the matching
counterparts in /usr/lib and /run.
The positive trust anchor files are more or less compatible to normal
DNS zone files containing DNSKEY and DS RRs. The negative trust anchor
files contain only new-line separated hostnames for which to require no
signing.
By default no trust anchor files are installed, in which case the
compiled-in root domain DS RR is used, as before. As soon as at least
one positive root anchor for the root is defined via trust anchor files
this buil-in DS RR is not added though.