Commit graph

38 commits

Author SHA1 Message Date
Lennart Poettering 274b874830 resolved: rename DnsTransaction's current_features field to current_feature_level
This is a follow-up for f4461e5641.
2016-01-11 19:40:00 +01:00
Lennart Poettering 91adc4db33 resolved: don't attempt to send queries for DNSSEC RR types to servers not 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.
2016-01-11 19:40:00 +01:00
Lennart Poettering a1a3f73a57 resolved: when we get a TCP connection failure, try again
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.
2016-01-11 19:39:59 +01:00
Lennart Poettering d3760be01b resolved: when caching negative responses, honour NSEC/NSEC3 TTLs
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.
2016-01-05 01:35:28 +01:00
Lennart Poettering b2b796b8ab resolved: explicitly handle case when the trust anchor is empty
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.
2016-01-04 22:42:10 +01:00
Lennart Poettering 51e399bceb resolved: block transaction GC'ing while dns_transaction_request_dnssec_keys() is running
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.
2016-01-04 22:42:10 +01:00
Lennart Poettering f32f0e57ca resolved: add dns_transaction_close_connection()
This new call unifies how we shut down all connection resources, such as
UDP sockets, event sources, and TCP stream objects.

This patch just adds the basic hook-up, this function will be used more
in later commits.
2015-12-27 01:41:39 +01:00
Lennart Poettering cbe4216dd1 resolved: remember explicitly whether we already tried a stream connection
On LLMNR we never want to retry stream connections (since local TCP
connections should work, and we don't want to unnecessarily delay
operation), explicitly remember whether we already tried one, instead of
deriving this from a still stored stream object. This way, we can free
the stream early, without forgetting that we tried it.
2015-12-27 01:41:39 +01:00
Lennart Poettering ac720200b7 resolved: generate an explicit transaction error when we cannot reach server via TCP
Previously, if we couldn't reach a server via UDP we'd generate an
MAX_ATTEMPTS transaction result, but if we couldn't reach it via TCP
we'd generate a RESOURCES transaction result. While it is OK to generate
two different errors I think, "RESOURCES" is certainly a misnomer.
Introduce a new transaction result "CONNECTION_FAILURE" instead.
2015-12-26 19:09:10 +01:00
Lennart Poettering 019036a47f resolved: propagate the DNSSEC result from the transaction to the query and the the bus client
It's useful to generate useful errors, so let's do that.
2015-12-18 20:09:30 +01:00
Lennart Poettering 3bbdc31df3 resolved: rename DNS_TRANSACTION_FAILURE → DNS_TRANSACTION_RCODE_FAILURE
We have many types of failure for a transaction, and
DNS_TRANSACTION_FAILURE was just one specific one of them, if the server
responded with a non-zero RCODE. Hence let's rename this, to indicate
which kind of failure this actually refers to.
2015-12-18 19:49:25 +01:00
Lennart Poettering 105e151299 resolved: add support NSEC3 proofs, as well as proofs for domains that are OK to be unsigned
This large patch adds a couple of mechanisms to ensure we get NSEC3 and
proof-of-unsigned support into place. Specifically:

- Each item in an DnsAnswer gets two bit flags now:
  DNS_ANSWER_AUTHENTICATED and DNS_ANSWER_CACHEABLE. The former is
  necessary since DNS responses might contain signed as well as unsigned
  RRsets in one, and we need to remember which ones are signed and which
  ones aren't. The latter is necessary, since not we need to keep track
  which RRsets may be cached and which ones may not be, even while
  manipulating DnsAnswer objects.

- The .n_answer_cachable of DnsTransaction is dropped now (it used to
  store how many of the first DnsAnswer entries are cachable), and
  replaced by the DNS_ANSWER_CACHABLE flag instead.

- NSEC3 proofs are implemented now (lacking support for the wildcard
  part, to be added in a later commit).

- Support for the "AD" bit has been dropped. It's unsafe, and now that
  we have end-to-end authentication we don't need it anymore.

- An auxiliary DnsTransaction of a DnsTransactions is now kept around as
  least as long as the latter stays around. We no longer remove the
  auxiliary DnsTransaction as soon as it completed. THis is necessary,
  as we now are interested not only in the RRsets it acquired but also
  in its authentication status.
2015-12-18 14:48:50 +01:00
Lennart Poettering a0c888c78c resolved: merge two bools into a bitfield 2015-12-18 14:48:49 +01:00
Lennart Poettering a5784c4985 resolved: cache stringified transaction key once per transaction
We end up needing the stringified transaction key in many log messages,
hence let's simplify the logic and cache it inside of the transaction:
generate it the first time we need it, and reuse it afterwards. Free it
when the transaction goes away.

This also updated a couple of log messages to make use of this.
2015-12-18 14:48:49 +01:00
Lennart Poettering 79e2493138 resolved: rework how and when the number of answer RRs to cache is determined
Instead of figuring out how many RRs to cache right before we do so,
determine this at the time we install the answer RRs, so that we can
still alter this as we manipulate the answer during validation.

The primary purpose of this is to pave the way so that we can drop
unsigned RRsets from the answer and invalidate the number of RRs to
cache at the same time.
2015-12-11 14:14:27 +01:00
Lennart Poettering 547973dea7 resolved: chase DNSKEY/DS RRs when doing look-ups with DNSSEC enabled
This adds initial support for validating RRSIG/DNSKEY/DS chains when
doing lookups. Proof-of-non-existance, or proof-of-unsigned-zones is not
implemented yet.

With this change DnsTransaction objects will generate additional
DnsTransaction objects when looking for DNSKEY or DS RRs to validate an
RRSIG on a response. DnsTransaction objects are thus created for three
reasons now:

1) Because a user asked for something to be resolved, i.e. requested by
   a DnsQuery/DnsQueryCandidate object.
2) As result of LLMNR RR probing, requested by a DnsZoneItem.
3) Because another DnsTransaction requires the requested RRs for
   validation of its own response.

DnsTransactions are shared between all these users, and are GC
automatically as soon as all of these users don't need a specific
transaction anymore.

To unify the handling of these three reasons for existance for a
DnsTransaction, a new common naming is introduced: each DnsTransaction
now tracks its "owners" via a Set* object named "notify_xyz", containing
all owners to notify on completion.

A new DnsTransaction state is introduced called "VALIDATING" that is
entered after a response has been receieved which needs to be validated,
as long as we are still waiting for the DNSKEY/DS RRs from other
DnsTransactions.

This patch will request the DNSKEY/DS RRs bottom-up, and then validate
them top-down.

Caching of RRs is now only done after verification, so that the cache is
not poisoned with known invalid data.

The "DnsAnswer" object gained a substantial number of new calls, since
we need to add/remove RRs to it dynamically now.
2015-12-10 11:35:52 +01:00
Daniel Mack a9da14e1e9 resolved: add 'next_attempt_after' field to DnsTransaction
For each transaction, record when the earliest point in time when the
query packet may hit the wire. This is the same time stamp for which
the timer is scheduled in retries, except for the initial query packets
which are delayed by a random jitter. In this case, we denote that the
packet may actually be sent at the nominal time, without the jitter.

Transactions that share the same timestamp will also have identical
values in this field. It is used to coalesce pending queries in a later
patch.
2015-12-08 16:51:41 +01:00
Daniel Mack ef7ce6df4d resolved: short-cut jitter callbacks for LLMNR and mDNS
When a jitter callback is issued instead of sending a DNS packet directly,
on_transaction_timeout() is invoked to 'retry' the transaction. However,
this function has side effects. For once, it increases the packet loss
counter on the scope, and it also unrefs/refs the server instances.

Fix this by tracking the jitter with two bool variables. One saying that
the initial jitter has been scheduled in the first place, and one that
tells us the delay packet has been sent.
2015-12-08 16:51:40 +01:00
Daniel Mack ea12bcc789 resolved: add mDNS initial jitter
The logic is to kick off mDNS packets in a delayed way is mostly identical
to what LLMNR needs, except that the constants are different.
2015-12-08 16:41:45 +01:00
Lennart Poettering 931851e8e4 resolved: add a concept of "authenticated" responses
This adds a new SD_RESOLVED_AUTHENTICATED flag for responses we return
on the bus. When set, then the data has been authenticated. For now this
mostly reflects the DNSSEC AD bit, if DNSSEC=trust is set. As soon as
the client-side validation is complete it will be hooked up to this flag
too.

We also set this bit whenver we generated the data ourselves, for
example, because it originates in our local LLMNR zone, or from the
built-in trust anchor database.

The "systemd-resolve-host" tool has been updated to show the flag state
for the data it shows.
2015-12-03 21:17:49 +01:00
Lennart Poettering 0d2cd47617 resolved: add a simple trust anchor database as additional RR source
When doing DNSSEC lookups we need to know one or more DS or DNSKEY RRs
as trust anchors to validate lookups. With this change we add a
compiled-in trust anchor database, serving the root DS key as of today,
retrieved from:

https://data.iana.org/root-anchors/root-anchors.xml

The interface is kept generic, so that additional DS or DNSKEY RRs may
be served via the same interface, for example by provisioning them
locally in external files to support "islands" of security.

The trust anchor database becomes the fourth source of RRs we maintain,
besides, the network, the local cache, and the local zone.
2015-12-03 21:17:49 +01:00
Tom Gundersen be808ea083 resolved: fallback to TCP if UDP fails
This is inspired by the logic in BIND [0], follow-up patches
will implement the reset of that scheme.

If we get a server error back, or if after several attempts we don't
get a reply at all, we switch from UDP to TCP for the given
server for the current and all subsequent requests. However, if
we ever successfully received a reply over UDP, we never fall
back to TCP, and once a grace-period has passed, we try to upgrade
again to using UDP. The grace-period starts off at five minutes
after the current feature level was verified and then grows
exponentially to six hours. This is to mitigate problems due
to temporary lack of network connectivity, but at the same time
avoid flooding the network with retries when the feature attempted
feature level genuinely does not work.

Note that UDP is likely much more commonly supported than TCP,
but depending on the path between the client and the server, we
may have more luck with TCP in case something is wrong. We really
do prefer UDP though, as that is much more lightweight, that is
why TCP is only the last resort.

[0]: <https://kb.isc.org/article/AA-01219/0/Refinements-to-EDNS-fallback-behavior-can-cause-different-outcomes-in-Recursive-Servers.html>
2015-11-27 01:35:33 +01:00
Lennart Poettering c3bc53e624 resolved: for a transaction, keep track where the answer data came from
Let's track where the data came from: from the network, the cache or the
local zone. This is not only useful for debugging purposes, but is also
useful when the zone probing wants to ensure it's not reusing
transactions that were answered from the cache or the zone itself.
2015-11-27 00:03:39 +01:00
Lennart Poettering ae6a4bbf31 resolved: store just the DnsAnswer instead of a DnsPacket as answer in DnsTransaction objects
Previously we'd only store the DnsPacket in the DnsTransaction, and the
DnsQuery would then take the DnsPacket's DnsAnswer and return it. With
this change we already pull the DnsAnswer out inside the transaction.

We still store the DnsPacket in the transaction, if we have it, since we
still need to determine from which peer a response originates, to
implement caching properly. However, the DnsQuery logic doesn't care
anymore for the packet, it now only looks at answers and rcodes from the
successfuly candidate.

This also has the benefit of unifying how we propagate incoming packets,
data from the local zone or the local cache.
2015-11-27 00:03:39 +01:00
Lennart Poettering 801ad6a6a9 resolved: fully support DNS search domains
This adds support for searching single-label hostnames in a set of
configured search domains.

A new object DnsQueryCandidate is added that links queries to scopes.
It keeps track of the search domain last used for a query on a specific
link. Whenever a host name was unsuccessfuly resolved on a scope all its
transactions are flushed out and replaced by a new set, with the next
search domain appended.

This also adds a new flag SD_RESOLVED_NO_SEARCH to disable search domain
behaviour. The "systemd-resolve-host" tool is updated to make this
configurable via --search=.

Fixes #1697
2015-11-25 21:59:16 +01:00
Thomas Hindoe Paaboel Andersen 71d35b6b55 tree-wide: sort includes in *.h
This is a continuation of the previous include sort patch, which
only sorted for .c files.
2015-11-18 23:09:02 +01:00
Lennart Poettering 4667e00a61 resolved: rename DNS UDP socket to 'dns_udp_fd'
This hopefully makes this a bit more expressive and clarifies that the
fd is not used for the DNS TCP socket. This also mimics how the LLMNR
UDP fd is named in the manager object.
2015-08-25 18:51:23 +02:00
Lennart Poettering f52e61da04 resolved: only maintain one question RR key per transaction
Let's simplify things and only maintain a single RR key per transaction
object, instead of a full DnsQuestion. Unicast DNS and LLMNR don't
support multiple questions per packet anway, and Multicast DNS suggests
coalescing questions beyond a single dns query, across the whole system.
2015-08-21 22:55:01 +02:00
Tom Gundersen 3b31df8301 resolved: transaction - increase number of retry attempts
With the exponential backoff, we can perform more requests in the same amount of time,
so bump this a bit.

In case of large RTT this may be necessary in order not to regress, and in case
of large packet-loss it will make us more robust. The latter is particularly
relevant once we start probing for features (and hence may see packet-loss
until we settle on the right feature level).
2015-08-03 14:25:49 +02:00
Tom Gundersen 9df3ba6c6c resolved: transaction - exponentially increase retry timeouts
Rather than fixing this to 5s for unicast DNS and 1s for LLMNR, start
at a tenth of those values and increase exponentially until the old
values are reached. For LLMNR the recommended timeout for IEEE802
networks (which basically means all of the ones we care about) is 100ms,
so that should be uncontroversial. For unicast DNS I have found no
recommended value. However, it seems vastly more likely that hitting a
500ms timeout is casued by a packet loss, rather than the RTT genuinely
being greater than 500ms, so taking this as a startnig value seems
reasonable to me.

In the common case this greatly reduces the latency due to normal packet
loss. Moreover, once we get support for probing for features, this means
that we can send more packets before degrading the feature level whilst
still allowing us to settle on the correct feature level in a reasonable
timeframe.

The timeouts are tracked per server (or per scope for the multicast
protocols), and once a server (or scope) receives a successfull package
the timeout is reset. We also track the largest RTT for the given
server/scope, and always start our timouts at twice the largest
observed RTT.
2015-08-03 14:06:58 +02:00
Tom Gundersen 471d40d92f resolved: transaction - introduce dns_transaction_emit()
This function emits the UDP packet via the scope, but first it will
determine the current server (and connect to it) and store the
server in the transaction.

This should not change the behavior, but simplifies the code.
2015-07-27 20:30:54 +02:00
Tom Gundersen 0db643664c resolved: transaction - move DNS UDP socket creation to the scope
With access to the server when creating the socket, we can connect()
to the server and hence simplify message sending and receiving in
follow-up patches.
2015-07-27 20:13:11 +02:00
Tom Gundersen 0eb99d0a6a resloved: transaction - unify IPv4 and IPv6 sockets
A transaction can only have one socket at a time, so no need to distinguish these.
2015-07-27 19:52:48 +02:00
Tom Gundersen d20b1667db resolved: use one UDP socket per transaction
We used to have one global socket, use one per transaction instead. This
has the side-effect of giving us a random UDP port per transaction, and
hence increasing the entropy and making cache poisoining significantly
harder to achieve.

We still reuse the same port number for packets belonging to the same
transaction (resent packets).
2015-07-14 18:50:57 +02:00
Tom Gundersen 8300ba218e resolved: pin the server used in a transaction
We want to discover information about the server and use that in when crafting
packets to be resent.
2015-07-14 18:50:53 +02:00
Thomas Hindoe Paaboel Andersen 2eec67acbb remove unused includes
This patch removes includes that are not used. The removals were found with
include-what-you-use which checks if any of the symbols from a header is
in use.
2015-02-23 23:53:42 +01:00
Lennart Poettering 6e06847294 resolved: add 100ms initial jitter to all LLMNR requests 2014-08-05 17:02:46 +02:00
Lennart Poettering ec2c5e4398 resolved: implement LLMNR uniqueness verification 2014-07-31 17:47:19 +02:00