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) {
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;
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;
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;
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;
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;
/* 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)
* 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;
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;
(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,
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,
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;
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;
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;
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;
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:
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;
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;
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;
}
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;
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;
}
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;
}
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);
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;
+}
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 */
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));
+}
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
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),
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;
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) {
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
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));
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);
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)
return 0;
}
- dns_transaction_process_reply(t, p);
+ dns_transaction_process_reply(t, p, false);
return 0;
}
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;
}
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
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;
}
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);
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));
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);
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");
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) {
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");