From 6f055e43b817b66e6d4f6e4022f0a115dc35651b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 10 Nov 2020 17:14:16 +0100 Subject: [PATCH 1/3] resolved: replace "answer_authenticated" bool by uint64_t query_flags field Let's use the same flags type we use for client communication, i.e. instead of "bool answer_authenticated", let's use "uint64_t answer_query_flags", with the SD_RESOLVED_AUTHENTICATED flag. This is mostly just search/replace, i.e. a refactoring, no change in behaviour. This becomes useful once in a later commit SD_RESOLVED_CONFIDENTIAL is added to indicate resolution that either were encrypted (DNS-over-TLS) or never left the local system. --- src/resolve/resolved-dns-cache.c | 62 ++++++++++++++----------- src/resolve/resolved-dns-cache.h | 4 +- src/resolve/resolved-dns-query.c | 25 +++++----- src/resolve/resolved-dns-query.h | 2 +- src/resolve/resolved-dns-transaction.c | 63 ++++++++++++-------------- src/resolve/resolved-dns-transaction.h | 15 +++--- 6 files changed, 87 insertions(+), 84 deletions(-) diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index cf0e221621c..78b858b8bea 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -22,6 +22,8 @@ * now) */ #define CACHE_TTL_STRANGE_RCODE_USEC (10 * USEC_PER_SEC) +#define CACHEABLE_QUERY_FLAGS (SD_RESOLVED_AUTHENTICATED) + typedef enum DnsCacheItemType DnsCacheItemType; typedef struct DnsCacheItem DnsCacheItem; @@ -41,8 +43,8 @@ struct DnsCacheItem { int rcode; usec_t until; - bool authenticated:1; bool shared_owner:1; + uint64_t query_flags; /* SD_RESOLVED_AUTHENTICATED */ DnssecResult dnssec_result; int ifindex; @@ -353,7 +355,7 @@ static void dns_cache_item_update_positive( DnsResourceRecord *rr, DnsAnswer *answer, DnsPacket *full_packet, - bool authenticated, + uint64_t query_flags, bool shared_owner, DnssecResult dnssec_result, usec_t timestamp, @@ -390,7 +392,7 @@ static void dns_cache_item_update_positive( i->full_packet = full_packet; i->until = calculate_until(rr, UINT32_MAX, timestamp, false); - i->authenticated = authenticated; + i->query_flags = query_flags & CACHEABLE_QUERY_FLAGS; i->shared_owner = shared_owner; i->dnssec_result = dnssec_result; @@ -407,7 +409,7 @@ static int dns_cache_put_positive( DnsResourceRecord *rr, DnsAnswer *answer, DnsPacket *full_packet, - bool authenticated, + uint64_t query_flags, bool shared_owner, DnssecResult dnssec_result, usec_t timestamp, @@ -448,7 +450,7 @@ static int dns_cache_put_positive( rr, answer, full_packet, - authenticated, + query_flags, shared_owner, dnssec_result, timestamp, @@ -476,7 +478,7 @@ static int dns_cache_put_positive( .answer = dns_answer_ref(answer), .full_packet = dns_packet_ref(full_packet), .until = calculate_until(rr, (uint32_t) -1, timestamp, false), - .authenticated = authenticated, + .query_flags = query_flags & CACHEABLE_QUERY_FLAGS, .shared_owner = shared_owner, .dnssec_result = dnssec_result, .ifindex = ifindex, @@ -496,7 +498,7 @@ static int dns_cache_put_positive( (void) in_addr_to_string(i->owner_family, &i->owner_address, &t); log_debug("Added positive %s%s cache entry for %s "USEC_FMT"s on %s/%s/%s", - i->authenticated ? "authenticated" : "unauthenticated", + FLAGS_SET(i->query_flags, SD_RESOLVED_AUTHENTICATED) ? "authenticated" : "unauthenticated", i->shared_owner ? " shared" : "", dns_resource_key_to_string(i->key, key_str, sizeof key_str), (i->until - timestamp) / USEC_PER_SEC, @@ -515,7 +517,7 @@ static int dns_cache_put_negative( int rcode, DnsAnswer *answer, DnsPacket *full_packet, - bool authenticated, + uint64_t query_flags, DnssecResult dnssec_result, uint32_t nsec_ttl, usec_t timestamp, @@ -566,7 +568,7 @@ static int dns_cache_put_negative( .type = rcode == DNS_RCODE_SUCCESS ? DNS_CACHE_NODATA : rcode == DNS_RCODE_NXDOMAIN ? DNS_CACHE_NXDOMAIN : DNS_CACHE_RCODE, - .authenticated = authenticated, + .query_flags = query_flags & CACHEABLE_QUERY_FLAGS, .dnssec_result = dnssec_result, .owner_family = owner_family, .owner_address = *owner_address, @@ -669,7 +671,7 @@ int dns_cache_put( int rcode, DnsAnswer *answer, DnsPacket *full_packet, - bool authenticated, + uint64_t query_flags, DnssecResult dnssec_result, uint32_t nsec_ttl, int owner_family, @@ -761,7 +763,7 @@ int dns_cache_put( item->rr, primary ? answer : NULL, primary ? full_packet : NULL, - item->flags & DNS_ANSWER_AUTHENTICATED, + (item->flags & DNS_ANSWER_AUTHENTICATED) ? SD_RESOLVED_AUTHENTICATED : 0, item->flags & DNS_ANSWER_SHARED_OWNER, dnssec_result, timestamp, @@ -802,7 +804,8 @@ int dns_cache_put( if (r > 0) { /* Refuse using the SOA data if it is unsigned, but the key is * signed */ - if (authenticated && (flags & DNS_ANSWER_AUTHENTICATED) == 0) + if (FLAGS_SET(query_flags, SD_RESOLVED_AUTHENTICATED) && + (flags & DNS_ANSWER_AUTHENTICATED) == 0) return 0; } @@ -819,7 +822,7 @@ int dns_cache_put( rcode, answer, full_packet, - authenticated, + query_flags, dnssec_result, nsec_ttl, timestamp, @@ -951,7 +954,7 @@ int dns_cache_lookup( int *ret_rcode, DnsAnswer **ret_answer, DnsPacket **ret_full_packet, - bool *ret_authenticated, + uint64_t *ret_query_flags, DnssecResult *ret_dnssec_result) { _cleanup_(dns_packet_unrefp) DnsPacket *full_packet = NULL; @@ -1013,7 +1016,7 @@ int dns_cache_lookup( n++; } - if (j->authenticated) + if (FLAGS_SET(j->query_flags, SD_RESOLVED_AUTHENTICATED)) have_authenticated = true; else have_non_authenticated = true; @@ -1049,7 +1052,14 @@ int dns_cache_lookup( } } else if (j->rr) { - r = answer_add_clamp_ttl(&answer, j->rr, j->ifindex, j->authenticated ? DNS_ANSWER_AUTHENTICATED : 0, NULL, query_flags, j->until, current); + r = answer_add_clamp_ttl(&answer, + j->rr, + j->ifindex, + FLAGS_SET(j->query_flags, SD_RESOLVED_AUTHENTICATED) ? DNS_ANSWER_AUTHENTICATED : 0, + NULL, + query_flags, + j->until, + current); if (r < 0) return r; } @@ -1072,8 +1082,8 @@ int dns_cache_lookup( *ret_answer = TAKE_PTR(answer); if (ret_full_packet) *ret_full_packet = TAKE_PTR(full_packet); - if (ret_authenticated) - *ret_authenticated = false; + if (ret_query_flags) + *ret_query_flags = 0; if (ret_dnssec_result) *ret_dnssec_result = dnssec_result; @@ -1097,8 +1107,8 @@ int dns_cache_lookup( *ret_answer = TAKE_PTR(answer); if (ret_full_packet) *ret_full_packet = TAKE_PTR(full_packet); - if (ret_authenticated) - *ret_authenticated = nsec->authenticated; + if (ret_query_flags) + *ret_query_flags = nsec->query_flags; if (ret_dnssec_result) *ret_dnssec_result = nsec->dnssec_result; @@ -1127,8 +1137,8 @@ int dns_cache_lookup( *ret_answer = TAKE_PTR(answer); if (ret_full_packet) *ret_full_packet = TAKE_PTR(full_packet); - if (ret_authenticated) - *ret_authenticated = have_authenticated && !have_non_authenticated; + if (ret_query_flags) + *ret_query_flags = (have_authenticated && !have_non_authenticated) ? SD_RESOLVED_AUTHENTICATED : 0; if (ret_dnssec_result) *ret_dnssec_result = dnssec_result; @@ -1143,8 +1153,8 @@ int dns_cache_lookup( *ret_answer = TAKE_PTR(answer); if (ret_full_packet) *ret_full_packet = TAKE_PTR(full_packet); - if (ret_authenticated) - *ret_authenticated = have_authenticated && !have_non_authenticated; + if (ret_query_flags) + *ret_query_flags = (have_authenticated && !have_non_authenticated) ? SD_RESOLVED_AUTHENTICATED : 0; if (ret_dnssec_result) *ret_dnssec_result = dnssec_result; @@ -1157,8 +1167,8 @@ miss: *ret_answer = NULL; if (ret_full_packet) *ret_full_packet = NULL; - if (ret_authenticated) - *ret_authenticated = false; + if (ret_query_flags) + *ret_query_flags = 0; if (ret_dnssec_result) *ret_dnssec_result = _DNSSEC_RESULT_INVALID; diff --git a/src/resolve/resolved-dns-cache.h b/src/resolve/resolved-dns-cache.h index cfae24fb71c..621b52f8926 100644 --- a/src/resolve/resolved-dns-cache.h +++ b/src/resolve/resolved-dns-cache.h @@ -30,7 +30,7 @@ int dns_cache_put( int rcode, DnsAnswer *answer, DnsPacket *full_packet, - bool authenticated, + uint64_t query_flags, DnssecResult dnssec_result, uint32_t nsec_ttl, int owner_family, @@ -43,7 +43,7 @@ int dns_cache_lookup( int *ret_rcode, DnsAnswer **ret_answer, DnsPacket **ret_full_packet, - bool *ret_authenticated, + uint64_t *ret_query_flags, DnssecResult *ret_dnssec_result); int dns_cache_check_conflicts(DnsCache *cache, DnsResourceRecord *rr, int owner_family, const union in_addr_union *owner_address); diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index aa058446421..8137b4028b6 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -346,7 +346,7 @@ static void dns_query_reset_answer(DnsQuery *q) { q->answer_rcode = 0; q->answer_dnssec_result = _DNSSEC_RESULT_INVALID; q->answer_errno = 0; - q->answer_authenticated = false; + q->answer_query_flags = 0; q->answer_protocol = _DNS_PROTOCOL_INVALID; q->answer_family = AF_UNSPEC; q->answer_search_domain = dns_search_domain_unref(q->answer_search_domain); @@ -630,7 +630,7 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) { q->answer_rcode = DNS_RCODE_NXDOMAIN; q->answer_protocol = dns_synthesize_protocol(q->flags); q->answer_family = dns_synthesize_family(q->flags); - q->answer_authenticated = true; + q->answer_query_flags = SD_RESOLVED_AUTHENTICATED; *state = DNS_TRANSACTION_RCODE_FAILURE; return 0; @@ -644,7 +644,7 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) { q->answer_rcode = DNS_RCODE_SUCCESS; q->answer_protocol = dns_synthesize_protocol(q->flags); q->answer_family = dns_synthesize_family(q->flags); - q->answer_authenticated = true; + q->answer_query_flags = SD_RESOLVED_AUTHENTICATED; *state = DNS_TRANSACTION_SUCCESS; @@ -676,7 +676,7 @@ static int dns_query_try_etc_hosts(DnsQuery *q) { q->answer_rcode = DNS_RCODE_SUCCESS; q->answer_protocol = dns_synthesize_protocol(q->flags); q->answer_family = dns_synthesize_family(q->flags); - q->answer_authenticated = true; + q->answer_query_flags = SD_RESOLVED_AUTHENTICATED; return 1; } @@ -817,7 +817,7 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { q->answer = dns_answer_unref(q->answer); q->answer_rcode = 0; q->answer_dnssec_result = _DNSSEC_RESULT_INVALID; - q->answer_authenticated = false; + q->answer_query_flags = 0; q->answer_errno = c->error_code; q->answer_full_packet = dns_packet_unref(q->answer_full_packet); } @@ -845,7 +845,7 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { dns_packet_unref(q->answer_full_packet); q->answer_full_packet = dns_packet_ref(t->received); - if (t->answer_authenticated) { + if (FLAGS_SET(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED)) { has_authenticated = true; dnssec_result_authenticated = t->answer_dnssec_result; } else { @@ -870,14 +870,15 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { continue; /* If there's already an authenticated negative reply stored, then prefer that over any unauthenticated one */ - if (q->answer_authenticated && !t->answer_authenticated) + if (FLAGS_SET(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED) && + !FLAGS_SET(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED)) continue; dns_answer_unref(q->answer); q->answer = dns_answer_ref(t->answer); q->answer_rcode = t->answer_rcode; q->answer_dnssec_result = t->answer_dnssec_result; - q->answer_authenticated = t->answer_authenticated; + q->answer_query_flags = t->answer_query_flags; q->answer_errno = t->answer_errno; dns_packet_unref(q->answer_full_packet); q->answer_full_packet = dns_packet_ref(t->received); @@ -888,8 +889,8 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { } if (state == DNS_TRANSACTION_SUCCESS) { - q->answer_authenticated = has_authenticated && !has_non_authenticated; - q->answer_dnssec_result = q->answer_authenticated ? dnssec_result_authenticated : dnssec_result_non_authenticated; + SET_FLAG(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED, has_authenticated && !has_non_authenticated); + q->answer_dnssec_result = FLAGS_SET(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED) ? dnssec_result_authenticated : dnssec_result_non_authenticated; } q->answer_protocol = c->scope->protocol; @@ -1049,7 +1050,7 @@ int dns_query_process_cname(DnsQuery *q) { if (q->flags & SD_RESOLVED_NO_CNAME) return -ELOOP; - if (!q->answer_authenticated) + if (!FLAGS_SET(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED)) q->previous_redirect_unauthenticated = true; /* OK, let's actually follow the CNAME */ @@ -1119,5 +1120,5 @@ const char *dns_query_string(DnsQuery *q) { bool dns_query_fully_authenticated(DnsQuery *q) { assert(q); - return q->answer_authenticated && !q->previous_redirect_unauthenticated; + return FLAGS_SET(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED) && !q->previous_redirect_unauthenticated; } diff --git a/src/resolve/resolved-dns-query.h b/src/resolve/resolved-dns-query.h index a7916712c11..1a30433e8cb 100644 --- a/src/resolve/resolved-dns-query.h +++ b/src/resolve/resolved-dns-query.h @@ -66,7 +66,7 @@ struct DnsQuery { DnsAnswer *answer; int answer_rcode; DnssecResult answer_dnssec_result; - bool answer_authenticated; + uint64_t answer_query_flags; DnsProtocol answer_protocol; int answer_family; DnsSearchDomain *answer_search_domain; diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 55b9114f583..32f3f16a0da 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -29,7 +29,7 @@ static void dns_transaction_reset_answer(DnsTransaction *t) { t->answer_rcode = 0; t->answer_dnssec_result = _DNSSEC_RESULT_INVALID; t->answer_source = _DNS_TRANSACTION_SOURCE_INVALID; - t->answer_authenticated = false; + t->answer_query_flags = 0; t->answer_nsec_ttl = (uint32_t) -1; t->answer_errno = 0; } @@ -420,7 +420,7 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { st, t->answer_source < 0 ? "none" : dns_transaction_source_to_string(t->answer_source), FLAGS_SET(t->query_flags, SD_RESOLVED_NO_VALIDATE) ? "not validated" : - (t->answer_authenticated ? "authenticated" : "unsigned")); + (FLAGS_SET(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED) ? "authenticated" : "unsigned")); t->state = state; @@ -793,7 +793,7 @@ static void dns_transaction_cache_answer(DnsTransaction *t) { * since our usecase for caching them * is "bypass" mode which is only * enabled for CD packets. */ - t->answer_authenticated, + t->answer_query_flags, t->answer_dnssec_result, t->answer_nsec_ttl, t->received->family, @@ -1231,7 +1231,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { t->answer = dns_answer_ref(p->answer); t->answer_rcode = DNS_PACKET_RCODE(p); t->answer_dnssec_result = _DNSSEC_RESULT_INVALID; - t->answer_authenticated = false; + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, false); r = dns_transaction_fix_rcode(t); if (r < 0) @@ -1519,7 +1519,7 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) { if (r > 0) { t->answer_rcode = DNS_RCODE_SUCCESS; t->answer_source = DNS_TRANSACTION_TRUST_ANCHOR; - t->answer_authenticated = true; + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, true); dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); return 0; } @@ -1538,7 +1538,7 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) { t->answer_rcode = DNS_RCODE_SUCCESS; t->answer_source = DNS_TRANSACTION_TRUST_ANCHOR; - t->answer_authenticated = false; + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, false); dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); } else /* If we are not in downgrade mode, then fail the lookup, because we cannot @@ -1559,7 +1559,7 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) { if (r > 0) { t->answer_rcode = DNS_RCODE_SUCCESS; t->answer_source = DNS_TRANSACTION_ZONE; - t->answer_authenticated = true; + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, true); dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); return 0; } @@ -1582,7 +1582,7 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) { &t->answer_rcode, &t->answer, &t->received, - &t->answer_authenticated, + &t->answer_query_flags, &t->answer_dnssec_result); if (r < 0) return r; @@ -2566,7 +2566,7 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord * * RRs we are looking at. If it discovered signed DS * RRs, then we need to be signed, too. */ - if (!dt->answer_authenticated) + if (!FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED)) return false; return dns_answer_match_key(dt->answer, dns_transaction_key(dt), NULL); @@ -2618,7 +2618,7 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord * if (r == 0) continue; - return t->answer_authenticated; + return FLAGS_SET(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED); } return true; @@ -2642,12 +2642,10 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord * if (r == 0) continue; - /* We found the transaction that was supposed to find - * the SOA RR for us. It was successful, but found no - * RR for us. This means we are not at a zone cut. In - * this case, we require authentication if the SOA - * lookup was authenticated too. */ - return t->answer_authenticated; + /* We found the transaction that was supposed to find the SOA RR for us. It was + * successful, but found no RR for us. This means we are not at a zone cut. In this + * case, we require authentication if the SOA lookup was authenticated too. */ + return FLAGS_SET(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED); } return true; @@ -2788,7 +2786,7 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) { if (r == 0) continue; - return dt->answer_authenticated; + return FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED); } /* If in doubt, require NSEC/NSEC3 */ @@ -2832,11 +2830,10 @@ static int dns_transaction_dnskey_authenticated(DnsTransaction *t, DnsResourceRe if (r == 0) continue; - /* OK, we found an auxiliary DNSKEY - * lookup. If that lookup is - * authenticated, report this. */ + /* OK, we found an auxiliary DNSKEY lookup. If that lookup is authenticated, + * report this. */ - if (dt->answer_authenticated) + if (FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED)) return true; found = true; @@ -2849,12 +2846,10 @@ static int dns_transaction_dnskey_authenticated(DnsTransaction *t, DnsResourceRe if (r == 0) continue; - /* OK, we found an auxiliary DS - * lookup. If that lookup is - * authenticated and non-zero, we - * won! */ + /* OK, we found an auxiliary DS lookup. If that lookup is authenticated and + * non-zero, we won! */ - if (!dt->answer_authenticated) + if (!FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED)) return false; return dns_answer_match_key(dt->answer, dns_transaction_key(dt), NULL); @@ -2942,7 +2937,7 @@ static int dns_transaction_copy_validated(DnsTransaction *t) { if (DNS_TRANSACTION_IS_LIVE(dt->state)) continue; - if (!dt->answer_authenticated) + if (!FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED)) continue; r = dns_answer_extend(&t->validated_keys, dt->answer); @@ -3244,7 +3239,7 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { /* Our own stuff needs no validation */ if (IN_SET(t->answer_source, DNS_TRANSACTION_ZONE, DNS_TRANSACTION_TRUST_ANCHOR)) { t->answer_dnssec_result = DNSSEC_VALIDATED; - t->answer_authenticated = true; + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, true); return 0; } @@ -3332,11 +3327,11 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { /* The answer is fully authenticated, yay. */ t->answer_dnssec_result = DNSSEC_VALIDATED; t->answer_rcode = DNS_RCODE_SUCCESS; - t->answer_authenticated = true; + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, true); } else { /* The answer is not fully authenticated. */ t->answer_dnssec_result = DNSSEC_UNSIGNED; - t->answer_authenticated = false; + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, false); } } else if (r == 0) { @@ -3355,7 +3350,7 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { log_debug("Proved NXDOMAIN via NSEC/NSEC3 for transaction %u (%s)", t->id, key_str); t->answer_dnssec_result = DNSSEC_VALIDATED; t->answer_rcode = DNS_RCODE_NXDOMAIN; - t->answer_authenticated = authenticated; + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, authenticated); manager_dnssec_verdict(t->scope->manager, authenticated ? DNSSEC_SECURE : DNSSEC_INSECURE, dns_transaction_key(t)); break; @@ -3365,7 +3360,7 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { log_debug("Proved NODATA via NSEC/NSEC3 for transaction %u (%s)", t->id, key_str); t->answer_dnssec_result = DNSSEC_VALIDATED; t->answer_rcode = DNS_RCODE_SUCCESS; - t->answer_authenticated = authenticated; + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, authenticated); manager_dnssec_verdict(t->scope->manager, authenticated ? DNSSEC_SECURE : DNSSEC_INSECURE, dns_transaction_key(t)); break; @@ -3374,7 +3369,7 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { /* NSEC3 says the data might not be signed */ log_debug("Data is NSEC3 opt-out via NSEC/NSEC3 for transaction %u (%s)", t->id, key_str); t->answer_dnssec_result = DNSSEC_UNSIGNED; - t->answer_authenticated = false; + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, false); manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, dns_transaction_key(t)); break; @@ -3390,7 +3385,7 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { manager_dnssec_verdict(t->scope->manager, DNSSEC_BOGUS, dns_transaction_key(t)); } else { t->answer_dnssec_result = DNSSEC_UNSIGNED; - t->answer_authenticated = false; + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, false); manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, dns_transaction_key(t)); } diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index 9376d504bfe..dab26d01fca 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -77,15 +77,12 @@ struct DnsTransaction { uint32_t answer_nsec_ttl; int answer_errno; /* if state is DNS_TRANSACTION_ERRNO */ - /* Indicates whether the primary answer is authenticated, - * i.e. whether the RRs from answer which directly match the - * question are authenticated, or, if there are none, whether - * the NODATA or NXDOMAIN case is. It says nothing about - * additional RRs listed in the answer, however they have - * their own DNS_ANSWER_AUTHORIZED FLAGS. Note that this bit - * is defined different than the AD bit in DNS packets, as - * that covers more than just the actual primary answer. */ - bool answer_authenticated; + /* SD_RESOLVED_AUTHENTICATED here indicates whether the primary answer is authenticated, i.e. whether + * the RRs from answer which directly match the question are authenticated, or, if there are none, + * whether the NODATA or NXDOMAIN case is. It says nothing about additional RRs listed in the answer, + * however they have their own DNS_ANSWER_AUTHORIZED FLAGS. Note that this bit is defined different + * than the AD bit in DNS packets, as that covers more than just the actual primary answer. */ + uint64_t answer_query_flags; /* Contains DNSKEY, DS, SOA RRs we already verified and need * to authenticate this reply */ From 43fc4baa26ccf3bc5ee65d4c6fa4890084632f2b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 10 Nov 2020 18:06:19 +0100 Subject: [PATCH 2/3] resolved: add "confidential" flag for replies passed to clients Let's introduce a new flag that indicates whether the response was acquired in "confidential" mode, i.e. via encrypted DNS-over-TLS, or synthesized locally. Fixes: #12859 --- src/resolve/resolvectl.c | 7 +++++-- src/resolve/resolved-bus.c | 10 ++++----- src/resolve/resolved-def.h | 3 +++ src/resolve/resolved-dns-cache.c | 25 +++++++++++++++------- src/resolve/resolved-dns-packet.h | 9 ++++++-- src/resolve/resolved-dns-query.c | 22 +++++++++++++++---- src/resolve/resolved-dns-query.h | 11 ++++++++++ src/resolve/resolved-dns-scope.c | 2 +- src/resolve/resolved-dns-transaction.c | 29 ++++++++++++++++---------- src/resolve/resolved-dns-transaction.h | 2 +- src/resolve/resolved-llmnr.c | 2 +- src/resolve/resolved-mdns.c | 8 +++---- src/resolve/resolved-varlink.c | 6 +++--- 13 files changed, 95 insertions(+), 41 deletions(-) diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index 6301b6ba09b..c24bc4e27e4 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -155,9 +155,12 @@ static void print_source(uint64_t flags, usec_t rtt) { assert_se(format_timespan(rtt_str, sizeof(rtt_str), rtt, 100)); printf(" in %s.%s\n" - "%s-- Data is authenticated: %s%s\n", + "%s-- Data is authenticated: %s; Data was acquired via local or encrypted transport: %s%s\n", rtt_str, ansi_normal(), - ansi_grey(), yes_no(flags & SD_RESOLVED_AUTHENTICATED), ansi_normal()); + ansi_grey(), + yes_no(flags & SD_RESOLVED_AUTHENTICATED), + yes_no(flags & SD_RESOLVED_CONFIDENTIAL), + ansi_normal()); } static void print_ifindex_comment(int printed_so_far, int ifindex) { diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 0c1124f7ddd..90e043be62a 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -252,7 +252,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) { r = sd_bus_message_append( reply, "st", normalized, - SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q))); + dns_query_reply_flags_make(q)); if (r < 0) goto finish; @@ -367,7 +367,7 @@ static int parse_as_address(sd_bus_message *m, int ifindex, const char *hostname return r; r = sd_bus_message_append(reply, "st", canonical, - SD_RESOLVED_FLAGS_MAKE(dns_synthesize_protocol(flags), ff, true)); + SD_RESOLVED_FLAGS_MAKE(dns_synthesize_protocol(flags), ff, true, true)); if (r < 0) return r; @@ -510,7 +510,7 @@ static void bus_method_resolve_address_complete(DnsQuery *q) { if (r < 0) goto finish; - r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q))); + r = sd_bus_message_append(reply, "t", dns_query_reply_flags_make(q)); if (r < 0) goto finish; @@ -672,7 +672,7 @@ static void bus_method_resolve_record_complete(DnsQuery *q) { if (r < 0) goto finish; - r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q))); + r = sd_bus_message_append(reply, "t", dns_query_reply_flags_make(q)); if (r < 0) goto finish; @@ -1048,7 +1048,7 @@ static void resolve_service_all_complete(DnsQuery *q) { reply, "ssst", name, type, domain, - SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q))); + dns_query_reply_flags_make(q)); if (r < 0) goto finish; diff --git a/src/resolve/resolved-def.h b/src/resolve/resolved-def.h index 133cf0556f6..cdcd06d8205 100644 --- a/src/resolve/resolved-def.h +++ b/src/resolve/resolved-def.h @@ -52,6 +52,9 @@ /* Input: If reply is answered from cache, the TTLs will be adjusted by age of cache entry */ #define SD_RESOLVED_CLAMP_TTL (UINT64_C(1) << 17) +/* Output: Result was only sent via encrypted channels, or never left this system */ +#define SD_RESOLVED_CONFIDENTIAL (UINT64_C(1) << 18) + #define SD_RESOLVED_LLMNR (SD_RESOLVED_LLMNR_IPV4|SD_RESOLVED_LLMNR_IPV6) #define SD_RESOLVED_MDNS (SD_RESOLVED_MDNS_IPV4|SD_RESOLVED_MDNS_IPV6) #define SD_RESOLVED_PROTOCOLS_ALL (SD_RESOLVED_MDNS|SD_RESOLVED_LLMNR|SD_RESOLVED_DNS) diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index 78b858b8bea..1a10357123e 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -22,7 +22,7 @@ * now) */ #define CACHE_TTL_STRANGE_RCODE_USEC (10 * USEC_PER_SEC) -#define CACHEABLE_QUERY_FLAGS (SD_RESOLVED_AUTHENTICATED) +#define CACHEABLE_QUERY_FLAGS (SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL) typedef enum DnsCacheItemType DnsCacheItemType; typedef struct DnsCacheItem DnsCacheItem; @@ -44,7 +44,7 @@ struct DnsCacheItem { usec_t until; bool shared_owner:1; - uint64_t query_flags; /* SD_RESOLVED_AUTHENTICATED */ + uint64_t query_flags; /* SD_RESOLVED_AUTHENTICATED and/or SD_RESOLVED_CONFIDENTIAL */ DnssecResult dnssec_result; int ifindex; @@ -497,8 +497,9 @@ static int dns_cache_put_positive( (void) in_addr_to_string(i->owner_family, &i->owner_address, &t); - log_debug("Added positive %s%s cache entry for %s "USEC_FMT"s on %s/%s/%s", + log_debug("Added positive %s %s%s cache entry for %s "USEC_FMT"s on %s/%s/%s", FLAGS_SET(i->query_flags, SD_RESOLVED_AUTHENTICATED) ? "authenticated" : "unauthenticated", + FLAGS_SET(i->query_flags, SD_RESOLVED_CONFIDENTIAL) ? "confidential" : "non-confidential", i->shared_owner ? " shared" : "", dns_resource_key_to_string(i->key, key_str, sizeof key_str), (i->until - timestamp) / USEC_PER_SEC, @@ -763,7 +764,8 @@ int dns_cache_put( item->rr, primary ? answer : NULL, primary ? full_packet : NULL, - (item->flags & DNS_ANSWER_AUTHENTICATED) ? SD_RESOLVED_AUTHENTICATED : 0, + ((item->flags & DNS_ANSWER_AUTHENTICATED) ? SD_RESOLVED_AUTHENTICATED : 0) | + (query_flags & SD_RESOLVED_CONFIDENTIAL), item->flags & DNS_ANSWER_SHARED_OWNER, dnssec_result, timestamp, @@ -964,7 +966,7 @@ int dns_cache_lookup( int r; bool nxdomain = false; DnsCacheItem *j, *first, *nsec = NULL; - bool have_authenticated = false, have_non_authenticated = false; + bool have_authenticated = false, have_non_authenticated = false, have_confidential = false, have_non_confidential = false; usec_t current; int found_rcode = -1; DnssecResult dnssec_result = -1; @@ -1021,6 +1023,11 @@ int dns_cache_lookup( else have_non_authenticated = true; + if (FLAGS_SET(j->query_flags, SD_RESOLVED_CONFIDENTIAL)) + have_confidential = true; + else + have_non_confidential = true; + if (j->dnssec_result < 0) { have_dnssec_result = false; /* an entry without dnssec result? then invalidate things for good */ dnssec_result = _DNSSEC_RESULT_INVALID; @@ -1138,7 +1145,9 @@ int dns_cache_lookup( if (ret_full_packet) *ret_full_packet = TAKE_PTR(full_packet); if (ret_query_flags) - *ret_query_flags = (have_authenticated && !have_non_authenticated) ? SD_RESOLVED_AUTHENTICATED : 0; + *ret_query_flags = + ((have_authenticated && !have_non_authenticated) ? SD_RESOLVED_AUTHENTICATED : 0) | + ((have_confidential && !have_non_confidential) ? SD_RESOLVED_CONFIDENTIAL : 0); if (ret_dnssec_result) *ret_dnssec_result = dnssec_result; @@ -1154,7 +1163,9 @@ int dns_cache_lookup( if (ret_full_packet) *ret_full_packet = TAKE_PTR(full_packet); if (ret_query_flags) - *ret_query_flags = (have_authenticated && !have_non_authenticated) ? SD_RESOLVED_AUTHENTICATED : 0; + *ret_query_flags = + ((have_authenticated && !have_non_authenticated) ? SD_RESOLVED_AUTHENTICATED : 0) | + ((have_confidential && !have_non_confidential) ? SD_RESOLVED_CONFIDENTIAL : 0); if (ret_dnssec_result) *ret_dnssec_result = dnssec_result; diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index 9fe278264bc..c7b88310e52 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -269,12 +269,17 @@ DnsProtocol dns_protocol_from_string(const char *s) _pure_; extern const struct hash_ops dns_packet_hash_ops; -static inline uint64_t SD_RESOLVED_FLAGS_MAKE(DnsProtocol protocol, int family, bool authenticated) { +static inline uint64_t SD_RESOLVED_FLAGS_MAKE( + DnsProtocol protocol, + int family, + bool authenticated, + bool confidential) { uint64_t f; /* Converts a protocol + family into a flags field as used in queries and responses */ - f = authenticated ? SD_RESOLVED_AUTHENTICATED : 0; + f = (authenticated ? SD_RESOLVED_AUTHENTICATED : 0) | + (confidential ? SD_RESOLVED_CONFIDENTIAL : 0); switch (protocol) { case DNS_PROTOCOL_DNS: diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index 8137b4028b6..ee1da97e1e3 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -630,7 +630,7 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) { q->answer_rcode = DNS_RCODE_NXDOMAIN; q->answer_protocol = dns_synthesize_protocol(q->flags); q->answer_family = dns_synthesize_family(q->flags); - q->answer_query_flags = SD_RESOLVED_AUTHENTICATED; + q->answer_query_flags = SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL; *state = DNS_TRANSACTION_RCODE_FAILURE; return 0; @@ -644,7 +644,7 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) { q->answer_rcode = DNS_RCODE_SUCCESS; q->answer_protocol = dns_synthesize_protocol(q->flags); q->answer_family = dns_synthesize_family(q->flags); - q->answer_query_flags = SD_RESOLVED_AUTHENTICATED; + q->answer_query_flags = SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL; *state = DNS_TRANSACTION_SUCCESS; @@ -676,7 +676,7 @@ static int dns_query_try_etc_hosts(DnsQuery *q) { q->answer_rcode = DNS_RCODE_SUCCESS; q->answer_protocol = dns_synthesize_protocol(q->flags); q->answer_family = dns_synthesize_family(q->flags); - q->answer_query_flags = SD_RESOLVED_AUTHENTICATED; + q->answer_query_flags = SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL; return 1; } @@ -795,7 +795,7 @@ fail: static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS; - bool has_authenticated = false, has_non_authenticated = false; + bool has_authenticated = false, has_non_authenticated = false, has_confidential = false, has_non_confidential = false; DnssecResult dnssec_result_authenticated = _DNSSEC_RESULT_INVALID, dnssec_result_non_authenticated = _DNSSEC_RESULT_INVALID; DnsTransaction *t; int r; @@ -853,6 +853,11 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { dnssec_result_non_authenticated = t->answer_dnssec_result; } + if (FLAGS_SET(t->answer_query_flags, SD_RESOLVED_CONFIDENTIAL)) + has_confidential = true; + else + has_non_confidential = true; + state = DNS_TRANSACTION_SUCCESS; break; } @@ -890,6 +895,7 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { if (state == DNS_TRANSACTION_SUCCESS) { SET_FLAG(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED, has_authenticated && !has_non_authenticated); + SET_FLAG(q->answer_query_flags, SD_RESOLVED_CONFIDENTIAL, has_confidential && !has_non_confidential); q->answer_dnssec_result = FLAGS_SET(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED) ? dnssec_result_authenticated : dnssec_result_non_authenticated; } @@ -1052,6 +1058,8 @@ int dns_query_process_cname(DnsQuery *q) { if (!FLAGS_SET(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED)) q->previous_redirect_unauthenticated = true; + if (!FLAGS_SET(q->answer_query_flags, SD_RESOLVED_CONFIDENTIAL)) + q->previous_redirect_non_confidential = true; /* OK, let's actually follow the CNAME */ r = dns_query_cname_redirect(q, cname); @@ -1122,3 +1130,9 @@ bool dns_query_fully_authenticated(DnsQuery *q) { return FLAGS_SET(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED) && !q->previous_redirect_unauthenticated; } + +bool dns_query_fully_confidential(DnsQuery *q) { + assert(q); + + return FLAGS_SET(q->answer_query_flags, SD_RESOLVED_CONFIDENTIAL) && !q->previous_redirect_non_confidential; +} diff --git a/src/resolve/resolved-dns-query.h b/src/resolve/resolved-dns-query.h index 1a30433e8cb..607390b8efb 100644 --- a/src/resolve/resolved-dns-query.h +++ b/src/resolve/resolved-dns-query.h @@ -72,6 +72,7 @@ struct DnsQuery { DnsSearchDomain *answer_search_domain; int answer_errno; /* if state is DNS_TRANSACTION_ERRNO */ bool previous_redirect_unauthenticated; + bool previous_redirect_non_confidential; DnsPacket *answer_full_packet; /* Bus + Varlink client information */ @@ -132,3 +133,13 @@ const char *dns_query_string(DnsQuery *q); DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQuery*, dns_query_free); bool dns_query_fully_authenticated(DnsQuery *q); +bool dns_query_fully_confidential(DnsQuery *q); + +static inline uint64_t dns_query_reply_flags_make(DnsQuery *q) { + assert(q); + + return SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, + q->answer_family, + dns_query_fully_authenticated(q), + dns_query_fully_confidential(q)); +} diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index c962af9aba3..8b5dd257324 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -505,7 +505,7 @@ DnsScopeMatch dns_scope_good_domain( if (ifindex != 0 && (!s->link || s->link->ifindex != ifindex)) return DNS_SCOPE_NO; - if ((SD_RESOLVED_FLAGS_MAKE(s->protocol, s->family, 0) & flags) == 0) + if ((SD_RESOLVED_FLAGS_MAKE(s->protocol, s->family, false, false) & flags) == 0) return DNS_SCOPE_NO; /* Never resolve any loopback hostname or IP address via DNS, LLMNR or mDNS. Instead, always rely on diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 32f3f16a0da..36e38f65322 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -410,7 +410,7 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { else st = dns_transaction_state_to_string(state); - log_debug("%s transaction %" PRIu16 " for <%s> on scope %s on %s/%s now complete with <%s> from %s (%s).", + log_debug("%s transaction %" PRIu16 " for <%s> on scope %s on %s/%s now complete with <%s> from %s (%s; %s).", t->bypass ? "Bypass" : "Regular", t->id, dns_resource_key_to_string(dns_transaction_key(t), key_str, sizeof key_str), @@ -420,7 +420,8 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { st, t->answer_source < 0 ? "none" : dns_transaction_source_to_string(t->answer_source), FLAGS_SET(t->query_flags, SD_RESOLVED_NO_VALIDATE) ? "not validated" : - (FLAGS_SET(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED) ? "authenticated" : "unsigned")); + (FLAGS_SET(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED) ? "authenticated" : "unsigned"), + FLAGS_SET(t->answer_query_flags, SD_RESOLVED_CONFIDENTIAL) ? "confidential" : "non-confidential"); t->state = state; @@ -561,10 +562,15 @@ static void on_transaction_stream_error(DnsTransaction *t, int error) { dns_transaction_complete_errno(t, error); } -static int dns_transaction_on_stream_packet(DnsTransaction *t, DnsPacket *p) { +static int dns_transaction_on_stream_packet(DnsTransaction *t, DnsStream *s, DnsPacket *p) { + bool encrypted; + assert(t); + assert(s); assert(p); + encrypted = s->encrypted; + dns_transaction_close_connection(t, true); if (dns_packet_validate_reply(p) <= 0) { @@ -576,7 +582,7 @@ static int dns_transaction_on_stream_packet(DnsTransaction *t, DnsPacket *p) { dns_scope_check_conflicts(t->scope, p); t->block_gc++; - dns_transaction_process_reply(t, p); + dns_transaction_process_reply(t, p, encrypted); t->block_gc--; /* If the response wasn't useful, then complete the transition @@ -621,12 +627,11 @@ static int on_stream_packet(DnsStream *s) { assert(s); /* Take ownership of packet to be able to receive new packets */ - p = dns_stream_take_read_packet(s); - assert(p); + assert_se(p = dns_stream_take_read_packet(s)); t = hashmap_get(s->manager->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p))); if (t) - return dns_transaction_on_stream_packet(t, p); + return dns_transaction_on_stream_packet(t, s, p); /* Ignore incorrect transaction id as an old transaction can have been canceled. */ log_debug("Received unexpected TCP reply packet with id %" PRIu16 ", ignoring.", DNS_PACKET_ID(p)); @@ -990,7 +995,7 @@ static int dns_transaction_fix_rcode(DnsTransaction *t) { return 0; } -void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { +void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p, bool encrypted) { int r; assert(t); @@ -1232,6 +1237,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { t->answer_rcode = DNS_PACKET_RCODE(p); t->answer_dnssec_result = _DNSSEC_RESULT_INVALID; SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, false); + SET_FLAG(t->answer_query_flags, SD_RESOLVED_CONFIDENTIAL, encrypted); r = dns_transaction_fix_rcode(t); if (r < 0) @@ -1315,7 +1321,7 @@ static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *use return 0; } - dns_transaction_process_reply(t, p); + dns_transaction_process_reply(t, p, false); return 0; } @@ -1519,7 +1525,7 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) { if (r > 0) { t->answer_rcode = DNS_RCODE_SUCCESS; t->answer_source = DNS_TRANSACTION_TRUST_ANCHOR; - SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, true); + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL, true); dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); return 0; } @@ -1539,6 +1545,7 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) { t->answer_rcode = DNS_RCODE_SUCCESS; t->answer_source = DNS_TRANSACTION_TRUST_ANCHOR; SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, false); + SET_FLAG(t->answer_query_flags, SD_RESOLVED_CONFIDENTIAL, true); dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); } else /* If we are not in downgrade mode, then fail the lookup, because we cannot @@ -1559,7 +1566,7 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) { if (r > 0) { t->answer_rcode = DNS_RCODE_SUCCESS; t->answer_source = DNS_TRANSACTION_ZONE; - SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, true); + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL, true); dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); return 0; } diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index dab26d01fca..2c1894f9c23 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -145,7 +145,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DnsTransaction*, dns_transaction_gc); int dns_transaction_go(DnsTransaction *t); -void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p); +void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p, bool encrypted); void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state); void dns_transaction_notify(DnsTransaction *t, DnsTransaction *source); diff --git a/src/resolve/resolved-llmnr.c b/src/resolve/resolved-llmnr.c index b1b8351e00b..cc933d6b8e7 100644 --- a/src/resolve/resolved-llmnr.c +++ b/src/resolve/resolved-llmnr.c @@ -99,7 +99,7 @@ static int on_llmnr_packet(sd_event_source *s, int fd, uint32_t revents, void *u t = hashmap_get(m->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p))); if (t) - dns_transaction_process_reply(t, p); + dns_transaction_process_reply(t, p, false); } else if (dns_packet_validate_query(p) > 0) { log_debug("Got LLMNR UDP query packet for id %u", DNS_PACKET_ID(p)); diff --git a/src/resolve/resolved-mdns.c b/src/resolve/resolved-mdns.c index 6fccc5a1e5a..5b4d08cce8d 100644 --- a/src/resolve/resolved-mdns.c +++ b/src/resolve/resolved-mdns.c @@ -303,20 +303,20 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us t = dns_scope_find_transaction(scope, rr->key, SD_RESOLVED_NO_CACHE|SD_RESOLVED_NO_ZONE); if (t) - dns_transaction_process_reply(t, p); + dns_transaction_process_reply(t, p, false); /* Also look for the various types of ANY transactions */ t = dns_scope_find_transaction(scope, &DNS_RESOURCE_KEY_CONST(rr->key->class, DNS_TYPE_ANY, dns_resource_key_name(rr->key)), SD_RESOLVED_NO_CACHE|SD_RESOLVED_NO_ZONE); if (t) - dns_transaction_process_reply(t, p); + dns_transaction_process_reply(t, p, false); t = dns_scope_find_transaction(scope, &DNS_RESOURCE_KEY_CONST(DNS_CLASS_ANY, rr->key->type, dns_resource_key_name(rr->key)), SD_RESOLVED_NO_CACHE|SD_RESOLVED_NO_ZONE); if (t) - dns_transaction_process_reply(t, p); + dns_transaction_process_reply(t, p, false); t = dns_scope_find_transaction(scope, &DNS_RESOURCE_KEY_CONST(DNS_CLASS_ANY, DNS_TYPE_ANY, dns_resource_key_name(rr->key)), SD_RESOLVED_NO_CACHE|SD_RESOLVED_NO_ZONE); if (t) - dns_transaction_process_reply(t, p); + dns_transaction_process_reply(t, p, false); } dns_cache_put(&scope->cache, scope->manager->enable_cache, NULL, DNS_PACKET_RCODE(p), p->answer, NULL, false, _DNSSEC_RESULT_INVALID, (uint32_t) -1, p->family, &p->sender); diff --git a/src/resolve/resolved-varlink.c b/src/resolve/resolved-varlink.c index b691e59d3ee..05bb2ec8177 100644 --- a/src/resolve/resolved-varlink.c +++ b/src/resolve/resolved-varlink.c @@ -222,7 +222,7 @@ static void vl_method_resolve_hostname_complete(DnsQuery *q) { JSON_BUILD_OBJECT( JSON_BUILD_PAIR("addresses", JSON_BUILD_VARIANT(array)), JSON_BUILD_PAIR("name", JSON_BUILD_STRING(normalized)), - JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q)))))); + JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(dns_query_reply_flags_make(q))))); finish: if (r < 0) { log_error_errno(r, "Failed to send hostname reply: %m"); @@ -267,7 +267,7 @@ static int parse_as_address(Varlink *link, LookupParameters *p) { JSON_BUILD_PAIR("family", JSON_BUILD_INTEGER(ff)), JSON_BUILD_PAIR("address", JSON_BUILD_BYTE_ARRAY(&parsed, FAMILY_ADDRESS_SIZE(ff)))))), JSON_BUILD_PAIR("name", JSON_BUILD_STRING(canonical)), - JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(SD_RESOLVED_FLAGS_MAKE(dns_synthesize_protocol(p->flags), ff, true))))); + JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(SD_RESOLVED_FLAGS_MAKE(dns_synthesize_protocol(p->flags), ff, true, true))))); } static int vl_method_resolve_hostname(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) { @@ -440,7 +440,7 @@ static void vl_method_resolve_address_complete(DnsQuery *q) { r = varlink_replyb(q->varlink_request, JSON_BUILD_OBJECT( JSON_BUILD_PAIR("names", JSON_BUILD_VARIANT(array)), - JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q)))))); + JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(dns_query_reply_flags_make(q))))); finish: if (r < 0) { log_error_errno(r, "Failed to send address reply: %m"); From 5c1790d1cec785951f16addb257bbf13d594e02b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 10 Nov 2020 23:34:40 +0100 Subject: [PATCH 3/3] resolved: propagate source where an RR from back to client This is extremely useful when debugging stuff: knowing whether a result was cached, came from network, or was synthesized. --- src/resolve/resolvectl.c | 10 ++++++++++ src/resolve/resolved-bus.c | 3 ++- src/resolve/resolved-def.h | 17 +++++++++++++++++ src/resolve/resolved-dns-query.c | 12 ++++++++---- src/resolve/resolved-dns-query.h | 3 ++- src/resolve/resolved-dns-transaction.h | 21 +++++++++++++++++++++ src/resolve/resolved-varlink.c | 3 ++- 7 files changed, 62 insertions(+), 7 deletions(-) diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index c24bc4e27e4..2302ca48ba3 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -161,6 +161,16 @@ static void print_source(uint64_t flags, usec_t rtt) { yes_no(flags & SD_RESOLVED_AUTHENTICATED), yes_no(flags & SD_RESOLVED_CONFIDENTIAL), ansi_normal()); + + if ((flags & (SD_RESOLVED_FROM_MASK|SD_RESOLVED_SYNTHETIC)) != 0) + printf("%s-- Data from:%s%s%s%s%s%s\n", + ansi_grey(), + FLAGS_SET(flags, SD_RESOLVED_SYNTHETIC) ? " synthetic" : "", + FLAGS_SET(flags, SD_RESOLVED_FROM_CACHE) ? " cache" : "", + FLAGS_SET(flags, SD_RESOLVED_FROM_ZONE) ? " zone" : "", + FLAGS_SET(flags, SD_RESOLVED_FROM_TRUST_ANCHOR) ? " trust-anchor" : "", + FLAGS_SET(flags, SD_RESOLVED_FROM_NETWORK) ? " network" : "", + ansi_normal()); } static void print_ifindex_comment(int printed_so_far, int ifindex) { diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 90e043be62a..71374a19ad6 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -367,7 +367,8 @@ static int parse_as_address(sd_bus_message *m, int ifindex, const char *hostname return r; r = sd_bus_message_append(reply, "st", canonical, - SD_RESOLVED_FLAGS_MAKE(dns_synthesize_protocol(flags), ff, true, true)); + SD_RESOLVED_FLAGS_MAKE(dns_synthesize_protocol(flags), ff, true, true) | + SD_RESOLVED_SYNTHETIC); if (r < 0) return r; diff --git a/src/resolve/resolved-def.h b/src/resolve/resolved-def.h index cdcd06d8205..702d3f8b418 100644 --- a/src/resolve/resolved-def.h +++ b/src/resolve/resolved-def.h @@ -55,8 +55,25 @@ /* Output: Result was only sent via encrypted channels, or never left this system */ #define SD_RESOLVED_CONFIDENTIAL (UINT64_C(1) << 18) +/* Output: Result was (at least partially) synthesized locally */ +#define SD_RESOLVED_SYNTHETIC (UINT64_C(1) << 19) + +/* Output: Result was (at least partially) answered from cache */ +#define SD_RESOLVED_FROM_CACHE (UINT64_C(1) << 20) + +/* Output: Result was (at least partially) answered from local zone */ +#define SD_RESOLVED_FROM_ZONE (UINT64_C(1) << 21) + +/* Output: Result was (at least partially) answered from trust anchor */ +#define SD_RESOLVED_FROM_TRUST_ANCHOR (UINT64_C(1) << 22) + +/* Output: Result was (at least partially) answered from network */ +#define SD_RESOLVED_FROM_NETWORK (UINT64_C(1) << 23) + #define SD_RESOLVED_LLMNR (SD_RESOLVED_LLMNR_IPV4|SD_RESOLVED_LLMNR_IPV6) #define SD_RESOLVED_MDNS (SD_RESOLVED_MDNS_IPV4|SD_RESOLVED_MDNS_IPV6) #define SD_RESOLVED_PROTOCOLS_ALL (SD_RESOLVED_MDNS|SD_RESOLVED_LLMNR|SD_RESOLVED_DNS) +#define SD_RESOLVED_FROM_MASK (SD_RESOLVED_FROM_CACHE|SD_RESOLVED_FROM_ZONE|SD_RESOLVED_FROM_TRUST_ANCHOR|SD_RESOLVED_FROM_NETWORK) + #define SD_RESOLVED_QUERY_TIMEOUT_USEC (120 * USEC_PER_SEC) diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index ee1da97e1e3..1413afe3b9b 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -630,7 +630,7 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) { q->answer_rcode = DNS_RCODE_NXDOMAIN; q->answer_protocol = dns_synthesize_protocol(q->flags); q->answer_family = dns_synthesize_family(q->flags); - q->answer_query_flags = SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL; + q->answer_query_flags = SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL|SD_RESOLVED_SYNTHETIC; *state = DNS_TRANSACTION_RCODE_FAILURE; return 0; @@ -644,7 +644,7 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) { q->answer_rcode = DNS_RCODE_SUCCESS; q->answer_protocol = dns_synthesize_protocol(q->flags); q->answer_family = dns_synthesize_family(q->flags); - q->answer_query_flags = SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL; + q->answer_query_flags = SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL|SD_RESOLVED_SYNTHETIC; *state = DNS_TRANSACTION_SUCCESS; @@ -676,7 +676,7 @@ static int dns_query_try_etc_hosts(DnsQuery *q) { q->answer_rcode = DNS_RCODE_SUCCESS; q->answer_protocol = dns_synthesize_protocol(q->flags); q->answer_family = dns_synthesize_family(q->flags); - q->answer_query_flags = SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL; + q->answer_query_flags = SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL|SD_RESOLVED_SYNTHETIC; return 1; } @@ -833,10 +833,14 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { r = dns_answer_extend(&q->answer, t->answer); if (r < 0) goto fail; + + q->answer_query_flags |= dns_transaction_source_to_query_flags(t->answer_source); } else { /* Override non-successful previous answers */ dns_answer_unref(q->answer); q->answer = dns_answer_ref(t->answer); + + q->answer_query_flags = dns_transaction_source_to_query_flags(t->answer_source); } q->answer_rcode = t->answer_rcode; @@ -883,7 +887,7 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { q->answer = dns_answer_ref(t->answer); q->answer_rcode = t->answer_rcode; q->answer_dnssec_result = t->answer_dnssec_result; - q->answer_query_flags = t->answer_query_flags; + q->answer_query_flags = t->answer_query_flags | dns_transaction_source_to_query_flags(t->answer_source); q->answer_errno = t->answer_errno; dns_packet_unref(q->answer_full_packet); q->answer_full_packet = dns_packet_ref(t->received); diff --git a/src/resolve/resolved-dns-query.h b/src/resolve/resolved-dns-query.h index 607390b8efb..4874aa0c177 100644 --- a/src/resolve/resolved-dns-query.h +++ b/src/resolve/resolved-dns-query.h @@ -141,5 +141,6 @@ static inline uint64_t dns_query_reply_flags_make(DnsQuery *q) { return SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q), - dns_query_fully_confidential(q)); + dns_query_fully_confidential(q)) | + (q->answer_query_flags & (SD_RESOLVED_FROM_MASK|SD_RESOLVED_SYNTHETIC)); } diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index 2c1894f9c23..b036adec2e4 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -169,6 +169,27 @@ static inline DnsResourceKey *dns_transaction_key(DnsTransaction *t) { return t->bypass->question->keys[0]; } +static inline uint64_t dns_transaction_source_to_query_flags(DnsTransactionSource s) { + + switch (s) { + + case DNS_TRANSACTION_NETWORK: + return SD_RESOLVED_FROM_NETWORK; + + case DNS_TRANSACTION_CACHE: + return SD_RESOLVED_FROM_CACHE; + + case DNS_TRANSACTION_ZONE: + return SD_RESOLVED_FROM_ZONE; + + case DNS_TRANSACTION_TRUST_ANCHOR: + return SD_RESOLVED_FROM_TRUST_ANCHOR; + + default: + return 0; + } +} + const char* dns_transaction_state_to_string(DnsTransactionState p) _const_; DnsTransactionState dns_transaction_state_from_string(const char *s) _pure_; diff --git a/src/resolve/resolved-varlink.c b/src/resolve/resolved-varlink.c index 05bb2ec8177..77e75b8a8d1 100644 --- a/src/resolve/resolved-varlink.c +++ b/src/resolve/resolved-varlink.c @@ -267,7 +267,8 @@ static int parse_as_address(Varlink *link, LookupParameters *p) { JSON_BUILD_PAIR("family", JSON_BUILD_INTEGER(ff)), JSON_BUILD_PAIR("address", JSON_BUILD_BYTE_ARRAY(&parsed, FAMILY_ADDRESS_SIZE(ff)))))), JSON_BUILD_PAIR("name", JSON_BUILD_STRING(canonical)), - JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(SD_RESOLVED_FLAGS_MAKE(dns_synthesize_protocol(p->flags), ff, true, true))))); + JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(SD_RESOLVED_FLAGS_MAKE(dns_synthesize_protocol(p->flags), ff, true, true)| + SD_RESOLVED_SYNTHETIC)))); } static int vl_method_resolve_hostname(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {