summaryrefslogtreecommitdiff
path: root/src/resolve
diff options
context:
space:
mode:
Diffstat (limited to 'src/resolve')
-rw-r--r--src/resolve/.gitignore6
l---------src/resolve/Makefile1
-rw-r--r--src/resolve/meson.build12
-rw-r--r--src/resolve/resolve-tool.c79
-rw-r--r--src/resolve/resolved-bus.c15
-rw-r--r--src/resolve/resolved-conf.c2
-rw-r--r--src/resolve/resolved-dns-dnssec.c8
-rw-r--r--src/resolve/resolved-dns-packet.c27
-rw-r--r--src/resolve/resolved-dns-packet.h22
-rw-r--r--src/resolve/resolved-dns-query.c11
-rw-r--r--src/resolve/resolved-dns-scope.c6
-rw-r--r--src/resolve/resolved-dns-server.c86
-rw-r--r--src/resolve/resolved-dns-server.h5
-rw-r--r--src/resolve/resolved-dns-stream.c8
-rw-r--r--src/resolve/resolved-dns-stub.c58
-rw-r--r--src/resolve/resolved-dns-synthesize.c97
-rw-r--r--src/resolve/resolved-dns-transaction.c7
-rw-r--r--src/resolve/resolved-dns-trust-anchor.c2
-rw-r--r--src/resolve/resolved-link.c53
-rw-r--r--src/resolve/resolved-link.h2
-rw-r--r--src/resolve/resolved-llmnr.c2
-rw-r--r--src/resolve/resolved-manager.c51
-rw-r--r--src/resolve/resolved-manager.h2
-rw-r--r--src/resolve/resolved-mdns.c18
-rw-r--r--src/resolve/resolved-resolv-conf.c40
-rw-r--r--src/resolve/resolved.c21
-rw-r--r--src/resolve/test-dns-packet.c4
-rw-r--r--src/resolve/test-dnssec-complex.c2
-rw-r--r--src/resolve/test-dnssec.c4
-rw-r--r--src/resolve/test-resolved-packet.c7
30 files changed, 469 insertions, 189 deletions
diff --git a/src/resolve/.gitignore b/src/resolve/.gitignore
deleted file mode 100644
index f0835923b7..0000000000
--- a/src/resolve/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-/resolved-gperf.c
-/resolved.conf
-/dns_type-from-name.gperf
-/dns_type-from-name.h
-/dns_type-list.txt
-/dns_type-to-name.h
diff --git a/src/resolve/Makefile b/src/resolve/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/resolve/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/resolve/meson.build b/src/resolve/meson.build
index fe228784fa..75e654e60d 100644
--- a/src/resolve/meson.build
+++ b/src/resolve/meson.build
@@ -123,7 +123,7 @@ systemd_resolve_sources = (basic_dns_sources +
systemd_resolve_only_sources +
dns_type_headers)
-if conf.get('ENABLE_RESOLVED', false)
+if conf.get('ENABLE_RESOLVE') == 1
install_data('org.freedesktop.resolve1.conf',
install_dir : dbuspolicydir)
install_data('org.freedesktop.resolve1.service',
@@ -149,7 +149,7 @@ tests += [
[libgcrypt,
libgpg_error,
libm],
- 'ENABLE_RESOLVED'],
+ 'ENABLE_RESOLVE'],
[['src/resolve/test-dns-packet.c',
basic_dns_sources,
@@ -158,7 +158,7 @@ tests += [
[libgcrypt,
libgpg_error,
libm],
- 'ENABLE_RESOLVED'],
+ 'ENABLE_RESOLVE'],
[['src/resolve/test-resolved-packet.c',
basic_dns_sources,
@@ -167,7 +167,7 @@ tests += [
[libgcrypt,
libgpg_error,
libm],
- 'ENABLE_RESOLVED'],
+ 'ENABLE_RESOLVE'],
[['src/resolve/test-dnssec.c',
basic_dns_sources,
@@ -176,12 +176,12 @@ tests += [
[libgcrypt,
libgpg_error,
libm],
- 'ENABLE_RESOLVED'],
+ 'ENABLE_RESOLVE'],
[['src/resolve/test-dnssec-complex.c',
'src/resolve/dns-type.c',
dns_type_headers],
[],
[],
- 'ENABLE_RESOLVED', 'manual'],
+ 'ENABLE_RESOLVE', 'manual'],
]
diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c
index c62058917f..708378573f 100644
--- a/src/resolve/resolve-tool.c
+++ b/src/resolve/resolve-tool.c
@@ -72,6 +72,7 @@ static enum {
MODE_STATISTICS,
MODE_RESET_STATISTICS,
MODE_FLUSH_CACHES,
+ MODE_RESET_SERVER_FEATURES,
MODE_STATUS,
} arg_mode = MODE_RESOLVE_HOST;
@@ -357,7 +358,7 @@ static int output_rr_packet(const void *d, size_t l, int ifindex) {
int r;
char ifname[IF_NAMESIZE] = "";
- r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
+ r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX);
if (r < 0)
return log_oom();
@@ -1055,6 +1056,24 @@ static int flush_caches(sd_bus *bus) {
return 0;
}
+static int reset_server_features(sd_bus *bus) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ int r;
+
+ r = sd_bus_call_method(bus,
+ "org.freedesktop.resolve1",
+ "/org/freedesktop/resolve1",
+ "org.freedesktop.resolve1.Manager",
+ "ResetServerFeatures",
+ &error,
+ NULL,
+ NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to reset server features: %s", bus_error_message(&error, r));
+
+ return 0;
+}
+
static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
char ***l = userdata;
int r;
@@ -1588,6 +1607,8 @@ static void help(void) {
" --reset-statistics Reset resolver statistics\n"
" --status Show link and server status\n"
" --flush-caches Flush all local DNS caches\n"
+ " --reset-server-features\n"
+ " Forget learnt DNS server feature levels\n"
, program_invocation_short_name);
}
@@ -1607,30 +1628,32 @@ static int parse_argv(int argc, char *argv[]) {
ARG_RESET_STATISTICS,
ARG_STATUS,
ARG_FLUSH_CACHES,
+ ARG_RESET_SERVER_FEATURES,
ARG_NO_PAGER,
};
static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
- { "type", required_argument, NULL, 't' },
- { "class", required_argument, NULL, 'c' },
- { "legend", required_argument, NULL, ARG_LEGEND },
- { "interface", required_argument, NULL, 'i' },
- { "protocol", required_argument, NULL, 'p' },
- { "cname", required_argument, NULL, ARG_CNAME },
- { "service", no_argument, NULL, ARG_SERVICE },
- { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
- { "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
- { "openpgp", no_argument, NULL, ARG_OPENPGP },
- { "tlsa", optional_argument, NULL, ARG_TLSA },
- { "raw", optional_argument, NULL, ARG_RAW },
- { "search", required_argument, NULL, ARG_SEARCH },
- { "statistics", no_argument, NULL, ARG_STATISTICS, },
- { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS },
- { "status", no_argument, NULL, ARG_STATUS },
- { "flush-caches", no_argument, NULL, ARG_FLUSH_CACHES },
- { "no-pager", no_argument, NULL, ARG_NO_PAGER },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { "type", required_argument, NULL, 't' },
+ { "class", required_argument, NULL, 'c' },
+ { "legend", required_argument, NULL, ARG_LEGEND },
+ { "interface", required_argument, NULL, 'i' },
+ { "protocol", required_argument, NULL, 'p' },
+ { "cname", required_argument, NULL, ARG_CNAME },
+ { "service", no_argument, NULL, ARG_SERVICE },
+ { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
+ { "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
+ { "openpgp", no_argument, NULL, ARG_OPENPGP },
+ { "tlsa", optional_argument, NULL, ARG_TLSA },
+ { "raw", optional_argument, NULL, ARG_RAW },
+ { "search", required_argument, NULL, ARG_SEARCH },
+ { "statistics", no_argument, NULL, ARG_STATISTICS, },
+ { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS },
+ { "status", no_argument, NULL, ARG_STATUS },
+ { "flush-caches", no_argument, NULL, ARG_FLUSH_CACHES },
+ { "reset-server-features", no_argument, NULL, ARG_RESET_SERVER_FEATURES },
+ { "no-pager", no_argument, NULL, ARG_NO_PAGER },
{}
};
@@ -1814,6 +1837,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_mode = MODE_FLUSH_CACHES;
break;
+ case ARG_RESET_SERVER_FEATURES:
+ arg_mode = MODE_RESET_SERVER_FEATURES;
+ break;
+
case ARG_STATUS:
arg_mode = MODE_STATUS;
break;
@@ -1999,6 +2026,16 @@ int main(int argc, char **argv) {
r = flush_caches(bus);
break;
+ case MODE_RESET_SERVER_FEATURES:
+ if (argc > optind) {
+ log_error("Too many arguments.");
+ r = -EINVAL;
+ goto finish;
+ }
+
+ r = reset_server_features(bus);
+ break;
+
case MODE_STATUS:
if (argc > optind) {
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c
index 5aa2348576..c6f14eb416 100644
--- a/src/resolve/resolved-bus.c
+++ b/src/resolve/resolved-bus.c
@@ -1569,6 +1569,17 @@ static int bus_method_flush_caches(sd_bus_message *message, void *userdata, sd_b
return sd_bus_reply_method_return(message, NULL);
}
+static int bus_method_reset_server_features(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+
+ assert(message);
+ assert(m);
+
+ manager_reset_server_features(m);
+
+ return sd_bus_reply_method_return(message, NULL);
+}
+
static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), 0),
@@ -1587,6 +1598,7 @@ static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_METHOD("ResolveService", "isssit", "a(qqqsa(iiay)s)aayssst", bus_method_resolve_service, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ResetStatistics", NULL, NULL, bus_method_reset_statistics, 0),
SD_BUS_METHOD("FlushCaches", NULL, NULL, bus_method_flush_caches, 0),
+ SD_BUS_METHOD("ResetServerFeatures", NULL, NULL, bus_method_reset_server_features, 0),
SD_BUS_METHOD("GetLink", "i", "o", bus_method_get_link, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, 0),
SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_domains, 0),
@@ -1644,8 +1656,7 @@ int manager_connect_bus(Manager *m) {
r = sd_bus_default_system(&m->bus);
if (r < 0) {
/* We failed to connect? Yuck, we must be in early
- * boot. Let's try in 5s again. As soon as we have
- * kdbus we can stop doing this... */
+ * boot. Let's try in 5s again. */
log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m");
diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c
index 75636e0e56..3cf4261ff0 100644
--- a/src/resolve/resolved-conf.c
+++ b/src/resolve/resolved-conf.c
@@ -246,7 +246,7 @@ int manager_parse_config_file(Manager *m) {
return r;
}
-#ifndef HAVE_GCRYPT
+#if ! HAVE_GCRYPT
if (m->dnssec_mode != DNSSEC_NO) {
log_warning("DNSSEC option cannot be enabled or set to allow-downgrade when systemd-resolved is built without gcrypt support. Turning off DNSSEC support.");
m->dnssec_mode = DNSSEC_NO;
diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c
index eddab58a81..33bb5a1f95 100644
--- a/src/resolve/resolved-dns-dnssec.c
+++ b/src/resolve/resolved-dns-dnssec.c
@@ -17,7 +17,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
#include <gcrypt.h>
#endif
@@ -125,7 +125,7 @@ int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) {
return (int) c;
}
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
static int rr_compare(const void *a, const void *b) {
DnsResourceRecord **x = (DnsResourceRecord**) a, **y = (DnsResourceRecord**) b;
@@ -1247,10 +1247,10 @@ static int nsec3_is_good(DnsResourceRecord *rr, DnsResourceRecord *nsec3) {
/* Ignore NSEC3 RRs generated from wildcards. If these NSEC3 RRs weren't correctly signed we can't make this
* check (since rr->n_skip_labels_source is -1), but that's OK, as we won't trust them anyway in that case. */
- if (rr->n_skip_labels_source != 0 && rr->n_skip_labels_source != (unsigned) -1)
+ if (!IN_SET(rr->n_skip_labels_source, 0, (unsigned) -1))
return 0;
/* Ignore NSEC3 RRs that are located anywhere else than one label below the zone */
- if (rr->n_skip_labels_signer != 1 && rr->n_skip_labels_signer != (unsigned) -1)
+ if (!IN_SET(rr->n_skip_labels_signer, 1, (unsigned) -1))
return 0;
if (!nsec3)
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index 49a04615d4..e2f227bfc6 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -28,7 +28,6 @@
#define EDNS0_OPT_DO (1<<15)
-#define DNS_PACKET_SIZE_START 512u
assert_cc(DNS_PACKET_SIZE_START > DNS_PACKET_HEADER_SIZE)
typedef struct DnsPacketRewinder {
@@ -44,11 +43,20 @@ static void rewind_dns_packet(DnsPacketRewinder *rewinder) {
#define INIT_REWINDER(rewinder, p) do { rewinder.packet = p; rewinder.saved_rindex = p->rindex; } while (0)
#define CANCEL_REWINDER(rewinder) do { rewinder.packet = NULL; } while (0)
-int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t min_alloc_dsize) {
+int dns_packet_new(
+ DnsPacket **ret,
+ DnsProtocol protocol,
+ size_t min_alloc_dsize,
+ size_t max_size) {
+
DnsPacket *p;
size_t a;
assert(ret);
+ assert(max_size >= DNS_PACKET_HEADER_SIZE);
+
+ if (max_size > DNS_PACKET_SIZE_MAX)
+ max_size = DNS_PACKET_SIZE_MAX;
/* The caller may not check what is going to be truly allocated, so do not allow to
* allocate a DNS packet bigger than DNS_PACKET_SIZE_MAX.
@@ -71,8 +79,8 @@ int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t min_alloc_dsize
a = PAGE_ALIGN(ALIGN(sizeof(DnsPacket)) + a) - ALIGN(sizeof(DnsPacket));
/* make sure we never allocate more than useful */
- if (a > DNS_PACKET_SIZE_MAX)
- a = DNS_PACKET_SIZE_MAX;
+ if (a > max_size)
+ a = max_size;
p = malloc0(ALIGN(sizeof(DnsPacket)) + a);
if (!p)
@@ -80,6 +88,7 @@ int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t min_alloc_dsize
p->size = p->rindex = DNS_PACKET_HEADER_SIZE;
p->allocated = a;
+ p->max_size = max_size;
p->protocol = protocol;
p->opt_start = p->opt_size = (size_t) -1;
p->n_ref = 1;
@@ -145,7 +154,7 @@ int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t min_alloc
assert(ret);
- r = dns_packet_new(&p, protocol, min_alloc_dsize);
+ r = dns_packet_new(&p, protocol, min_alloc_dsize, DNS_PACKET_SIZE_MAX);
if (r < 0)
return r;
@@ -314,11 +323,13 @@ static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start
assert(p);
if (p->size + add > p->allocated) {
- size_t a;
+ size_t a, ms;
a = PAGE_ALIGN((p->size + add) * 2);
- if (a > DNS_PACKET_SIZE_MAX)
- a = DNS_PACKET_SIZE_MAX;
+
+ ms = dns_packet_size_max(p);
+ if (a > ms)
+ a = ms;
if (p->size + add > a)
return -EMSGSIZE;
diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h
index a65d6d38cf..b873c0f745 100644
--- a/src/resolve/resolved-dns-packet.h
+++ b/src/resolve/resolved-dns-packet.h
@@ -56,10 +56,14 @@ struct DnsPacketHeader {
#define UDP_PACKET_HEADER_SIZE (sizeof(struct iphdr) + sizeof(struct udphdr))
/* The various DNS protocols deviate in how large a packet can grow,
- but the TCP transport has a 16bit size field, hence that appears to
- be the absolute maximum. */
+ * but the TCP transport has a 16bit size field, hence that appears to
+ * be the absolute maximum. */
#define DNS_PACKET_SIZE_MAX 0xFFFFu
+/* The default size to use for allocation when we don't know how large
+ * the packet will turn out to be. */
+#define DNS_PACKET_SIZE_START 512u
+
/* RFC 1035 say 512 is the maximum, for classic unicast DNS */
#define DNS_PACKET_UNICAST_SIZE_MAX 512u
@@ -69,7 +73,7 @@ struct DnsPacketHeader {
struct DnsPacket {
int n_ref;
DnsProtocol protocol;
- size_t size, allocated, rindex;
+ size_t size, allocated, rindex, max_size;
void *_data; /* don't access directly, use DNS_PACKET_DATA()! */
Hashmap *names; /* For name compression */
size_t opt_start, opt_size;
@@ -183,7 +187,7 @@ static inline unsigned DNS_PACKET_RRCOUNT(DnsPacket *p) {
(unsigned) DNS_PACKET_ARCOUNT(p);
}
-int dns_packet_new(DnsPacket **p, DnsProtocol protocol, size_t min_alloc_dsize);
+int dns_packet_new(DnsPacket **p, DnsProtocol protocol, size_t min_alloc_dsize, size_t max_size);
int dns_packet_new_query(DnsPacket **p, DnsProtocol protocol, size_t min_alloc_dsize, bool dnssec_checking_disabled);
void dns_packet_set_flags(DnsPacket *p, bool dnssec_checking_disabled, bool truncated);
@@ -299,3 +303,13 @@ static inline uint64_t SD_RESOLVED_FLAGS_MAKE(DnsProtocol protocol, int family,
return f;
}
}
+
+static inline size_t dns_packet_size_max(DnsPacket *p) {
+ assert(p);
+
+ /* Why not insist on a fully initialized max_size during DnsPacket construction? Well, this way it's easy to
+ * allocate a transient, throw-away DnsPacket on the stack by simple zero initialization, without having to
+ * deal with explicit field initialization. */
+
+ return p->max_size != 0 ? p->max_size : DNS_PACKET_SIZE_MAX;
+}
diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c
index 2b091e6c45..c2b29bc452 100644
--- a/src/resolve/resolved-dns-query.c
+++ b/src/resolve/resolved-dns-query.c
@@ -623,7 +623,18 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
q->question_utf8,
q->ifindex,
&answer);
+ if (r == -ENXIO) {
+ /* If we get ENXIO this tells us to generate NXDOMAIN unconditionally. */
+ dns_query_reset_answer(q);
+ 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;
+ *state = DNS_TRANSACTION_RCODE_FAILURE;
+
+ return 0;
+ }
if (r <= 0)
return r;
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index ffaefbe3f2..ca54158898 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -632,7 +632,7 @@ int dns_scope_make_reply_packet(
dns_answer_isempty(soa))
return -EINVAL;
- r = dns_packet_new(&p, s->protocol, 0);
+ r = dns_packet_new(&p, s->protocol, 0, DNS_PACKET_SIZE_MAX);
if (r < 0)
return r;
@@ -818,7 +818,7 @@ static int dns_scope_make_conflict_packet(
assert(rr);
assert(ret);
- r = dns_packet_new(&p, s->protocol, 0);
+ r = dns_packet_new(&p, s->protocol, 0, DNS_PACKET_SIZE_MAX);
if (r < 0)
return r;
@@ -904,7 +904,7 @@ int dns_scope_notify_conflict(DnsScope *scope, DnsResourceRecord *rr) {
* messages, not all of them. That should be enough to
* indicate where there might be a conflict */
r = ordered_hashmap_put(scope->conflict_queue, rr->key, rr);
- if (r == -EEXIST || r == 0)
+ if (IN_SET(r, 0, -EEXIST))
return 0;
if (r < 0)
return log_debug_errno(r, "Failed to queue conflicting RR: %m");
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c
index b3d37525f4..1b61dea626 100644
--- a/src/resolve/resolved-dns-server.c
+++ b/src/resolve/resolved-dns-server.c
@@ -70,15 +70,12 @@ int dns_server_new(
s->n_ref = 1;
s->manager = m;
- s->verified_feature_level = _DNS_SERVER_FEATURE_LEVEL_INVALID;
- s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_BEST;
- s->features_grace_period_usec = DNS_SERVER_FEATURE_GRACE_PERIOD_MIN_USEC;
- s->received_udp_packet_max = DNS_PACKET_UNICAST_SIZE_MAX;
s->type = type;
s->family = family;
s->address = *in_addr;
s->ifindex = ifindex;
- s->resend_timeout = DNS_TIMEOUT_MIN_USEC;
+
+ dns_server_reset_features(s);
switch (type) {
@@ -828,6 +825,85 @@ void dns_server_flush_cache(DnsServer *s) {
dns_cache_flush(&scope->cache);
}
+void dns_server_reset_features(DnsServer *s) {
+ assert(s);
+
+ s->max_rtt = 0;
+ s->resend_timeout = DNS_TIMEOUT_MIN_USEC;
+
+ s->verified_feature_level = _DNS_SERVER_FEATURE_LEVEL_INVALID;
+ s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_BEST;
+
+ s->received_udp_packet_max = DNS_PACKET_UNICAST_SIZE_MAX;
+
+ s->packet_bad_opt = false;
+ s->packet_rrsig_missing = false;
+
+ s->features_grace_period_usec = DNS_SERVER_FEATURE_GRACE_PERIOD_MIN_USEC;
+
+ s->warned_downgrade = false;
+
+ dns_server_reset_counters(s);
+}
+
+void dns_server_reset_features_all(DnsServer *s) {
+ DnsServer *i;
+
+ LIST_FOREACH(servers, i, s)
+ dns_server_reset_features(i);
+}
+
+void dns_server_dump(DnsServer *s, FILE *f) {
+ assert(s);
+
+ if (!f)
+ f = stdout;
+
+ fputs("[Server ", f);
+ fputs(dns_server_string(s), f);
+ fputs(" type=", f);
+ fputs(dns_server_type_to_string(s->type), f);
+
+ if (s->type == DNS_SERVER_LINK) {
+ assert(s->link);
+
+ fputs(" interface=", f);
+ fputs(s->link->name, f);
+ }
+
+ fputs("]\n", f);
+
+ fputs("\tVerified feature level: ", f);
+ fputs(strna(dns_server_feature_level_to_string(s->verified_feature_level)), f);
+ fputc('\n', f);
+
+ fputs("\tPossible feature level: ", f);
+ fputs(strna(dns_server_feature_level_to_string(s->possible_feature_level)), f);
+ fputc('\n', f);
+
+ fputs("\tDNSSEC Mode: ", f);
+ fputs(strna(dnssec_mode_to_string(dns_server_get_dnssec_mode(s))), f);
+ fputc('\n', f);
+
+ fputs("\tCan do DNSSEC: ", f);
+ fputs(yes_no(dns_server_dnssec_supported(s)), f);
+ fputc('\n', f);
+
+ fprintf(f,
+ "\tMaximum UDP packet size received: %zu\n"
+ "\tFailed UDP attempts: %u\n"
+ "\tFailed TCP attempts: %u\n"
+ "\tSeen truncated packet: %s\n"
+ "\tSeen OPT RR getting lost: %s\n"
+ "\tSeen RRSIG RR missing: %s\n",
+ s->received_udp_packet_max,
+ s->n_failed_udp,
+ s->n_failed_tcp,
+ yes_no(s->packet_truncated),
+ yes_no(s->packet_bad_opt),
+ yes_no(s->packet_rrsig_missing));
+}
+
static const char* const dns_server_type_table[_DNS_SERVER_TYPE_MAX] = {
[DNS_SERVER_SYSTEM] = "system",
[DNS_SERVER_FALLBACK] = "fallback",
diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h
index bc95d53c6a..00edd47d9a 100644
--- a/src/resolve/resolved-dns-server.h
+++ b/src/resolve/resolved-dns-server.h
@@ -151,3 +151,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DnsServer*, dns_server_unref);
extern const struct hash_ops dns_server_hash_ops;
void dns_server_flush_cache(DnsServer *s);
+
+void dns_server_reset_features(DnsServer *s);
+void dns_server_reset_features_all(DnsServer *s);
+
+void dns_server_dump(DnsServer *s, FILE *f);
diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c
index 878bae47dc..5892534687 100644
--- a/src/resolve/resolved-dns-stream.c
+++ b/src/resolve/resolved-dns-stream.c
@@ -221,7 +221,7 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
ss = writev(fd, iov, 2);
if (ss < 0) {
- if (errno != EINTR && errno != EAGAIN)
+ if (!IN_SET(errno, EINTR, EAGAIN))
return dns_stream_complete(s, errno);
} else
s->n_written += ss;
@@ -243,7 +243,7 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
ss = read(fd, (uint8_t*) &s->read_size + s->n_read, sizeof(s->read_size) - s->n_read);
if (ss < 0) {
- if (errno != EINTR && errno != EAGAIN)
+ if (!IN_SET(errno, EINTR, EAGAIN))
return dns_stream_complete(s, errno);
} else if (ss == 0)
return dns_stream_complete(s, ECONNRESET);
@@ -260,7 +260,7 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
ssize_t ss;
if (!s->read_packet) {
- r = dns_packet_new(&s->read_packet, s->protocol, be16toh(s->read_size));
+ r = dns_packet_new(&s->read_packet, s->protocol, be16toh(s->read_size), DNS_PACKET_SIZE_MAX);
if (r < 0)
return dns_stream_complete(s, -r);
@@ -293,7 +293,7 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
(uint8_t*) DNS_PACKET_DATA(s->read_packet) + s->n_read - sizeof(s->read_size),
sizeof(s->read_size) + be16toh(s->read_size) - s->n_read);
if (ss < 0) {
- if (errno != EINTR && errno != EAGAIN)
+ if (!IN_SET(errno, EINTR, EAGAIN))
return dns_stream_complete(s, errno);
} else if (ss == 0)
return dns_stream_complete(s, ECONNRESET);
diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c
index 7afbfedfb0..5bc79a313e 100644
--- a/src/resolve/resolved-dns-stub.c
+++ b/src/resolve/resolved-dns-stub.c
@@ -30,9 +30,12 @@ static int manager_dns_stub_tcp_fd(Manager *m);
static int dns_stub_make_reply_packet(
DnsPacket **p,
+ size_t max_size,
DnsQuestion *q,
- DnsAnswer *answer) {
+ DnsAnswer *answer,
+ bool *ret_truncated) {
+ bool truncated = false;
DnsResourceRecord *rr;
unsigned c = 0;
int r;
@@ -43,7 +46,7 @@ static int dns_stub_make_reply_packet(
* roundtrips aren't expensive. */
if (!*p) {
- r = dns_packet_new(p, DNS_PROTOCOL_DNS, 0);
+ r = dns_packet_new(p, DNS_PROTOCOL_DNS, 0, max_size);
if (r < 0)
return r;
@@ -71,12 +74,21 @@ static int dns_stub_make_reply_packet(
continue;
add:
r = dns_packet_append_rr(*p, rr, 0, NULL, NULL);
+ if (r == -EMSGSIZE) {
+ truncated = true;
+ break;
+ }
if (r < 0)
return r;
c++;
}
+ if (ret_truncated)
+ *ret_truncated = truncated;
+ else if (truncated)
+ return -EMSGSIZE;
+
DNS_PACKET_HEADER(*p)->ancount = htobe16(be16toh(DNS_PACKET_HEADER(*p)->ancount) + c);
return 0;
@@ -86,6 +98,7 @@ static int dns_stub_finish_reply_packet(
DnsPacket *p,
uint16_t id,
int rcode,
+ bool tc, /* set the Truncated bit? */
bool add_opt, /* add an OPT RR to this packet? */
bool edns0_do, /* set the EDNS0 DNSSEC OK bit? */
bool ad) { /* set the DNSSEC authenticated data bit? */
@@ -110,14 +123,14 @@ static int dns_stub_finish_reply_packet(
DNS_PACKET_HEADER(p)->id = id;
DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
- 1 /* qr */,
- 0 /* opcode */,
- 0 /* aa */,
- 0 /* tc */,
- 1 /* rd */,
- 1 /* ra */,
+ 1 /* qr */,
+ 0 /* opcode */,
+ 0 /* aa */,
+ tc /* tc */,
+ 1 /* rd */,
+ 1 /* ra */,
ad /* ad */,
- 0 /* cd */,
+ 0 /* cd */,
rcode));
if (add_opt) {
@@ -149,12 +162,6 @@ static int dns_stub_send(Manager *m, DnsStream *s, DnsPacket *p, DnsPacket *repl
else {
int fd;
- /* Truncate the message to the right size */
- if (reply->size > DNS_PACKET_PAYLOAD_SIZE_MAX(p)) {
- dns_packet_truncate(reply, DNS_PACKET_UNICAST_SIZE_MAX);
- DNS_PACKET_HEADER(reply)->flags = htobe16(be16toh(DNS_PACKET_HEADER(reply)->flags) | DNS_PACKET_FLAG_TC);
- }
-
fd = manager_dns_stub_udp_fd(m);
if (fd < 0)
return log_debug_errno(fd, "Failed to get reply socket: %m");
@@ -178,11 +185,11 @@ static int dns_stub_send_failure(Manager *m, DnsStream *s, DnsPacket *p, int rco
assert(m);
assert(p);
- r = dns_stub_make_reply_packet(&reply, p->question, NULL);
+ r = dns_stub_make_reply_packet(&reply, DNS_PACKET_PAYLOAD_SIZE_MAX(p), p->question, NULL, NULL);
if (r < 0)
return log_debug_errno(r, "Failed to make failure packet: %m");
- r = dns_stub_finish_reply_packet(reply, DNS_PACKET_ID(p), rcode, !!p->opt, DNS_PACKET_DO(p), authenticated);
+ r = dns_stub_finish_reply_packet(reply, DNS_PACKET_ID(p), rcode, false, !!p->opt, DNS_PACKET_DO(p), authenticated);
if (r < 0)
return log_debug_errno(r, "Failed to build failure packet: %m");
@@ -197,9 +204,10 @@ static void dns_stub_query_complete(DnsQuery *q) {
switch (q->state) {
- case DNS_TRANSACTION_SUCCESS:
+ case DNS_TRANSACTION_SUCCESS: {
+ bool truncated;
- r = dns_stub_make_reply_packet(&q->reply_dns_packet, q->question_idna, q->answer);
+ r = dns_stub_make_reply_packet(&q->reply_dns_packet, DNS_PACKET_PAYLOAD_SIZE_MAX(q->request_dns_packet), q->question_idna, q->answer, &truncated);
if (r < 0) {
log_debug_errno(r, "Failed to build reply packet: %m");
break;
@@ -221,6 +229,7 @@ static void dns_stub_query_complete(DnsQuery *q) {
q->reply_dns_packet,
DNS_PACKET_ID(q->request_dns_packet),
q->answer_rcode,
+ truncated,
!!q->request_dns_packet->opt,
DNS_PACKET_DO(q->request_dns_packet),
dns_query_fully_authenticated(q));
@@ -231,6 +240,7 @@ static void dns_stub_query_complete(DnsQuery *q) {
(void) dns_stub_send(q->manager, q->request_dns_stream, q->request_dns_packet, q->reply_dns_packet);
break;
+ }
case DNS_TRANSACTION_RCODE_FAILURE:
(void) dns_stub_send_failure(q->manager, q->request_dns_stream, q->request_dns_packet, q->answer_rcode, dns_query_fully_authenticated(q));
@@ -467,7 +477,7 @@ static int on_dns_stub_stream(sd_event_source *s, int fd, uint32_t revents, void
cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
if (cfd < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return 0;
return -errno;
@@ -543,6 +553,14 @@ int manager_dns_stub_start(Manager *m) {
assert(m);
+ if (m->dns_stub_listener_mode == DNS_STUB_LISTENER_NO)
+ log_debug("Not creating stub listener.");
+ else
+ log_debug("Creating stub listener using %s.",
+ m->dns_stub_listener_mode == DNS_STUB_LISTENER_UDP ? "UDP" :
+ m->dns_stub_listener_mode == DNS_STUB_LISTENER_TCP ? "TCP" :
+ "UDP/TCP");
+
if (IN_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_YES, DNS_STUB_LISTENER_UDP))
r = manager_dns_stub_udp_fd(m);
diff --git a/src/resolve/resolved-dns-synthesize.c b/src/resolve/resolved-dns-synthesize.c
index e3003411f7..e8592a60d8 100644
--- a/src/resolve/resolved-dns-synthesize.c
+++ b/src/resolve/resolved-dns-synthesize.c
@@ -186,6 +186,7 @@ static int answer_add_addresses_ptr(
unsigned n_addresses,
int af, const union in_addr_union *match) {
+ bool added = false;
unsigned j;
int r;
@@ -215,9 +216,11 @@ static int answer_add_addresses_ptr(
r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED);
if (r < 0)
return r;
+
+ added = true;
}
- return 0;
+ return added;
}
static int synthesize_system_hostname_rr(Manager *m, const DnsResourceKey *key, int ifindex, DnsAnswer **answer) {
@@ -240,21 +243,23 @@ static int synthesize_system_hostname_rr(Manager *m, const DnsResourceKey *key,
/* If we have no local addresses then use ::1
* and 127.0.0.2 as local ones. */
- if (af == AF_INET || af == AF_UNSPEC)
+ if (IN_SET(af, AF_INET, AF_UNSPEC))
buffer[n++] = (struct local_address) {
.family = AF_INET,
.ifindex = dns_synthesize_ifindex(ifindex),
.address.in.s_addr = htobe32(0x7F000002),
};
- if (af == AF_INET6 || af == AF_UNSPEC)
+ if (IN_SET(af, AF_INET6, AF_UNSPEC))
buffer[n++] = (struct local_address) {
.family = AF_INET6,
.ifindex = dns_synthesize_ifindex(ifindex),
.address.in6 = in6addr_loopback,
};
- return answer_add_addresses_rr(answer, dns_resource_key_name(key), buffer, n);
+ return answer_add_addresses_rr(answer,
+ dns_resource_key_name(key),
+ buffer, n);
}
}
@@ -263,6 +268,7 @@ static int synthesize_system_hostname_rr(Manager *m, const DnsResourceKey *key,
static int synthesize_system_hostname_ptr(Manager *m, int af, const union in_addr_union *address, int ifindex, DnsAnswer **answer) {
_cleanup_free_ struct local_address *addresses = NULL;
+ bool added = false;
int n, r;
assert(m);
@@ -271,10 +277,13 @@ static int synthesize_system_hostname_ptr(Manager *m, int af, const union in_add
if (af == AF_INET && address->in.s_addr == htobe32(0x7F000002)) {
- /* Always map the IPv4 address 127.0.0.2 to the local
- * hostname, in addition to "localhost": */
+ /* Always map the IPv4 address 127.0.0.2 to the local hostname, in addition to "localhost": */
- r = dns_answer_reserve(answer, 3);
+ r = dns_answer_reserve(answer, 4);
+ if (r < 0)
+ return r;
+
+ r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->full_hostname, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
if (r < 0)
return r;
@@ -290,23 +299,37 @@ static int synthesize_system_hostname_ptr(Manager *m, int af, const union in_add
if (r < 0)
return r;
- return 0;
+ return 1;
}
n = local_addresses(m->rtnl, ifindex, af, &addresses);
- if (n < 0)
+ if (n <= 0)
return n;
+ r = answer_add_addresses_ptr(answer, m->full_hostname, addresses, n, af, address);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ added = true;
+
r = answer_add_addresses_ptr(answer, m->llmnr_hostname, addresses, n, af, address);
if (r < 0)
return r;
+ if (r > 0)
+ added = true;
+
+ r = answer_add_addresses_ptr(answer, m->mdns_hostname, addresses, n, af, address);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ added = true;
- return answer_add_addresses_ptr(answer, m->mdns_hostname, addresses, n, af, address);
+ return added;
}
static int synthesize_gateway_rr(Manager *m, const DnsResourceKey *key, int ifindex, DnsAnswer **answer) {
_cleanup_free_ struct local_address *addresses = NULL;
- int n = 0, af;
+ int n = 0, af, r;
assert(m);
assert(key);
@@ -315,11 +338,15 @@ static int synthesize_gateway_rr(Manager *m, const DnsResourceKey *key, int ifin
af = dns_type_to_af(key->type);
if (af >= 0) {
n = local_gateways(m->rtnl, ifindex, af, &addresses);
- if (n < 0)
- return n;
+ if (n <= 0)
+ return n; /* < 0 means: error; == 0 means we have no gateway */
}
- return answer_add_addresses_rr(answer, dns_resource_key_name(key), addresses, n);
+ r = answer_add_addresses_rr(answer, dns_resource_key_name(key), addresses, n);
+ if (r < 0)
+ return r;
+
+ return 1; /* > 0 means: we have some gateway */
}
static int synthesize_gateway_ptr(Manager *m, int af, const union in_addr_union *address, int ifindex, DnsAnswer **answer) {
@@ -331,10 +358,10 @@ static int synthesize_gateway_ptr(Manager *m, int af, const union in_addr_union
assert(answer);
n = local_gateways(m->rtnl, ifindex, af, &addresses);
- if (n < 0)
+ if (n <= 0)
return n;
- return answer_add_addresses_ptr(answer, "gateway", addresses, n, af, address);
+ return answer_add_addresses_ptr(answer, "_gateway", addresses, n, af, address);
}
int dns_synthesize_answer(
@@ -345,7 +372,7 @@ int dns_synthesize_answer(
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
DnsResourceKey *key;
- bool found = false;
+ bool found = false, nxdomain = false;
int r;
assert(m);
@@ -356,8 +383,7 @@ int dns_synthesize_answer(
const char *name;
int af;
- if (key->class != DNS_CLASS_IN &&
- key->class != DNS_CLASS_ANY)
+ if (!IN_SET(key->class, DNS_CLASS_IN, DNS_CLASS_ANY))
continue;
name = dns_resource_key_name(key);
@@ -379,6 +405,10 @@ int dns_synthesize_answer(
r = synthesize_gateway_rr(m, key, ifindex, &answer);
if (r < 0)
return log_error_errno(r, "Failed to synthesize gateway RRs: %m");
+ if (r == 0) { /* if we have no gateway return NXDOMAIN */
+ nxdomain = true;
+ continue;
+ }
} else if ((dns_name_endswith(name, "127.in-addr.arpa") > 0 && dns_name_equal(name, "2.0.0.127.in-addr.arpa") == 0) ||
dns_name_equal(name, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0) {
@@ -388,26 +418,35 @@ int dns_synthesize_answer(
return log_error_errno(r, "Failed to synthesize localhost PTR RRs: %m");
} else if (dns_name_address(name, &af, &address) > 0) {
+ int v, w;
- r = synthesize_system_hostname_ptr(m, af, &address, ifindex, &answer);
- if (r < 0)
+ v = synthesize_system_hostname_ptr(m, af, &address, ifindex, &answer);
+ if (v < 0)
return log_error_errno(r, "Failed to synthesize system hostname PTR RR: %m");
- r = synthesize_gateway_ptr(m, af, &address, ifindex, &answer);
- if (r < 0)
+ w = synthesize_gateway_ptr(m, af, &address, ifindex, &answer);
+ if (w < 0)
return log_error_errno(r, "Failed to synthesize gateway hostname PTR RR: %m");
+
+ if (v == 0 && w == 0) /* This IP address is neither a local one nor a gateway */
+ continue;
+
} else
continue;
found = true;
}
- r = found;
+ if (found) {
- if (ret) {
- *ret = answer;
- answer = NULL;
- }
+ if (ret) {
+ *ret = answer;
+ answer = NULL;
+ }
+
+ return 1;
+ } else if (nxdomain)
+ return -ENXIO;
- return r;
+ return 0;
}
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 3075f62b5e..3cda429c3c 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -190,7 +190,7 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key)
return -EOPNOTSUPP;
/* We only support the IN class */
- if (key->class != DNS_CLASS_IN && key->class != DNS_CLASS_ANY)
+ if (!IN_SET(key->class, DNS_CLASS_IN, DNS_CLASS_ANY))
return -EOPNOTSUPP;
if (hashmap_size(s->manager->dns_transactions) >= TRANSACTIONS_MAX)
@@ -1528,8 +1528,7 @@ int dns_transaction_go(DnsTransaction *t) {
af_to_name_short(t->scope->family));
if (!t->initial_jitter_scheduled &&
- (t->scope->protocol == DNS_PROTOCOL_LLMNR ||
- t->scope->protocol == DNS_PROTOCOL_MDNS)) {
+ IN_SET(t->scope->protocol, DNS_PROTOCOL_LLMNR, DNS_PROTOCOL_MDNS)) {
usec_t jitter, accuracy;
/* RFC 4795 Section 2.7 suggests all queries should be
@@ -1594,7 +1593,7 @@ int dns_transaction_go(DnsTransaction *t) {
log_debug("Sending query via TCP since it is too large.");
else if (r == -EAGAIN)
log_debug("Sending query via TCP since server doesn't support UDP.");
- if (r == -EMSGSIZE || r == -EAGAIN)
+ if (IN_SET(r, -EMSGSIZE, -EAGAIN))
r = dns_transaction_open_tcp(t);
}
diff --git a/src/resolve/resolved-dns-trust-anchor.c b/src/resolve/resolved-dns-trust-anchor.c
index dda9875063..e169c8f02f 100644
--- a/src/resolve/resolved-dns-trust-anchor.c
+++ b/src/resolve/resolved-dns-trust-anchor.c
@@ -435,7 +435,7 @@ static int dns_trust_anchor_load_files(
assert(suffix);
assert(loader);
- r = conf_files_list_nulstr(&files, suffix, NULL, trust_anchor_dirs);
+ r = conf_files_list_nulstr(&files, suffix, NULL, 0, trust_anchor_dirs);
if (r < 0)
return log_error_errno(r, "Failed to enumerate %s trust anchor files: %m", suffix);
diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c
index 61a3f20362..3d26831b06 100644
--- a/src/resolve/resolved-link.c
+++ b/src/resolve/resolved-link.c
@@ -111,13 +111,30 @@ Link *link_free(Link *l) {
}
void link_allocate_scopes(Link *l) {
+ bool unicast_relevant;
int r;
assert(l);
- if (link_relevant(l, AF_UNSPEC, false) &&
- l->dns_servers) {
+ /* If a link that used to be relevant is no longer, or a link that did not use to be relevant now becomes
+ * relevant, let's reinit the learnt global DNS server information, since we might talk to different servers
+ * now, even if they have the same addresses as before. */
+
+ unicast_relevant = link_relevant(l, AF_UNSPEC, false);
+ if (unicast_relevant != l->unicast_relevant) {
+ l->unicast_relevant = unicast_relevant;
+
+ dns_server_reset_features_all(l->manager->fallback_dns_servers);
+ dns_server_reset_features_all(l->manager->dns_servers);
+ }
+
+ /* And now, allocate all scopes that makes sense now if we didn't have them yet, and drop those which we don't
+ * need anymore */
+
+ if (unicast_relevant && l->dns_servers) {
if (!l->unicast_scope) {
+ dns_server_reset_features_all(l->dns_servers);
+
r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
if (r < 0)
log_warning_errno(r, "Failed to allocate DNS scope: %m");
@@ -313,8 +330,8 @@ void link_set_dnssec_mode(Link *l, DnssecMode mode) {
assert(l);
-#ifndef HAVE_GCRYPT
- if (mode == DNSSEC_YES || mode == DNSSEC_ALLOW_DOWNGRADE)
+#if ! HAVE_GCRYPT
+ if (IN_SET(mode, DNSSEC_YES, DNSSEC_ALLOW_DOWNGRADE))
log_warning("DNSSEC option for the link cannot be enabled or set to allow-downgrade when systemd-resolved is built without gcrypt support. Turning off DNSSEC support.");
return;
#endif
@@ -1050,7 +1067,7 @@ int link_save_user(Link *l) {
if (r < 0)
goto fail;
- fputs("# This is private data. Do not parse.\n", f);
+ fputs_unlocked("# This is private data. Do not parse.\n", f);
v = resolve_support_to_string(l->llmnr_support);
if (v)
@@ -1067,11 +1084,11 @@ int link_save_user(Link *l) {
if (l->dns_servers) {
DnsServer *server;
- fputs("SERVERS=", f);
+ fputs_unlocked("SERVERS=", f);
LIST_FOREACH(servers, server, l->dns_servers) {
if (server != l->dns_servers)
- fputc(' ', f);
+ fputc_unlocked(' ', f);
v = dns_server_string(server);
if (!v) {
@@ -1079,26 +1096,26 @@ int link_save_user(Link *l) {
goto fail;
}
- fputs(v, f);
+ fputs_unlocked(v, f);
}
- fputc('\n', f);
+ fputc_unlocked('\n', f);
}
if (l->search_domains) {
DnsSearchDomain *domain;
- fputs("DOMAINS=", f);
+ fputs_unlocked("DOMAINS=", f);
LIST_FOREACH(domains, domain, l->search_domains) {
if (domain != l->search_domains)
- fputc(' ', f);
+ fputc_unlocked(' ', f);
if (domain->route_only)
- fputc('~', f);
+ fputc_unlocked('~', f);
- fputs(DNS_SEARCH_DOMAIN_NAME(domain), f);
+ fputs_unlocked(DNS_SEARCH_DOMAIN_NAME(domain), f);
}
- fputc('\n', f);
+ fputc_unlocked('\n', f);
}
if (!set_isempty(l->dnssec_negative_trust_anchors)) {
@@ -1106,16 +1123,16 @@ int link_save_user(Link *l) {
Iterator i;
char *nta;
- fputs("NTAS=", f);
+ fputs_unlocked("NTAS=", f);
SET_FOREACH(nta, l->dnssec_negative_trust_anchors, i) {
if (space)
- fputc(' ', f);
+ fputc_unlocked(' ', f);
- fputs(nta, f);
+ fputs_unlocked(nta, f);
space = true;
}
- fputc('\n', f);
+ fputc_unlocked('\n', f);
}
r = fflush_and_check(f);
diff --git a/src/resolve/resolved-link.h b/src/resolve/resolved-link.h
index 55a56b7906..c20b8b6d29 100644
--- a/src/resolve/resolved-link.h
+++ b/src/resolve/resolved-link.h
@@ -88,6 +88,8 @@ struct Link {
bool loaded;
char *state_file;
+
+ bool unicast_relevant;
};
int link_new(Manager *m, Link **ret, int ifindex);
diff --git a/src/resolve/resolved-llmnr.c b/src/resolve/resolved-llmnr.c
index 29396e9973..0cf4583572 100644
--- a/src/resolve/resolved-llmnr.c
+++ b/src/resolve/resolved-llmnr.c
@@ -345,7 +345,7 @@ static int on_llmnr_stream(sd_event_source *s, int fd, uint32_t revents, void *u
cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
if (cfd < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return 0;
return -errno;
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index b6620875ea..23c6731954 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -21,7 +21,7 @@
#include <poll.h>
#include <sys/ioctl.h>
-#ifdef HAVE_LIBIDN2
+#if HAVE_LIBIDN2
#include <idn2.h>
#endif
@@ -328,9 +328,9 @@ static int manager_network_monitor_listen(Manager *m) {
static int determine_hostname(char **full_hostname, char **llmnr_hostname, char **mdns_hostname) {
_cleanup_free_ char *h = NULL, *n = NULL;
-#if defined(HAVE_LIBIDN2)
+#if HAVE_LIBIDN2
_cleanup_free_ char *utf8 = NULL;
-#elif defined(HAVE_LIBIDN)
+#elif HAVE_LIBIDN
int k;
#endif
char label[DNS_LABEL_MAX];
@@ -356,7 +356,7 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char
return -EINVAL;
}
-#if defined(HAVE_LIBIDN2)
+#if HAVE_LIBIDN2
r = idn2_to_unicode_8z8z(label, &utf8, 0);
if (r != IDN2_OK)
return log_error("Failed to undo IDNA: %s", idn2_strerror(r));
@@ -364,7 +364,7 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char
r = strlen(utf8);
decoded = utf8;
-#elif defined(HAVE_LIBIDN)
+#elif HAVE_LIBIDN
k = dns_label_undo_idna(label, r, label, sizeof label);
if (k < 0)
return log_error_errno(k, "Failed to undo IDNA: %m");
@@ -519,8 +519,11 @@ static int manager_sigusr1(sd_event_source *s, const struct signalfd_siginfo *si
_cleanup_free_ char *buffer = NULL;
_cleanup_fclose_ FILE *f = NULL;
Manager *m = userdata;
+ DnsServer *server;
size_t size = 0;
DnsScope *scope;
+ Iterator i;
+ Link *l;
assert(s);
assert(si);
@@ -533,6 +536,14 @@ static int manager_sigusr1(sd_event_source *s, const struct signalfd_siginfo *si
LIST_FOREACH(scopes, scope, m->dns_scopes)
dns_scope_dump(scope, f);
+ LIST_FOREACH(servers, server, m->dns_servers)
+ dns_server_dump(server, f);
+ LIST_FOREACH(servers, server, m->fallback_dns_servers)
+ dns_server_dump(server, f);
+ HASHMAP_FOREACH(l, m->links, i)
+ LIST_FOREACH(servers, server, l->dns_servers)
+ dns_server_dump(server, f);
+
if (fflush_and_check(f) < 0)
return log_oom();
@@ -552,6 +563,17 @@ static int manager_sigusr2(sd_event_source *s, const struct signalfd_siginfo *si
return 0;
}
+static int manager_sigrtmin1(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+ Manager *m = userdata;
+
+ assert(s);
+ assert(si);
+ assert(m);
+
+ manager_reset_server_features(m);
+ return 0;
+}
+
int manager_new(Manager **ret) {
_cleanup_(manager_freep) Manager *m = NULL;
int r;
@@ -616,6 +638,7 @@ int manager_new(Manager **ret) {
(void) sd_event_add_signal(m->event, &m->sigusr1_event_source, SIGUSR1, manager_sigusr1, m);
(void) sd_event_add_signal(m->event, &m->sigusr2_event_source, SIGUSR2, manager_sigusr2, m);
+ (void) sd_event_add_signal(m->event, &m->sigrtmin1_event_source, SIGRTMIN+1, manager_sigrtmin1, m);
manager_cleanup_saved_user(m);
@@ -679,6 +702,7 @@ Manager *manager_free(Manager *m) {
sd_event_source_unref(m->sigusr1_event_source);
sd_event_source_unref(m->sigusr2_event_source);
+ sd_event_source_unref(m->sigrtmin1_event_source);
sd_event_unref(m->event);
@@ -723,7 +747,7 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
if (ms < 0)
return ms;
- r = dns_packet_new(&p, protocol, ms);
+ r = dns_packet_new(&p, protocol, ms, DNS_PACKET_SIZE_MAX);
if (r < 0)
return r;
@@ -741,7 +765,7 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
if (l == 0)
return 0;
if (l < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return 0;
return -errno;
@@ -1396,6 +1420,19 @@ void manager_flush_caches(Manager *m) {
log_info("Flushed all caches.");
}
+void manager_reset_server_features(Manager *m) {
+ Iterator i;
+ Link *l;
+
+ dns_server_reset_features_all(m->dns_servers);
+ dns_server_reset_features_all(m->fallback_dns_servers);
+
+ HASHMAP_FOREACH(l, m->links, i)
+ dns_server_reset_features_all(l->dns_servers);
+
+ log_info("Resetting learnt feature levels on all servers.");
+}
+
void manager_cleanup_saved_user(Manager *m) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h
index 97c52b7729..32a0e5fe0f 100644
--- a/src/resolve/resolved-manager.h
+++ b/src/resolve/resolved-manager.h
@@ -126,6 +126,7 @@ struct Manager {
sd_event_source *sigusr1_event_source;
sd_event_source *sigusr2_event_source;
+ sd_event_source *sigrtmin1_event_source;
unsigned n_transactions_total;
unsigned n_dnssec_verdict[_DNSSEC_VERDICT_MAX];
@@ -184,5 +185,6 @@ void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResource
bool manager_routable(Manager *m, int family);
void manager_flush_caches(Manager *m);
+void manager_reset_server_features(Manager *m);
void manager_cleanup_saved_user(Manager *m);
diff --git a/src/resolve/resolved-mdns.c b/src/resolve/resolved-mdns.c
index 415dc1a532..6fbf755878 100644
--- a/src/resolve/resolved-mdns.c
+++ b/src/resolve/resolved-mdns.c
@@ -86,27 +86,21 @@ static int mdns_scope_process_query(DnsScope *s, DnsPacket *p) {
key = p->question->keys[0];
r = dns_zone_lookup(&s->zone, key, 0, &answer, &soa, &tentative);
- if (r < 0) {
- log_debug_errno(r, "Failed to lookup key: %m");
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "Failed to lookup key: %m");
if (r == 0)
return 0;
r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, NULL, answer, NULL, false, &reply);
- if (r < 0) {
- log_debug_errno(r, "Failed to build reply packet: %m");
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "Failed to build reply packet: %m");
if (!ratelimit_test(&s->ratelimit))
return 0;
r = dns_scope_emit_udp(s, -1, reply);
- if (r < 0) {
- log_debug_errno(r, "Failed to send reply packet: %m");
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "Failed to send reply packet: %m");
return 0;
}
diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c
index 3c62550872..e3d6a33409 100644
--- a/src/resolve/resolved-resolv-conf.c
+++ b/src/resolve/resolved-resolv-conf.c
@@ -26,6 +26,7 @@
#include "fileio.h"
#include "ordered-set.h"
#include "resolved-conf.h"
+#include "resolved-dns-server.h"
#include "resolved-resolv-conf.h"
#include "string-util.h"
#include "strv.h"
@@ -87,7 +88,7 @@ int manager_read_resolv_conf(Manager *m) {
char *l;
l = strstrip(line);
- if (*l == '#' || *l == ';')
+ if (IN_SET(*l, '#', ';'))
continue;
a = first_word(l, "nameserver");
@@ -136,6 +137,11 @@ int manager_read_resolv_conf(Manager *m) {
if (m->unicast_scope)
dns_cache_flush(&m->unicast_scope->cache);
+ /* If /etc/resolv.conf changed, make sure to forget everything we learned about the DNS servers. After all we
+ * might now talk to a very different DNS server that just happens to have the same IP address as an old one
+ * (think 192.168.1.1). */
+ dns_server_reset_features_all(m->dns_servers);
+
return 0;
clear:
@@ -165,7 +171,7 @@ static void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) {
}
if (*count == MAXNS)
- fputs("# Too many DNS servers configured, the following entries may be ignored.\n", f);
+ fputs_unlocked("# Too many DNS servers configured, the following entries may be ignored.\n", f);
(*count)++;
fprintf(f, "nameserver %s\n", dns_server_string(s));
@@ -181,39 +187,39 @@ static void write_resolv_conf_search(
assert(domains);
assert(f);
- fputs("search", f);
+ fputs_unlocked("search", f);
ORDERED_SET_FOREACH(domain, domains, i) {
if (++count > MAXDNSRCH) {
- fputs("\n# Too many search domains configured, remaining ones ignored.", f);
+ fputs_unlocked("\n# Too many search domains configured, remaining ones ignored.", f);
break;
}
length += strlen(domain) + 1;
if (length > 256) {
- fputs("\n# Total length of all search domains is too long, remaining ones ignored.", f);
+ fputs_unlocked("\n# Total length of all search domains is too long, remaining ones ignored.", f);
break;
}
- fputc(' ', f);
- fputs(domain, f);
+ fputc_unlocked(' ', f);
+ fputs_unlocked(domain, f);
}
- fputs("\n", f);
+ fputs_unlocked("\n", f);
}
static int write_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *domains) {
Iterator i;
- fputs("# This file is managed by man:systemd-resolved(8). Do not edit.\n#\n"
- "# This is a dynamic resolv.conf file for connecting local clients directly to\n"
- "# all known DNS servers.\n#\n"
- "# Third party programs must not access this file directly, but only through the\n"
- "# symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a different way,\n"
- "# replace this symlink by a static file or a different symlink.\n#\n"
- "# See man:systemd-resolved.service(8) for details about the supported modes of\n"
- "# operation for /etc/resolv.conf.\n\n", f);
+ fputs_unlocked("# This file is managed by man:systemd-resolved(8). Do not edit.\n#\n"
+ "# This is a dynamic resolv.conf file for connecting local clients directly to\n"
+ "# all known DNS servers.\n#\n"
+ "# Third party programs must not access this file directly, but only through the\n"
+ "# symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a different way,\n"
+ "# replace this symlink by a static file or a different symlink.\n#\n"
+ "# See man:systemd-resolved.service(8) for details about the supported modes of\n"
+ "# operation for /etc/resolv.conf.\n\n", f);
if (ordered_set_isempty(dns))
- fputs("# No DNS servers known.\n", f);
+ fputs_unlocked("# No DNS servers known.\n", f);
else {
unsigned count = 0;
DnsServer *s;
diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c
index 74603f9311..2eb7bfd030 100644
--- a/src/resolve/resolved.c
+++ b/src/resolve/resolved.c
@@ -67,15 +67,20 @@ int main(int argc, char *argv[]) {
goto finish;
}
- /* Drop privileges, but keep three caps. Note that we drop those too, later on (see below) */
- r = drop_privileges(uid, gid,
- (UINT64_C(1) << CAP_NET_RAW)| /* needed for SO_BINDTODEVICE */
- (UINT64_C(1) << CAP_NET_BIND_SERVICE)| /* needed to bind on port 53 */
- (UINT64_C(1) << CAP_SETPCAP) /* needed in order to drop the caps later */);
- if (r < 0)
- goto finish;
+ /* Drop privileges, but only if we have been started as root. If we are not running as root we assume all
+ * privileges are already dropped. */
+ if (getuid() == 0) {
+
+ /* Drop privileges, but keep three caps. Note that we drop those too, later on (see below) */
+ r = drop_privileges(uid, gid,
+ (UINT64_C(1) << CAP_NET_RAW)| /* needed for SO_BINDTODEVICE */
+ (UINT64_C(1) << CAP_NET_BIND_SERVICE)| /* needed to bind on port 53 */
+ (UINT64_C(1) << CAP_SETPCAP) /* needed in order to drop the caps later */);
+ if (r < 0)
+ goto finish;
+ }
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGUSR1, SIGUSR2, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGUSR1, SIGUSR2, SIGRTMIN+1, -1) >= 0);
r = manager_new(&m);
if (r < 0) {
diff --git a/src/resolve/test-dns-packet.c b/src/resolve/test-dns-packet.c
index 8cbe492526..00dde9b6bd 100644
--- a/src/resolve/test-dns-packet.c
+++ b/src/resolve/test-dns-packet.c
@@ -75,7 +75,7 @@ static void test_packet_from_file(const char* filename, bool canonical) {
assert_se(packet_size > 0);
assert_se(offset + 8 + packet_size <= data_size);
- assert_se(dns_packet_new(&p, DNS_PROTOCOL_DNS, 0) >= 0);
+ assert_se(dns_packet_new(&p, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX) >= 0);
assert_se(dns_packet_append_blob(p, data + offset + 8, packet_size, NULL) >= 0);
assert_se(dns_packet_read_rr(p, &rr, NULL, NULL) >= 0);
@@ -90,7 +90,7 @@ static void test_packet_from_file(const char* filename, bool canonical) {
assert_se(dns_resource_record_to_wire_format(rr, canonical) >= 0);
- assert_se(dns_packet_new(&p2, DNS_PROTOCOL_DNS, 0) >= 0);
+ assert_se(dns_packet_new(&p2, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX) >= 0);
assert_se(dns_packet_append_blob(p2, rr->wire_format, rr->wire_format_size, NULL) >= 0);
assert_se(dns_packet_read_rr(p2, &rr2, NULL, NULL) >= 0);
diff --git a/src/resolve/test-dnssec-complex.c b/src/resolve/test-dnssec-complex.c
index 090b2fac23..25ec6f4352 100644
--- a/src/resolve/test-dnssec-complex.c
+++ b/src/resolve/test-dnssec-complex.c
@@ -218,7 +218,7 @@ int main(int argc, char* argv[]) {
test_hostname_lookup(bus, "poettering.de", AF_INET, NULL);
test_hostname_lookup(bus, "poettering.de", AF_INET6, NULL);
-#if defined(HAVE_LIBIDN2) || defined(HAVE_LIBIDN)
+#if HAVE_LIBIDN2 || HAVE_LIBIDN
/* Unsigned A with IDNA conversion necessary */
test_hostname_lookup(bus, "pöttering.de", AF_UNSPEC, NULL);
test_hostname_lookup(bus, "pöttering.de", AF_INET, NULL);
diff --git a/src/resolve/test-dnssec.c b/src/resolve/test-dnssec.c
index b3018e8239..8cb4b50393 100644
--- a/src/resolve/test-dnssec.c
+++ b/src/resolve/test-dnssec.c
@@ -47,7 +47,7 @@ static void test_dnssec_canonicalize(void) {
test_dnssec_canonicalize_one("FOO..bar.", NULL, -EINVAL);
}
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
static void test_dnssec_verify_dns_key(void) {
@@ -332,7 +332,7 @@ int main(int argc, char*argv[]) {
test_dnssec_canonicalize();
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
test_dnssec_verify_dns_key();
test_dnssec_verify_rrset();
test_dnssec_verify_rrset2();
diff --git a/src/resolve/test-resolved-packet.c b/src/resolve/test-resolved-packet.c
index 1b0041214b..ab11fbcd32 100644
--- a/src/resolve/test-resolved-packet.c
+++ b/src/resolve/test-resolved-packet.c
@@ -27,13 +27,16 @@ static void test_dns_packet_new(void) {
for (i = 0; i <= DNS_PACKET_SIZE_MAX; i++) {
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
- assert_se(dns_packet_new(&p, DNS_PROTOCOL_DNS, i) == 0);
+ assert_se(dns_packet_new(&p, DNS_PROTOCOL_DNS, i, DNS_PACKET_SIZE_MAX) == 0);
log_debug("dns_packet_new: %zu → %zu", i, p->allocated);
assert_se(p->allocated >= MIN(DNS_PACKET_SIZE_MAX, i));
+
+ if (i > DNS_PACKET_SIZE_START + 10 && i < DNS_PACKET_SIZE_MAX - 10)
+ i = MIN(i * 2, DNS_PACKET_SIZE_MAX - 10);
}
- assert_se(dns_packet_new(&p2, DNS_PROTOCOL_DNS, DNS_PACKET_SIZE_MAX + 1) == -EFBIG);
+ assert_se(dns_packet_new(&p2, DNS_PROTOCOL_DNS, DNS_PACKET_SIZE_MAX + 1, DNS_PACKET_SIZE_MAX) == -EFBIG);
}
int main(int argc, char **argv) {