1
0
mirror of https://github.com/systemd/systemd synced 2025-09-30 17:24:46 +02:00

Compare commits

...

10 Commits

Author SHA1 Message Date
Yu Watanabe
ccb4072e21 man: fix indentation 2021-02-16 17:59:21 +01:00
Lennart Poettering
b52eac2010 resolved: paranoia — ensure DNS reply came over stream we sent it to 2021-02-16 17:43:27 +01:00
heretoenhance
8d186a35cb
Adding an explanation for CONFIG_NET requirement (#18600)
* README: replace CONFIG_NET with CONFIG_UNIX in requirements list
2021-02-16 16:26:51 +00:00
Lennart Poettering
1d123e772d resolved: reduce indentation level a bit 2021-02-16 16:46:01 +01:00
Lennart Poettering
13eb76ef06 resolved: let's preferably route reverse lookups for local subnets to matching interfaces
Let's preferably route traffic for reverse lookups to LLMNR/mDNS/DNS on
the matching interface if the IP address is in the local subnet. Also,
if looking up an IP address of our own host, let's avoid doing
LLMNR/mDNS at all.

This is useful if "~." is a routing domain to DNS, as it means, local
reverse lookups still go to LLMNR/mDNS, too.

Fixes: #16243 #10081
2021-02-16 16:13:42 +01:00
Lennart Poettering
1e69eaddf8 resolved: log process info of clients requesting resolution via D-Bus
Let's make things more debuggable: when debug logging is on, let's
say which client is asking for our services.

This is helpful for easily figuring out which local process might
interfere with your debugging sessions by issuing additional requests
while you try to debug a request (I am looking at you, geoclue!).
2021-02-16 13:42:49 +01:00
Lennart Poettering
ff05157f82
Merge pull request #18617 from poettering/resolved-confidential
resolved: tell clients which source a response is from, and whether it was never sent via unencrypted transports
2021-02-16 13:40:46 +01:00
Lennart Poettering
5c1790d1ce 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.
2021-02-16 10:03:43 +01:00
Lennart Poettering
43fc4baa26 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
2021-02-16 10:03:43 +01:00
Lennart Poettering
6f055e43b8 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.
2021-02-16 10:03:43 +01:00
21 changed files with 392 additions and 141 deletions

2
README
View File

@ -44,7 +44,7 @@ REQUIREMENTS:
CONFIG_SIGNALFD
CONFIG_TIMERFD
CONFIG_EPOLL
CONFIG_NET
CONFIG_UNIX (it requires CONFIG_NET, but every other flag in it is not necessary)
CONFIG_SYSFS
CONFIG_PROC_FS
CONFIG_FHANDLE (libudev, mount and bind mount handling)

View File

@ -1344,16 +1344,15 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
set, then the gateway address provided by DHCPv4 or IPv6 RA is used.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>GatewayOnLink=</varname></term>
<listitem>
<para>Takes a boolean. If set to true, the kernel does not have
to check if the gateway is reachable directly by the current machine (i.e., the kernel does
not need to check if the gateway is attached to the local network), so that we can insert the
route in the kernel table without it being complained about. Defaults to <literal>no</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>GatewayOnLink=</varname></term>
<listitem>
<para>Takes a boolean. If set to true, the kernel does not have to check if the gateway is
reachable directly by the current machine (i.e., the kernel does not need to check if the
gateway is attached to the local network), so that we can insert the route in the kernel
table without it being complained about. Defaults to <literal>no</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Destination=</varname></term>
<listitem>

View File

@ -155,9 +155,22 @@ 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());
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) {

View File

@ -7,6 +7,7 @@
#include "bus-message-util.h"
#include "bus-polkit.h"
#include "dns-domain.h"
#include "format-util.h"
#include "memory-util.h"
#include "missing_capability.h"
#include "resolved-bus.h"
@ -252,7 +253,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,13 +368,39 @@ 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) |
SD_RESOLVED_SYNTHETIC);
if (r < 0)
return r;
return sd_bus_send(sd_bus_message_get_bus(m), reply, NULL);
}
void bus_client_log(sd_bus_message *m, const char *what) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
const char *comm = NULL;
uid_t uid = UID_INVALID;
pid_t pid = 0;
int r;
assert(m);
assert(what);
if (!DEBUG_LOGGING)
return;
r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_AUGMENT, &creds);
if (r < 0)
return (void) log_debug_errno(r, "Failed to query client credentials, ignoring: %m");
(void) sd_bus_creds_get_uid(creds, &uid);
(void) sd_bus_creds_get_pid(creds, &pid);
(void) sd_bus_creds_get_comm(creds, &comm);
log_debug("D-Bus %s request from client PID " PID_FMT " (%s) with UID " UID_FMT,
what, pid, strna(comm), uid);
}
static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL;
Manager *m = userdata;
@ -420,6 +447,8 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata,
if (r < 0 && r != -EALREADY)
return r;
bus_client_log(message, "hostname resolution");
r = dns_query_new(m, &q, question_utf8, question_idna ?: question_utf8, NULL, ifindex, flags);
if (r < 0)
return r;
@ -510,7 +539,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;
@ -562,6 +591,8 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s
if (r < 0)
return r;
bus_client_log(message, "address resolution");
r = dns_query_new(m, &q, question, question, NULL, ifindex, flags|SD_RESOLVED_NO_SEARCH);
if (r < 0)
return r;
@ -672,7 +703,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;
@ -738,6 +769,8 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd
if (r < 0)
return r;
bus_client_log(message, "resource record resolution");
/* Setting SD_RESOLVED_CLAMP_TTL: let's request that the TTL is fixed up for locally cached entries,
* after all we return it in the wire format blob. */
r = dns_query_new(m, &q, question, question, NULL, ifindex, flags|SD_RESOLVED_NO_SEARCH|SD_RESOLVED_CLAMP_TTL);
@ -1048,7 +1081,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;
@ -1270,6 +1303,8 @@ static int bus_method_resolve_service(sd_bus_message *message, void *userdata, s
if (r < 0)
return r;
bus_client_log(message, "service resolution");
r = dns_query_new(m, &q, question_utf8, question_idna, NULL, ifindex, flags|SD_RESOLVED_NO_SEARCH);
if (r < 0)
return r;
@ -1662,6 +1697,8 @@ static int bus_method_reset_statistics(sd_bus_message *message, void *userdata,
assert(message);
assert(m);
bus_client_log(message, "statistics reset");
LIST_FOREACH(scopes, s, m->dns_scopes)
s->cache.n_hit = s->cache.n_miss = 0;
@ -1774,6 +1811,8 @@ static int bus_method_flush_caches(sd_bus_message *message, void *userdata, sd_b
assert(message);
assert(m);
bus_client_log(message, "cache flush");
manager_flush_caches(m, LOG_INFO);
return sd_bus_reply_method_return(message, NULL);
@ -1785,6 +1824,8 @@ static int bus_method_reset_server_features(sd_bus_message *message, void *userd
assert(message);
assert(m);
bus_client_log(message, "server feature reset");
manager_reset_server_features(m);
return sd_bus_reply_method_return(message, NULL);

View File

@ -13,3 +13,5 @@ int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex
int bus_property_get_resolve_support(sd_bus *bus, const char *path, const char *interface,
const char *property, sd_bus_message *reply,
void *userdata, sd_bus_error *error);
void bus_client_log(sd_bus_message *m, const char *what);

View File

@ -52,8 +52,28 @@
/* 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)
/* 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)

View File

@ -22,6 +22,8 @@
* now) */
#define CACHE_TTL_STRANGE_RCODE_USEC (10 * USEC_PER_SEC)
#define CACHEABLE_QUERY_FLAGS (SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL)
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 and/or SD_RESOLVED_CONFIDENTIAL */
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,
@ -495,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",
i->authenticated ? "authenticated" : "unauthenticated",
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,
@ -515,7 +518,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 +569,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 +672,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 +764,8 @@ 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) |
(query_flags & SD_RESOLVED_CONFIDENTIAL),
item->flags & DNS_ANSWER_SHARED_OWNER,
dnssec_result,
timestamp,
@ -802,7 +806,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 +824,7 @@ int dns_cache_put(
rcode,
answer,
full_packet,
authenticated,
query_flags,
dnssec_result,
nsec_ttl,
timestamp,
@ -951,7 +956,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;
@ -961,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;
@ -1013,11 +1018,16 @@ 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;
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;
@ -1049,7 +1059,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 +1089,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 +1114,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 +1144,10 @@ 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) |
((have_confidential && !have_non_confidential) ? SD_RESOLVED_CONFIDENTIAL : 0);
if (ret_dnssec_result)
*ret_dnssec_result = dnssec_result;
@ -1143,8 +1162,10 @@ 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) |
((have_confidential && !have_non_confidential) ? SD_RESOLVED_CONFIDENTIAL : 0);
if (ret_dnssec_result)
*ret_dnssec_result = dnssec_result;
@ -1157,8 +1178,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;

View File

@ -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);

View File

@ -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:

View File

@ -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|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_authenticated = true;
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_authenticated = true;
q->answer_query_flags = SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL|SD_RESOLVED_SYNTHETIC;
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;
@ -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);
}
@ -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;
@ -845,7 +849,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 {
@ -853,6 +857,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;
}
@ -870,14 +879,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 | 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);
@ -888,8 +898,9 @@ 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);
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;
}
q->answer_protocol = c->scope->protocol;
@ -1049,8 +1060,10 @@ 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;
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);
@ -1119,5 +1132,11 @@ 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;
}
bool dns_query_fully_confidential(DnsQuery *q) {
assert(q);
return FLAGS_SET(q->answer_query_flags, SD_RESOLVED_CONFIDENTIAL) && !q->previous_redirect_non_confidential;
}

View File

@ -66,12 +66,13 @@ 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;
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,14 @@ 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)) |
(q->answer_query_flags & (SD_RESOLVED_FROM_MASK|SD_RESOLVED_SYNTHETIC));
}

View File

@ -477,6 +477,65 @@ static DnsScopeMatch match_link_local_reverse_lookups(const char *domain) {
return _DNS_SCOPE_MATCH_INVALID;
}
static DnsScopeMatch match_subnet_reverse_lookups(
DnsScope *s,
const char *domain,
bool exclude_own) {
union in_addr_union ia;
LinkAddress *a;
int f, r;
assert(s);
assert(domain);
/* Checks whether the specified domain is a reverse address domain (i.e. in the .in-addr.arpa or
* .ip6.arpa area), and if so, whether the address matches any of the local subnets of the link the
* scope is associated with. If so, our scope should consider itself relevant for any lookup in the
* domain, since it apparently refers to hosts on this link's subnet.
*
* If 'exclude_own' is true this will return DNS_SCOPE_NO for any IP addresses assigned locally. This
* is useful for LLMNR/mDNS as we never want to look up our own hostname on LLMNR/mDNS but always use
* the locally synthesized one. */
if (!s->link)
return _DNS_SCOPE_MATCH_INVALID; /* No link, hence no local addresses to check */
r = dns_name_address(domain, &f, &ia);
if (r < 0)
log_debug_errno(r, "Failed to determine whether '%s' is an address domain: %m", domain);
if (r <= 0)
return _DNS_SCOPE_MATCH_INVALID;
if (s->family != AF_UNSPEC && f != s->family)
return _DNS_SCOPE_MATCH_INVALID; /* Don't look for IPv4 addresses on LLMNR/mDNS over IPv6 and vice versa */
LIST_FOREACH(addresses, a, s->link->addresses) {
if (a->family != f)
continue;
/* Equals our own address? nah, let's not use this scope. The local synthesizer will pick it up for us. */
if (exclude_own &&
in_addr_equal(f, &a->in_addr, &ia) > 0)
return DNS_SCOPE_NO;
if (a->prefixlen == UCHAR_MAX) /* don't know subnet mask */
continue;
/* Check if the address is in the local subnet */
r = in_addr_prefix_covers(f, &a->in_addr, a->prefixlen, &ia);
if (r < 0)
log_debug_errno(r, "Failed to determine whether link address covers lookup address '%s': %m", domain);
if (r > 0)
/* Note that we only claim zero labels match. This is so that this is at the same
* priority a DNS scope with "." as routing domain is. */
return DNS_SCOPE_YES_BASE + 0;
}
return _DNS_SCOPE_MATCH_INVALID;
}
DnsScopeMatch dns_scope_good_domain(
DnsScope *s,
int ifindex,
@ -505,7 +564,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
@ -533,6 +592,7 @@ DnsScopeMatch dns_scope_good_domain(
case DNS_PROTOCOL_DNS: {
bool has_search_domains = false;
DnsScopeMatch m;
int n_best = -1;
/* Never route things to scopes that lack DNS servers */
@ -579,6 +639,13 @@ DnsScopeMatch dns_scope_good_domain(
dns_name_endswith(domain, "local") > 0)
return DNS_SCOPE_NO;
/* If the IP address to look up matches the local subnet, then implicity synthesizes
* DNS_SCOPE_YES_BASE + 0 on this interface, i.e. preferably resolve IP addresses via the DNS
* server belonging to this interface. */
m = match_subnet_reverse_lookups(s, domain, false);
if (m >= 0)
return m;
/* If there was no match at all, then see if this scope is suitable as default route. */
if (!dns_scope_is_default_route(s))
return DNS_SCOPE_NO;
@ -593,6 +660,10 @@ DnsScopeMatch dns_scope_good_domain(
if (m >= 0)
return m;
m = match_subnet_reverse_lookups(s, domain, true);
if (m >= 0)
return m;
if ((s->family == AF_INET && dns_name_endswith(domain, "in-addr.arpa") > 0) ||
(s->family == AF_INET6 && dns_name_endswith(domain, "ip6.arpa") > 0))
return DNS_SCOPE_MAYBE;
@ -612,6 +683,10 @@ DnsScopeMatch dns_scope_good_domain(
if (m >= 0)
return m;
m = match_subnet_reverse_lookups(s, domain, true);
if (m >= 0)
return m;
if ((s->family == AF_INET && dns_name_endswith(domain, "in-addr.arpa") > 0) ||
(s->family == AF_INET6 && dns_name_endswith(domain, "ip6.arpa") > 0))
return DNS_SCOPE_MAYBE;

View File

@ -281,16 +281,15 @@ void dns_server_packet_received(DnsServer *s, int protocol, DnsServerFeatureLeve
if (s->packet_bad_opt && level >= DNS_SERVER_FEATURE_LEVEL_EDNS0)
level = DNS_SERVER_FEATURE_LEVEL_EDNS0 - 1;
/* Even if we successfully receive a reply to a request announcing support for large packets,
that does not mean we can necessarily receive large packets. */
/* Even if we successfully receive a reply to a request announcing support for large packets, that
* does not mean we can necessarily receive large packets. */
if (level == DNS_SERVER_FEATURE_LEVEL_LARGE)
level = DNS_SERVER_FEATURE_LEVEL_LARGE - 1;
dns_server_verified(s, level);
/* Remember the size of the largest UDP packet we received from a server,
we know that we can always announce support for packets with at least
this size. */
/* Remember the size of the largest UDP packet we received from a server, we know that we can always
* announce support for packets with at least this size. */
if (protocol == IPPROTO_UDP && s->received_udp_packet_max < size)
s->received_udp_packet_max = size;
}
@ -299,15 +298,16 @@ void dns_server_packet_lost(DnsServer *s, int protocol, DnsServerFeatureLevel le
assert(s);
assert(s->manager);
if (s->possible_feature_level == level) {
if (protocol == IPPROTO_UDP)
s->n_failed_udp++;
else if (protocol == IPPROTO_TCP) {
if (DNS_SERVER_FEATURE_LEVEL_IS_TLS(level))
s->n_failed_tls++;
else
s->n_failed_tcp++;
}
if (s->possible_feature_level != level)
return;
if (protocol == IPPROTO_UDP)
s->n_failed_udp++;
else if (protocol == IPPROTO_TCP) {
if (DNS_SERVER_FEATURE_LEVEL_IS_TLS(level))
s->n_failed_tls++;
else
s->n_failed_tcp++;
}
}

View File

@ -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;
}
@ -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" :
(t->answer_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,12 @@ 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);
if (t && t->stream == s) /* Validate that the stream we got this on actually is the stream the
* transaction was using. */
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));
@ -793,7 +799,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,
@ -990,7 +996,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);
@ -1231,7 +1237,8 @@ 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);
SET_FLAG(t->answer_query_flags, SD_RESOLVED_CONFIDENTIAL, encrypted);
r = dns_transaction_fix_rcode(t);
if (r < 0)
@ -1315,7 +1322,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 +1526,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|SD_RESOLVED_CONFIDENTIAL, true);
dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS);
return 0;
}
@ -1538,7 +1545,8 @@ 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);
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 +1567,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|SD_RESOLVED_CONFIDENTIAL, true);
dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS);
return 0;
}
@ -1582,7 +1590,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 +2574,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 +2626,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 +2650,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 +2794,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 +2838,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 +2854,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 +2945,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 +3247,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 +3335,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 +3358,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 +3368,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 +3377,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 +3393,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));
}

View File

@ -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 */
@ -148,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);
@ -172,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_;

View File

@ -296,6 +296,8 @@ static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, voi
}
}
bus_client_log(message, "DNS server change");
dns_server_mark_all(l->dns_servers);
for (size_t i = 0; i < n; i++) {
@ -404,6 +406,8 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_
if (r == 0)
return 1; /* Polkit will call us back */
bus_client_log(message, "dns domains change");
dns_search_domain_mark_all(l->search_domains);
for (;;) {
@ -477,6 +481,8 @@ int bus_link_method_set_default_route(sd_bus_message *message, void *userdata, s
if (r == 0)
return 1; /* Polkit will call us back */
bus_client_log(message, "dns default route change");
if (l->default_route != b) {
l->default_route = b;
@ -523,6 +529,8 @@ int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_er
if (r == 0)
return 1; /* Polkit will call us back */
bus_client_log(message, "LLMNR change");
l->llmnr_support = mode;
link_allocate_scopes(l);
link_add_rrs(l, false);
@ -568,6 +576,8 @@ int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_err
if (r == 0)
return 1; /* Polkit will call us back */
bus_client_log(message, "mDNS change");
l->mdns_support = mode;
link_allocate_scopes(l);
link_add_rrs(l, false);
@ -613,6 +623,8 @@ int bus_link_method_set_dns_over_tls(sd_bus_message *message, void *userdata, sd
if (r == 0)
return 1; /* Polkit will call us back */
bus_client_log(message, "D-o-T change");
link_set_dns_over_tls_mode(l, mode);
(void) link_save_user(l);
@ -657,6 +669,8 @@ int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_e
if (r == 0)
return 1; /* Polkit will call us back */
bus_client_log(message, "DNSSEC change");
link_set_dnssec_mode(l, mode);
(void) link_save_user(l);
@ -715,6 +729,8 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v
if (r == 0)
return 1; /* Polkit will call us back */
bus_client_log(message, "DNSSEC NTA change");
set_free_free(l->dnssec_negative_trust_anchors);
l->dnssec_negative_trust_anchors = TAKE_PTR(ns);
@ -748,6 +764,8 @@ int bus_link_method_revert(sd_bus_message *message, void *userdata, sd_bus_error
if (r == 0)
return 1; /* Polkit will call us back */
bus_client_log(message, "revert");
link_flush_settings(l);
link_allocate_scopes(l);
link_add_rrs(l, false);

View File

@ -802,6 +802,7 @@ int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr
.family = family,
.in_addr = *in_addr,
.link = l,
.prefixlen = UCHAR_MAX,
};
LIST_PREPEND(addresses, l->addresses, a);
@ -1094,6 +1095,7 @@ fail:
int link_address_update_rtnl(LinkAddress *a, sd_netlink_message *m) {
int r;
assert(a);
assert(m);
@ -1101,7 +1103,8 @@ int link_address_update_rtnl(LinkAddress *a, sd_netlink_message *m) {
if (r < 0)
return r;
sd_rtnl_message_addr_get_scope(m, &a->scope);
(void) sd_rtnl_message_addr_get_prefixlen(m, &a->prefixlen);
(void) sd_rtnl_message_addr_get_scope(m, &a->scope);
link_allocate_scopes(a->link);
link_add_rrs(a->link, false);

View File

@ -23,6 +23,7 @@ struct LinkAddress {
int family;
union in_addr_union in_addr;
unsigned char prefixlen;
unsigned char flags, scope;

View File

@ -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));

View File

@ -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);

View File

@ -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,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)))));
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) {
@ -440,7 +441,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");