Skip to content
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

Thirteenth DNSSEC patch set #2289

Merged
merged 38 commits into from
Jan 11, 2016
Merged

Thirteenth DNSSEC patch set #2289

merged 38 commits into from
Jan 11, 2016

Conversation

poettering
Copy link
Member

No description provided.

int trivial_compare_func(const void *a, const void *b) _const_;
extern const struct hash_ops trivial_hash_ops;

/* 32bit values we can always just embedd in the pointer itself, but
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/embedd/embed/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, can fix, but note that this is just some moved code, not new code...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will prep a fix in a later PR

@vcaputo
Copy link
Member

vcaputo commented Jan 10, 2016

Casually reviewed, some nits, but fwiw lgtm.

@poettering
Copy link
Member Author

Thanks for the review!

The domain name for this NSEC3 RR was originally stored in a variable
called "suffix", which was then renamed to "zone" in
d1511b3. Hence also rename the
RR variable accordingly.
This increases compatibility with crappy Belkin routers.
…_dnssec()

Invert an "if" check, so that we can use "continue" rather than another
code block indentation.
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.
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.
… 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.
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.
…ldcard 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.
Let's be a bit more precise with the editor configuration and specify a higher fill column of 119. This isn't as emacs'
default of 70, but also not particularly high on today's screens.

While we are at it, also set a couple of other emacs C coding style variables.
The hash operations are not really that specific to hashmaps, hence split them into a .c module of their own.
…hashes

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.
The code to retry transactions has been used over and over again, simplify it by replacing it by a new function.
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.
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.
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.
… UDP to 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.
…s 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.
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.
This makes it easier to log information about a specific DnsServer object.
… knows DNSSEC

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.
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.
@poettering
Copy link
Member Author

Force pushed a new patch set now, that fixes a few things @vcaputo suggested, and adds a couple of new commits to the PR.

We wouldn't know how to validate them, since they are the signatures, and hence have no signatures.
teg added a commit that referenced this pull request Jan 11, 2016
@teg teg merged commit a41a718 into systemd:master Jan 11, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

Successfully merging this pull request may close these issues.

None yet

3 participants