summaryrefslogtreecommitdiff
path: root/src/grp-resolve/systemd-resolved
diff options
context:
space:
mode:
Diffstat (limited to 'src/grp-resolve/systemd-resolved')
-rw-r--r--src/grp-resolve/systemd-resolved/Makefile113
-rw-r--r--src/grp-resolve/systemd-resolved/RFCs2
-rw-r--r--src/grp-resolve/systemd-resolved/dns-type.c17
-rw-r--r--src/grp-resolve/systemd-resolved/dns-type.h15
-rw-r--r--src/grp-resolve/systemd-resolved/resolve-tool.c346
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-bus.c134
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-conf.c4
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-answer.c14
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-answer.h2
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-cache.c146
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-dnssec.c80
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-packet.c458
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-packet.h6
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-query.c31
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-question.c10
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-rr.c207
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-rr.h33
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-scope.c4
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-server.c9
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-synthesize.c14
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-transaction.c786
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-transaction.h9
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-trust-anchor.c4
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-zone.c39
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-etc-hosts.c6
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-link-bus.c6
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-link-bus.h2
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-link.c2
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-llmnr.c2
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-manager.c10
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-mdns.c2
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-resolv-conf.c4
-rw-r--r--src/grp-resolve/systemd-resolved/resolved.c2
-rw-r--r--src/grp-resolve/systemd-resolved/resolved.conf.in2
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/_443._tcp.fedoraproject.org.pktsbin0 -> 169 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/_openpgpkey.fedoraproject.org.pktsbin0 -> 986 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/fake-caa.pktsbin0 -> 196 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/fedoraproject.org.pktsbin0 -> 1483 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/gandi.net.pktsbin0 -> 1010 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/google.com.pktsbin0 -> 747 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/kyhwana.org.pktsbin0 -> 1803 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/root.pktsbin0 -> 1061 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pktsbin0 -> 330 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/teamits.com.pktsbin0 -> 1021 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/zbyszek@fedoraproject.org.pktsbin0 -> 2533 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-dns-packet.c114
-rw-r--r--src/grp-resolve/systemd-resolved/test-dnssec.c275
-rw-r--r--src/grp-resolve/systemd-resolved/test-resolve-tables.c37
48 files changed, 1740 insertions, 1207 deletions
diff --git a/src/grp-resolve/systemd-resolved/Makefile b/src/grp-resolve/systemd-resolved/Makefile
index 4e34240a43..f025608eab 100644
--- a/src/grp-resolve/systemd-resolved/Makefile
+++ b/src/grp-resolve/systemd-resolved/Makefile
@@ -23,8 +23,35 @@
include $(dir $(lastword $(MAKEFILE_LIST)))/../../../config.mk
include $(topsrcdir)/build-aux/Makefile.head.mk
+
+$(outdir)/dns_type-list.txt: src/resolve/dns-type.h
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
+ $(AM_V_GEN)$(SED) -n -r 's/.* DNS_TYPE_(\w+).*/\1/p' <$< >$@
+
+$(outdir)/dns_type-to-name.h: src/resolve/dns_type-list.txt
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
+ $(AM_V_GEN)$(AWK) 'BEGIN{ print "const char *dns_type_to_string(int type) {\n\tswitch(type) {" } {printf " case DNS_TYPE_%s: return ", $$1; sub(/_/, "-"); printf "\"%s\";\n", $$1 } END{ print " default: return NULL;\n\t}\n}\n" }' <$< >$@
+
+$(outdir)/dns_type-from-name.gperf: src/resolve/dns_type-list.txt
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
+ $(AM_V_GEN)$(AWK) 'BEGIN{ print "struct dns_type_name { const char* name; int id; };"; print "%null-strings"; print "%%";} { s=$$1; sub(/_/, "-", s); printf "%s, ", $$s; printf "DNS_TYPE_%s\n", $$1 }' <$< >$@
+
ifneq ($(ENABLE_RESOLVED),)
+basic_dns_sources = \
+ src/resolve/resolved-dns-dnssec.c \
+ src/resolve/resolved-dns-dnssec.h \
+ src/resolve/resolved-dns-packet.c \
+ src/resolve/resolved-dns-packet.h \
+ src/resolve/resolved-dns-rr.c \
+ src/resolve/resolved-dns-rr.h \
+ src/resolve/resolved-dns-answer.c \
+ src/resolve/resolved-dns-answer.h \
+ src/resolve/resolved-dns-question.c \
+ src/resolve/resolved-dns-question.h \
+ src/resolve/dns-type.c \
+ src/resolve/dns-type.h
+
systemd_resolved_SOURCES = \
src/resolve/resolved.c \
src/resolve/resolved-manager.c \
@@ -44,14 +71,7 @@ systemd_resolved_SOURCES = \
src/resolve/resolved-mdns.h \
src/resolve/resolved-mdns.c \
src/resolve/resolved-def.h \
- src/resolve/resolved-dns-rr.h \
- src/resolve/resolved-dns-rr.c \
- src/resolve/resolved-dns-question.h \
- src/resolve/resolved-dns-question.c \
- src/resolve/resolved-dns-answer.h \
- src/resolve/resolved-dns-answer.c \
- src/resolve/resolved-dns-packet.h \
- src/resolve/resolved-dns-packet.c \
+ $(basic_dns_sources) \
src/resolve/resolved-dns-query.h \
src/resolve/resolved-dns-query.c \
src/resolve/resolved-dns-synthesize.h \
@@ -70,14 +90,12 @@ systemd_resolved_SOURCES = \
src/resolve/resolved-dns-zone.c \
src/resolve/resolved-dns-stream.h \
src/resolve/resolved-dns-stream.c \
- src/resolve/resolved-dns-dnssec.h \
- src/resolve/resolved-dns-dnssec.c \
src/resolve/resolved-dns-trust-anchor.h \
src/resolve/resolved-dns-trust-anchor.c \
src/resolve/resolved-etc-hosts.h \
src/resolve/resolved-etc-hosts.c \
- src/resolve/dns-type.c \
- src/resolve/dns-type.h
+ src/shared/gcrypt-util.c \
+ src/shared/gcrypt-util.h
nodist_systemd_resolved_SOURCES = \
src/resolve/dns_type-from-name.h \
@@ -137,18 +155,9 @@ lib_LTLIBRARIES += \
systemd_resolve_SOURCES = \
src/resolve/resolve-tool.c \
- src/resolve/resolved-dns-dnssec.c \
- src/resolve/resolved-dns-dnssec.h \
- src/resolve/resolved-dns-packet.c \
- src/resolve/resolved-dns-packet.h \
- src/resolve/resolved-dns-rr.c \
- src/resolve/resolved-dns-rr.h \
- src/resolve/resolved-dns-answer.c \
- src/resolve/resolved-dns-answer.h \
- src/resolve/resolved-dns-question.c \
- src/resolve/resolved-dns-question.h \
- src/resolve/dns-type.c \
- src/resolve/dns-type.h
+ $(basic_dns_sources) \
+ src/shared/gcrypt-util.c \
+ src/shared/gcrypt-util.h
nodist_systemd_resolve_SOURCES = \
src/resolve/dns_type-from-name.h \
@@ -160,27 +169,57 @@ systemd_resolve_LDADD = \
bin_PROGRAMS += \
systemd-resolve
+dist_bashcompletion_data += \
+ shell-completion/bash/systemd-resolve
+
+dist_zshcompletion_data += \
+ shell-completion/zsh/_systemd-resolve
+
tests += \
- test-dns-domain \
+ test-dns-packet \
+ test-resolve-tables \
test-dnssec
manual_tests += \
test-dnssec-complex
+test_resolve_tables_SOURCES = \
+ src/resolve/test-resolve-tables.c \
+ src/resolve/dns_type-from-name.h \
+ src/resolve/dns_type-to-name.h \
+ $(basic_dns_sources) \
+ src/shared/test-tables.h
+
+test_resolve_tables_LDADD = \
+ libshared.la
+
+test_dns_packet_SOURCES = \
+ src/resolve/test-dns-packet.c \
+ $(basic_dns_sources)
+
+test_dns_packet_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -DRESOLVE_TEST_DIR=\"$(abs_top_srcdir)/src/resolve/test-data\"
+
+test_dns_packet_LDADD = \
+ libshared.la
+
+EXTRA_DIST += \
+ src/resolve/test-data/_openpgpkey.fedoraproject.org.pkts \
+ src/resolve/test-data/fedoraproject.org.pkts \
+ src/resolve/test-data/gandi.net.pkts \
+ src/resolve/test-data/google.com.pkts \
+ src/resolve/test-data/root.pkts \
+ src/resolve/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts \
+ src/resolve/test-data/teamits.com.pkts \
+ src/resolve/test-data/zbyszek@fedoraproject.org.pkts \
+ src/resolve/test-data/_443._tcp.fedoraproject.org.pkts \
+ src/resolve/test-data/kyhwana.org.pkts \
+ src/resolve/test-data/fake-caa.pkts
+
test_dnssec_SOURCES = \
src/resolve/test-dnssec.c \
- src/resolve/resolved-dns-packet.c \
- src/resolve/resolved-dns-packet.h \
- src/resolve/resolved-dns-rr.c \
- src/resolve/resolved-dns-rr.h \
- src/resolve/resolved-dns-answer.c \
- src/resolve/resolved-dns-answer.h \
- src/resolve/resolved-dns-question.c \
- src/resolve/resolved-dns-question.h \
- src/resolve/resolved-dns-dnssec.c \
- src/resolve/resolved-dns-dnssec.h \
- src/resolve/dns-type.c \
- src/resolve/dns-type.h
+ $(basic_dns_sources)
test_dnssec_LDADD = \
libshared.la
diff --git a/src/grp-resolve/systemd-resolved/RFCs b/src/grp-resolve/systemd-resolved/RFCs
index 22004a00cd..09c85f9518 100644
--- a/src/grp-resolve/systemd-resolved/RFCs
+++ b/src/grp-resolve/systemd-resolved/RFCs
@@ -8,7 +8,7 @@ D = Comprehensively Implemented, by a dependency of resolved
Y https://tools.ietf.org/html/rfc1034 → DOMAIN NAMES - CONCEPTS AND FACILITIES
Y https://tools.ietf.org/html/rfc1035 → DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION
? https://tools.ietf.org/html/rfc1101 → DNS Encoding of Network Names and Other Types
-Y https://tools.ietf.org/html/rfc1123 → Requirements for Internet Hosts -- Application and Support
+Y https://tools.ietf.org/html/rfc1123 → Requirements for Internet Hosts — Application and Support
~ https://tools.ietf.org/html/rfc1464 → Using the Domain Name System To Store Arbitrary String Attributes
Y https://tools.ietf.org/html/rfc1536 → Common DNS Implementation Errors and Suggested Fixes
Y https://tools.ietf.org/html/rfc1876 → A Means for Expressing Location Information in the Domain Name System
diff --git a/src/grp-resolve/systemd-resolved/dns-type.c b/src/grp-resolve/systemd-resolved/dns-type.c
index b2f479cae5..78d9d5733f 100644
--- a/src/grp-resolve/systemd-resolved/dns-type.c
+++ b/src/grp-resolve/systemd-resolved/dns-type.c
@@ -193,6 +193,23 @@ bool dns_type_is_obsolete(uint16_t type) {
DNS_TYPE_NULL);
}
+bool dns_type_needs_authentication(uint16_t type) {
+
+ /* Returns true for all (non-obsolete) RR types where records are not useful if they aren't
+ * authenticated. I.e. everything that contains crypto keys. */
+
+ return IN_SET(type,
+ DNS_TYPE_CERT,
+ DNS_TYPE_SSHFP,
+ DNS_TYPE_IPSECKEY,
+ DNS_TYPE_DS,
+ DNS_TYPE_DNSKEY,
+ DNS_TYPE_TLSA,
+ DNS_TYPE_CDNSKEY,
+ DNS_TYPE_OPENPGPKEY,
+ DNS_TYPE_CAA);
+}
+
int dns_type_to_af(uint16_t t) {
switch (t) {
diff --git a/src/grp-resolve/systemd-resolved/dns-type.h b/src/grp-resolve/systemd-resolved/dns-type.h
index a6c1630021..7b79d29d7e 100644
--- a/src/grp-resolve/systemd-resolved/dns-type.h
+++ b/src/grp-resolve/systemd-resolved/dns-type.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include "macro.h"
/* DNS record types, taken from
@@ -124,6 +124,9 @@ enum {
_DNS_CLASS_INVALID = -1
};
+#define _DNS_CLASS_STRING_MAX (sizeof "CLASS" + DECIMAL_STR_MAX(uint16_t))
+#define _DNS_TYPE_STRING_MAX (sizeof "CLASS" + DECIMAL_STR_MAX(uint16_t))
+
bool dns_type_is_pseudo(uint16_t type);
bool dns_type_is_valid_query(uint16_t type);
bool dns_type_is_valid_rr(uint16_t type);
@@ -132,7 +135,8 @@ bool dns_type_is_dnssec(uint16_t type);
bool dns_type_is_obsolete(uint16_t type);
bool dns_type_may_wildcard(uint16_t type);
bool dns_type_apex_only(uint16_t type);
-int dns_type_to_af(uint16_t t);
+bool dns_type_needs_authentication(uint16_t type);
+int dns_type_to_af(uint16_t type);
bool dns_class_is_pseudo(uint16_t class);
bool dns_class_is_valid_rr(uint16_t class);
@@ -141,7 +145,7 @@ bool dns_class_is_valid_rr(uint16_t class);
const char *dns_type_to_string(int type);
int dns_type_from_string(const char *s);
-const char *dns_class_to_string(uint16_t type);
+const char *dns_class_to_string(uint16_t class);
int dns_class_from_string(const char *name);
/* https://tools.ietf.org/html/draft-ietf-dane-protocol-23#section-7.2 */
@@ -152,3 +156,6 @@ const char *tlsa_selector_to_string(uint8_t selector);
/* https://tools.ietf.org/html/draft-ietf-dane-protocol-23#section-7.4 */
const char *tlsa_matching_type_to_string(uint8_t selector);
+
+/* https://tools.ietf.org/html/rfc6844#section-5.1 */
+#define CAA_FLAG_CRITICAL (1u << 7)
diff --git a/src/grp-resolve/systemd-resolved/resolve-tool.c b/src/grp-resolve/systemd-resolved/resolve-tool.c
index 3f1b6e32f1..fbf7b0e4f6 100644
--- a/src/grp-resolve/systemd-resolved/resolve-tool.c
+++ b/src/grp-resolve/systemd-resolved/resolve-tool.c
@@ -28,6 +28,7 @@
#include "bus-util.h"
#include "escape.h"
#include "in-addr-util.h"
+#include "gcrypt-util.h"
#include "parse-util.h"
#include "resolved-def.h"
#include "resolved-dns-packet.h"
@@ -42,14 +43,54 @@ static uint16_t arg_class = 0;
static bool arg_legend = true;
static uint64_t arg_flags = 0;
+typedef enum ServiceFamily {
+ SERVICE_FAMILY_TCP,
+ SERVICE_FAMILY_UDP,
+ SERVICE_FAMILY_SCTP,
+ _SERVICE_FAMILY_INVALID = -1,
+} ServiceFamily;
+static ServiceFamily arg_service_family = SERVICE_FAMILY_TCP;
+
+typedef enum RawType {
+ RAW_NONE,
+ RAW_PAYLOAD,
+ RAW_PACKET,
+} RawType;
+static RawType arg_raw = RAW_NONE;
+
static enum {
MODE_RESOLVE_HOST,
MODE_RESOLVE_RECORD,
MODE_RESOLVE_SERVICE,
+ MODE_RESOLVE_OPENPGP,
+ MODE_RESOLVE_TLSA,
MODE_STATISTICS,
MODE_RESET_STATISTICS,
} arg_mode = MODE_RESOLVE_HOST;
+static ServiceFamily service_family_from_string(const char *s) {
+ if (s == NULL || streq(s, "tcp"))
+ return SERVICE_FAMILY_TCP;
+ if (streq(s, "udp"))
+ return SERVICE_FAMILY_UDP;
+ if (streq(s, "sctp"))
+ return SERVICE_FAMILY_SCTP;
+ return _SERVICE_FAMILY_INVALID;
+}
+
+static const char* service_family_to_string(ServiceFamily service) {
+ switch(service) {
+ case SERVICE_FAMILY_TCP:
+ return "_tcp";
+ case SERVICE_FAMILY_UDP:
+ return "_udp";
+ case SERVICE_FAMILY_SCTP:
+ return "_sctp";
+ default:
+ assert_not_reached("invalid service");
+ }
+}
+
static void print_source(uint64_t flags, usec_t rtt) {
char rtt_str[FORMAT_TIMESTAMP_MAX];
@@ -328,6 +369,50 @@ static int parse_address(const char *s, int *family, union in_addr_union *addres
return 0;
}
+static int output_rr_packet(const void *d, size_t l, int ifindex) {
+ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
+ _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
+ int r;
+ char ifname[IF_NAMESIZE] = "";
+
+ r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
+ if (r < 0)
+ return log_oom();
+
+ p->refuse_compression = true;
+
+ r = dns_packet_append_blob(p, d, l, NULL);
+ if (r < 0)
+ return log_oom();
+
+ r = dns_packet_read_rr(p, &rr, NULL, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse RR: %m");
+
+ if (arg_raw == RAW_PAYLOAD) {
+ void *data;
+ ssize_t k;
+
+ k = dns_resource_record_payload(rr, &data);
+ if (k < 0)
+ return log_error_errno(k, "Cannot dump RR: %m");
+ fwrite(data, 1, k, stdout);
+ } else {
+ const char *s;
+
+ s = dns_resource_record_to_string(rr);
+ if (!s)
+ return log_oom();
+
+ if (ifindex > 0 && !if_indextoname(ifindex, ifname))
+ log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
+
+ printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname);
+ }
+
+ return 0;
+}
+
static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_t type) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -336,6 +421,7 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_
uint64_t flags;
int r;
usec_t ts;
+ bool needs_authentication = false;
assert(name);
@@ -373,9 +459,6 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_
return bus_log_parse_error(r);
while ((r = sd_bus_message_enter_container(reply, 'r', "iqqay")) > 0) {
- _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
- _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
- const char *s;
uint16_t c, t;
int ifindex;
const void *d;
@@ -395,29 +478,20 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_
if (r < 0)
return bus_log_parse_error(r);
- r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
- if (r < 0)
- return log_oom();
-
- p->refuse_compression = true;
+ if (arg_raw == RAW_PACKET) {
+ uint64_t u64 = htole64(l);
- r = dns_packet_append_blob(p, d, l, NULL);
- if (r < 0)
- return log_oom();
-
- r = dns_packet_read_rr(p, &rr, NULL, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to parse RR: %m");
+ fwrite(&u64, sizeof(u64), 1, stdout);
+ fwrite(d, 1, l, stdout);
+ } else {
+ r = output_rr_packet(d, l, ifindex);
+ if (r < 0)
+ return r;
+ }
- s = dns_resource_record_to_string(rr);
- if (!s)
- return log_oom();
+ if (dns_type_needs_authentication(t))
+ needs_authentication = true;
- ifname[0] = 0;
- if (ifindex > 0 && !if_indextoname(ifindex, ifname))
- log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
-
- printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname);
n++;
}
if (r < 0)
@@ -438,6 +512,18 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_
print_source(flags, ts);
+ if ((flags & SD_RESOLVED_AUTHENTICATED) == 0 && needs_authentication) {
+ fflush(stdout);
+
+ fprintf(stderr, "\n%s"
+ "WARNING: The resources shown contain cryptographic key data which could not be\n"
+ " authenticated. It is not suitable to authenticate any communication.\n"
+ " This is usually indication that DNSSEC authentication was not enabled\n"
+ " or is not available for the selected protocol or DNS servers.%s\n",
+ ansi_highlight_red(),
+ ansi_normal());
+ }
+
return 0;
}
@@ -545,15 +631,10 @@ static int resolve_rfc4501(sd_bus *bus, const char *name) {
} else
n = p;
- if (type == 0)
- type = arg_type;
- if (type == 0)
- type = DNS_TYPE_A;
-
- if (class == 0)
- class = arg_class;
if (class == 0)
- class = DNS_CLASS_IN;
+ class = arg_class ?: DNS_CLASS_IN;
+ if (type == 0)
+ type = arg_type ?: DNS_TYPE_A;
return resolve_record(bus, n, class, type);
@@ -763,6 +844,68 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons
return 0;
}
+static int resolve_openpgp(sd_bus *bus, const char *address) {
+ const char *domain, *full;
+ int r;
+ _cleanup_free_ char *hashed = NULL;
+
+ assert(bus);
+ assert(address);
+
+ domain = strrchr(address, '@');
+ if (!domain) {
+ log_error("Address does not contain '@': \"%s\"", address);
+ return -EINVAL;
+ } else if (domain == address || domain[1] == '\0') {
+ log_error("Address starts or ends with '@': \"%s\"", address);
+ return -EINVAL;
+ }
+ domain++;
+
+ r = string_hashsum_sha224(address, domain - 1 - address, &hashed);
+ if (r < 0)
+ return log_error_errno(r, "Hashing failed: %m");
+
+ full = strjoina(hashed, "._openpgpkey.", domain);
+ log_debug("Looking up \"%s\".", full);
+
+ return resolve_record(bus, full,
+ arg_class ?: DNS_CLASS_IN,
+ arg_type ?: DNS_TYPE_OPENPGPKEY);
+}
+
+static int resolve_tlsa(sd_bus *bus, const char *address) {
+ const char *port;
+ uint16_t port_num = 443;
+ _cleanup_free_ char *full = NULL;
+ int r;
+
+ assert(bus);
+ assert(address);
+
+ port = strrchr(address, ':');
+ if (port) {
+ r = safe_atou16(port + 1, &port_num);
+ if (r < 0 || port_num == 0)
+ return log_error_errno(r, "Invalid port \"%s\".", port + 1);
+
+ address = strndupa(address, port - address);
+ }
+
+ r = asprintf(&full, "_%u.%s.%s",
+ port_num,
+ service_family_to_string(arg_service_family),
+ address);
+ if (r < 0)
+ return log_oom();
+
+ log_debug("Looking up \"%s\".", full);
+
+ return resolve_record(bus, full,
+ arg_class ?: DNS_CLASS_IN,
+ arg_type ?: DNS_TYPE_TLSA);
+}
+
static int show_statistics(sd_bus *bus) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
@@ -931,26 +1074,34 @@ static void help_dns_classes(void) {
}
static void help(void) {
- printf("%s [OPTIONS...] NAME...\n"
- "%s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n\n"
+ printf("%1$s [OPTIONS...] HOSTNAME|ADDRESS...\n"
+ "%1$s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n"
+ "%1$s [OPTIONS...] --openpgp EMAIL@DOMAIN...\n"
+ "%1$s [OPTIONS...] --statistics\n"
+ "%1$s [OPTIONS...] --reset-statistics\n"
+ "\n"
"Resolve domain names, IPv4 and IPv6 addresses, DNS resource records, and services.\n\n"
- " -h --help Show this help\n"
- " --version Show package version\n"
- " -4 Resolve IPv4 addresses\n"
- " -6 Resolve IPv6 addresses\n"
- " -i --interface=INTERFACE Look on interface\n"
- " -p --protocol=PROTOCOL|help Look via protocol\n"
- " -t --type=TYPE|help Query RR with DNS type\n"
- " -c --class=CLASS|help Query RR with DNS class\n"
- " --service Resolve service (SRV)\n"
- " --service-address=BOOL Do [not] resolve address for services\n"
- " --service-txt=BOOL Do [not] resolve TXT records for services\n"
- " --cname=BOOL Do [not] follow CNAME redirects\n"
- " --search=BOOL Do [not] use search domains\n"
- " --legend=BOOL Do [not] print column headers and meta information\n"
- " --statistics Show resolver statistics\n"
- " --reset-statistics Reset resolver statistics\n"
- , program_invocation_short_name, program_invocation_short_name);
+ " -h --help Show this help\n"
+ " --version Show package version\n"
+ " -4 Resolve IPv4 addresses\n"
+ " -6 Resolve IPv6 addresses\n"
+ " -i --interface=INTERFACE Look on interface\n"
+ " -p --protocol=PROTO|help Look via protocol\n"
+ " -t --type=TYPE|help Query RR with DNS type\n"
+ " -c --class=CLASS|help Query RR with DNS class\n"
+ " --service Resolve service (SRV)\n"
+ " --service-address=BOOL Resolve address for services (default: yes)\n"
+ " --service-txt=BOOL Resolve TXT records for services (default: yes)\n"
+ " --openpgp Query OpenPGP public key\n"
+ " --tlsa Query TLS public key\n"
+ " --cname=BOOL Follow CNAME redirects (default: yes)\n"
+ " --search=BOOL Use search domains for single-label names\n"
+ " (default: yes)\n"
+ " --raw[=payload|packet] Dump the answer as binary data\n"
+ " --legend=BOOL Print headers and additional info (default: yes)\n"
+ " --statistics Show resolver statistics\n"
+ " --reset-statistics Reset resolver statistics\n"
+ , program_invocation_short_name);
}
static int parse_argv(int argc, char *argv[]) {
@@ -961,6 +1112,9 @@ static int parse_argv(int argc, char *argv[]) {
ARG_CNAME,
ARG_SERVICE_ADDRESS,
ARG_SERVICE_TXT,
+ ARG_OPENPGP,
+ ARG_TLSA,
+ ARG_RAW,
ARG_SEARCH,
ARG_STATISTICS,
ARG_RESET_STATISTICS,
@@ -978,6 +1132,9 @@ static int parse_argv(int argc, char *argv[]) {
{ "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 },
@@ -1087,44 +1244,63 @@ static int parse_argv(int argc, char *argv[]) {
arg_mode = MODE_RESOLVE_SERVICE;
break;
+ case ARG_OPENPGP:
+ arg_mode = MODE_RESOLVE_OPENPGP;
+ break;
+
+ case ARG_TLSA:
+ arg_mode = MODE_RESOLVE_TLSA;
+ arg_service_family = service_family_from_string(optarg);
+ if (arg_service_family < 0) {
+ log_error("Unknown service family \"%s\".", optarg);
+ return -EINVAL;
+ }
+ break;
+
+ case ARG_RAW:
+ if (on_tty()) {
+ log_error("Refusing to write binary data to tty.");
+ return -ENOTTY;
+ }
+
+ if (optarg == NULL || streq(optarg, "payload"))
+ arg_raw = RAW_PAYLOAD;
+ else if (streq(optarg, "packet"))
+ arg_raw = RAW_PACKET;
+ else {
+ log_error("Unknown --raw specifier \"%s\".", optarg);
+ return -EINVAL;
+ }
+
+ arg_legend = false;
+ break;
+
case ARG_CNAME:
r = parse_boolean(optarg);
if (r < 0)
return log_error_errno(r, "Failed to parse --cname= argument.");
- if (r == 0)
- arg_flags |= SD_RESOLVED_NO_CNAME;
- else
- arg_flags &= ~SD_RESOLVED_NO_CNAME;
+ SET_FLAG(arg_flags, SD_RESOLVED_NO_CNAME, r == 0);
break;
case ARG_SERVICE_ADDRESS:
r = parse_boolean(optarg);
if (r < 0)
return log_error_errno(r, "Failed to parse --service-address= argument.");
- if (r == 0)
- arg_flags |= SD_RESOLVED_NO_ADDRESS;
- else
- arg_flags &= ~SD_RESOLVED_NO_ADDRESS;
+ SET_FLAG(arg_flags, SD_RESOLVED_NO_ADDRESS, r == 0);
break;
case ARG_SERVICE_TXT:
r = parse_boolean(optarg);
if (r < 0)
return log_error_errno(r, "Failed to parse --service-txt= argument.");
- if (r == 0)
- arg_flags |= SD_RESOLVED_NO_TXT;
- else
- arg_flags &= ~SD_RESOLVED_NO_TXT;
+ SET_FLAG(arg_flags, SD_RESOLVED_NO_TXT, r == 0);
break;
case ARG_SEARCH:
r = parse_boolean(optarg);
if (r < 0)
return log_error_errno(r, "Failed to parse --search argument.");
- if (r == 0)
- arg_flags |= SD_RESOLVED_NO_SEARCH;
- else
- arg_flags &= ~SD_RESOLVED_NO_SEARCH;
+ SET_FLAG(arg_flags, SD_RESOLVED_NO_SEARCH, r == 0);
break;
case ARG_STATISTICS:
@@ -1147,7 +1323,7 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
- if (arg_type != 0 && arg_mode != MODE_RESOLVE_RECORD) {
+ if (arg_type != 0 && arg_mode == MODE_RESOLVE_SERVICE) {
log_error("--service and --type= may not be combined.");
return -EINVAL;
}
@@ -1246,6 +1422,42 @@ int main(int argc, char **argv) {
break;
+ case MODE_RESOLVE_OPENPGP:
+ if (argc < optind + 1) {
+ log_error("E-mail address required.");
+ r = -EINVAL;
+ goto finish;
+
+ }
+
+ r = 0;
+ while (optind < argc) {
+ int k;
+
+ k = resolve_openpgp(bus, argv[optind++]);
+ if (k < 0)
+ r = k;
+ }
+ break;
+
+ case MODE_RESOLVE_TLSA:
+ if (argc < optind + 1) {
+ log_error("Domain name required.");
+ r = -EINVAL;
+ goto finish;
+
+ }
+
+ r = 0;
+ while (optind < argc) {
+ int k;
+
+ k = resolve_tlsa(bus, argv[optind++]);
+ if (k < 0)
+ r = k;
+ }
+ break;
+
case MODE_STATISTICS:
if (argc > optind) {
log_error("Too many arguments.");
diff --git a/src/grp-resolve/systemd-resolved/resolved-bus.c b/src/grp-resolve/systemd-resolved/resolved-bus.c
index fc5e6beca0..33f7c61557 100644
--- a/src/grp-resolve/systemd-resolved/resolved-bus.c
+++ b/src/grp-resolve/systemd-resolved/resolved-bus.c
@@ -23,6 +23,7 @@
#include "dns-domain.h"
#include "resolved-bus.h"
#include "resolved-def.h"
+#include "resolved-dns-synthesize.h"
#include "resolved-link-bus.h"
static int reply_query_state(DnsQuery *q) {
@@ -139,6 +140,7 @@ static int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifin
static void bus_method_resolve_hostname_complete(DnsQuery *q) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_free_ char *normalized = NULL;
DnsResourceRecord *rr;
unsigned added = 0;
int ifindex, r;
@@ -186,7 +188,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
if (!canonical)
canonical = dns_resource_record_ref(rr);
- added ++;
+ added++;
}
if (added <= 0) {
@@ -198,11 +200,17 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
if (r < 0)
goto finish;
+ /* The key names are not necessarily normalized, make sure that they are when we return them to our bus
+ * clients. */
+ r = dns_name_normalize(dns_resource_key_name(canonical->key), &normalized);
+ if (r < 0)
+ goto finish;
+
/* Return the precise spelling and uppercasing and CNAME target reported by the server */
assert(canonical);
r = sd_bus_message_append(
reply, "st",
- DNS_RESOURCE_KEY_NAME(canonical->key),
+ normalized,
SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated));
if (r < 0)
goto finish;
@@ -233,6 +241,65 @@ static int check_ifindex_flags(int ifindex, uint64_t *flags, uint64_t ok, sd_bus
return 0;
}
+static int parse_as_address(sd_bus_message *m, int ifindex, const char *hostname, int family, uint64_t flags) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_free_ char *canonical = NULL;
+ union in_addr_union parsed;
+ int r, ff;
+
+ /* Check if the hostname is actually already an IP address formatted as string. In that case just parse it,
+ * let's not attempt to look it up. */
+
+ r = in_addr_from_string_auto(hostname, &ff, &parsed);
+ if (r < 0) /* not an address */
+ return 0;
+
+ if (family != AF_UNSPEC && ff != family)
+ return sd_bus_reply_method_errorf(m, BUS_ERROR_NO_SUCH_RR, "The specified address is not of the requested family.");
+
+ r = sd_bus_message_new_method_return(m, &reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(reply, 'a', "(iiay)");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(reply, 'r', "iiay");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(reply, "ii", ifindex, ff);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append_array(reply, 'y', &parsed, FAMILY_ADDRESS_SIZE(ff));
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return r;
+
+ /* When an IP address is specified we just return it as canonical name, in order to avoid a DNS
+ * look-up. However, we reformat it to make sure it's in a truly canonical form (i.e. on IPv6 the inner
+ * omissions are always done the same way). */
+ r = in_addr_to_string(ff, &parsed, &canonical);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(reply, "st", canonical,
+ SD_RESOLVED_FLAGS_MAKE(dns_synthesize_protocol(flags), ff, true));
+ if (r < 0)
+ return r;
+
+ return sd_bus_send(sd_bus_message_get_bus(m), reply, NULL);
+}
+
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;
@@ -254,15 +321,19 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata,
if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
- r = dns_name_is_valid(hostname);
+ r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_SEARCH, error);
if (r < 0)
return r;
- if (r == 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
- r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_SEARCH, error);
+ r = parse_as_address(message, ifindex, hostname, family, flags);
+ if (r != 0)
+ return r;
+
+ r = dns_name_is_valid(hostname);
if (r < 0)
return r;
+ if (r == 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
r = dns_question_new_address(&question_utf8, family, hostname, false);
if (r < 0)
@@ -331,24 +402,31 @@ static void bus_method_resolve_address_complete(DnsQuery *q) {
question = dns_query_question_for_protocol(q, q->answer_protocol);
DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
+ _cleanup_free_ char *normalized = NULL;
+
r = dns_question_matches_rr(question, rr, NULL);
if (r < 0)
goto finish;
if (r == 0)
continue;
- r = sd_bus_message_append(reply, "(is)", ifindex, rr->ptr.name);
+ r = dns_name_normalize(rr->ptr.name, &normalized);
+ if (r < 0)
+ goto finish;
+
+ r = sd_bus_message_append(reply, "(is)", ifindex, normalized);
if (r < 0)
goto finish;
- added ++;
+ added++;
}
if (added <= 0) {
_cleanup_free_ char *ip = NULL;
- in_addr_to_string(q->request_family, &q->request_address, &ip);
- r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have any RR of requested type", strna(ip));
+ (void) in_addr_to_string(q->request_family, &q->request_address, &ip);
+ r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR,
+ "Address '%s' does not have any RR of requested type", strnull(ip));
goto finish;
}
@@ -510,7 +588,7 @@ static void bus_method_resolve_record_complete(DnsQuery *q) {
if (r < 0)
goto finish;
- added ++;
+ added++;
}
if (added <= 0) {
@@ -607,6 +685,7 @@ fail:
static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
+ _cleanup_free_ char *normalized = NULL;
DnsQuery *aux;
int r;
@@ -663,10 +742,14 @@ static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr)
if (r < 0)
return r;
+ r = dns_name_normalize(rr->srv.name, &normalized);
+ if (r < 0)
+ return r;
+
r = sd_bus_message_append(
reply,
"qqqs",
- rr->srv.priority, rr->srv.weight, rr->srv.port, rr->srv.name);
+ rr->srv.priority, rr->srv.weight, rr->srv.port, normalized);
if (r < 0)
return r;
@@ -712,9 +795,17 @@ static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr)
if (r < 0)
return r;
+ if (canonical) {
+ normalized = mfree(normalized);
+
+ r = dns_name_normalize(dns_resource_key_name(canonical->key), &normalized);
+ if (r < 0)
+ return r;
+ }
+
/* Note that above we appended the hostname as encoded in the
* SRV, and here the canonical hostname this maps to. */
- r = sd_bus_message_append(reply, "s", canonical ? DNS_RESOURCE_KEY_NAME(canonical->key) : rr->srv.name);
+ r = sd_bus_message_append(reply, "s", normalized);
if (r < 0)
return r;
@@ -869,7 +960,7 @@ static void resolve_service_all_complete(DnsQuery *q) {
goto finish;
assert(canonical);
- r = dns_service_split(DNS_RESOURCE_KEY_NAME(canonical->key), &name, &type, &domain);
+ r = dns_service_split(dns_resource_key_name(canonical->key), &name, &type, &domain);
if (r < 0)
goto finish;
@@ -1004,9 +1095,9 @@ static void bus_method_resolve_service_complete(DnsQuery *q) {
}
if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
- q->block_all_complete ++;
+ q->block_all_complete++;
r = resolve_service_hostname(q, rr, ifindex);
- q->block_all_complete --;
+ q->block_all_complete--;
if (r < 0)
goto finish;
@@ -1047,7 +1138,6 @@ finish:
static int bus_method_resolve_service(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL;
const char *name, *type, *domain;
- _cleanup_free_ char *n = NULL;
Manager *m = userdata;
int family, ifindex;
uint64_t flags;
@@ -1198,7 +1288,7 @@ static int bus_property_get_dns_servers(
return sd_bus_message_close_container(reply);
}
-static int bus_property_get_search_domains(
+static int bus_property_get_domains(
sd_bus *bus,
const char *path,
const char *interface,
@@ -1396,8 +1486,8 @@ static int bus_method_set_link_dns_servers(sd_bus_message *message, void *userda
return call_link_method(userdata, message, bus_link_method_set_dns_servers, error);
}
-static int bus_method_set_link_search_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return call_link_method(userdata, message, bus_link_method_set_search_domains, error);
+static int bus_method_set_link_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return call_link_method(userdata, message, bus_link_method_set_domains, error);
}
static int bus_method_set_link_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -1449,7 +1539,7 @@ static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), 0),
SD_BUS_PROPERTY("DNS", "a(iiay)", bus_property_get_dns_servers, 0, 0),
- SD_BUS_PROPERTY("SearchDomains", "a(isb)", bus_property_get_search_domains, 0, 0),
+ SD_BUS_PROPERTY("Domains", "a(isb)", bus_property_get_domains, 0, 0),
SD_BUS_PROPERTY("TransactionStatistics", "(tt)", bus_property_get_transaction_statistics, 0, 0),
SD_BUS_PROPERTY("CacheStatistics", "(ttt)", bus_property_get_cache_statistics, 0, 0),
SD_BUS_PROPERTY("DNSSECStatistics", "(tttt)", bus_property_get_dnssec_statistics, 0, 0),
@@ -1462,7 +1552,7 @@ static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_METHOD("ResetStatistics", NULL, NULL, bus_method_reset_statistics, 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_search_domains, 0),
+ SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_domains, 0),
SD_BUS_METHOD("SetLinkLLMNR", "is", NULL, bus_method_set_link_llmnr, 0),
SD_BUS_METHOD("SetLinkMulticastDNS", "is", NULL, bus_method_set_link_mdns, 0),
SD_BUS_METHOD("SetLinkDNSSEC", "is", NULL, bus_method_set_link_dnssec, 0),
diff --git a/src/grp-resolve/systemd-resolved/resolved-conf.c b/src/grp-resolve/systemd-resolved/resolved-conf.c
index bb93fbfda2..990dc03b60 100644
--- a/src/grp-resolve/systemd-resolved/resolved-conf.c
+++ b/src/grp-resolve/systemd-resolved/resolved-conf.c
@@ -59,7 +59,7 @@ int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, con
assert(m);
assert(string);
- for(;;) {
+ for (;;) {
_cleanup_free_ char *word = NULL;
r = extract_first_word(&string, &word, NULL, 0);
@@ -114,7 +114,7 @@ int manager_parse_search_domains_and_warn(Manager *m, const char *string) {
assert(m);
assert(string);
- for(;;) {
+ for (;;) {
_cleanup_free_ char *word = NULL;
r = extract_first_word(&string, &word, NULL, EXTRACT_QUOTES);
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-answer.c b/src/grp-resolve/systemd-resolved/resolved-dns-answer.c
index 7eb303ab95..0dadf8b1dd 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-answer.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-answer.c
@@ -330,7 +330,7 @@ int dns_answer_contains_zone_nsec3(DnsAnswer *answer, const char *zone) {
if (rr->key->type != DNS_TYPE_NSEC3)
continue;
- p = DNS_RESOURCE_KEY_NAME(rr->key);
+ p = dns_resource_key_name(rr->key);
r = dns_name_parent(&p);
if (r < 0)
return r;
@@ -363,7 +363,7 @@ int dns_answer_find_soa(DnsAnswer *a, const DnsResourceKey *key, DnsResourceReco
if (r > 0) {
if (soa) {
- r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(soa->key));
+ r = dns_name_endswith(dns_resource_key_name(rr->key), dns_resource_key_name(soa->key));
if (r < 0)
return r;
if (r > 0)
@@ -538,7 +538,7 @@ int dns_answer_remove_by_key(DnsAnswer **a, const DnsResourceKey *key) {
dns_resource_record_unref((*a)->items[i].rr);
memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1));
- (*a)->n_rrs --;
+ (*a)->n_rrs--;
continue;
} else
@@ -624,7 +624,7 @@ int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rm) {
dns_resource_record_unref((*a)->items[i].rr);
memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1));
- (*a)->n_rrs --;
+ (*a)->n_rrs--;
continue;
} else
@@ -757,7 +757,7 @@ int dns_answer_reserve_or_clone(DnsAnswer **a, unsigned n_free) {
assert(a);
/* Tries to extend the DnsAnswer object. And if that's not
- * possibly, since we are not the sole owner, then allocate a
+ * possible, since we are not the sole owner, then allocate a
* new, appropriately sized one. Either way, after this call
* the object will only have a single reference, and has room
* for at least the specified number of RRs. */
@@ -840,13 +840,13 @@ bool dns_answer_has_dname_for_cname(DnsAnswer *a, DnsResourceRecord *cname) {
if (rr->key->class != cname->key->class)
continue;
- r = dns_name_change_suffix(cname->cname.name, rr->dname.name, DNS_RESOURCE_KEY_NAME(rr->key), &n);
+ r = dns_name_change_suffix(cname->cname.name, rr->dname.name, dns_resource_key_name(rr->key), &n);
if (r < 0)
return r;
if (r == 0)
continue;
- r = dns_name_equal(n, DNS_RESOURCE_KEY_NAME(cname->key));
+ r = dns_name_equal(n, dns_resource_key_name(cname->key));
if (r < 0)
return r;
if (r > 0)
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-answer.h b/src/grp-resolve/systemd-resolved/resolved-dns-answer.h
index 8f9c15eab4..0679c610f5 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-answer.h
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-answer.h
@@ -30,7 +30,7 @@ typedef struct DnsAnswerItem DnsAnswerItem;
* can qualify A and AAAA RRs referring to a local link with the
* right ifindex.
*
- * Note that we usually encode the the empty DnsAnswer object as a simple NULL. */
+ * Note that we usually encode the empty DnsAnswer object as a simple NULL. */
typedef enum DnsAnswerFlags {
DNS_ANSWER_AUTHENTICATED = 1, /* Item has been authenticated */
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-cache.c b/src/grp-resolve/systemd-resolved/resolved-dns-cache.c
index 9bcc71724e..77c42d7aad 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-cache.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-cache.c
@@ -17,6 +17,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <net/if.h>
+
+#include "af-list.h"
#include "alloc-util.h"
#include "dns-domain.h"
#include "resolved-dns-answer.h"
@@ -180,6 +183,7 @@ void dns_cache_prune(DnsCache *c) {
for (;;) {
DnsCacheItem *i;
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
i = prioq_peek(c->by_expiry);
if (!i)
@@ -192,8 +196,12 @@ void dns_cache_prune(DnsCache *c) {
break;
/* Depending whether this is an mDNS shared entry
- * either remove only this one RR or the whole
- * RRset */
+ * either remove only this one RR or the whole RRset */
+ log_debug("Removing %scache entry for %s (expired "USEC_FMT"s ago)",
+ i->shared_owner ? "shared " : "",
+ dns_resource_key_to_string(i->key, key_str, sizeof key_str),
+ (t - i->until) / USEC_PER_SEC);
+
if (i->shared_owner)
dns_cache_item_unlink_and_free(c, i);
else {
@@ -375,8 +383,8 @@ static int dns_cache_put_positive(
const union in_addr_union *owner_address) {
_cleanup_(dns_cache_item_freep) DnsCacheItem *i = NULL;
- _cleanup_free_ char *key_str = NULL;
DnsCacheItem *existing;
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX], ifname[IF_NAMESIZE];
int r, k;
assert(c);
@@ -392,18 +400,9 @@ static int dns_cache_put_positive(
/* New TTL is 0? Delete this specific entry... */
if (rr->ttl <= 0) {
k = dns_cache_remove_by_rr(c, rr);
-
- if (log_get_max_level() >= LOG_DEBUG) {
- r = dns_resource_key_to_string(rr->key, &key_str);
- if (r < 0)
- return r;
-
- if (k > 0)
- log_debug("Removed zero TTL entry from cache: %s", key_str);
- else
- log_debug("Not caching zero TTL cache entry: %s", key_str);
- }
-
+ log_debug("%s: %s",
+ k > 0 ? "Removed zero TTL entry from cache" : "Not caching zero TTL cache entry",
+ dns_resource_key_to_string(rr->key, key_str, sizeof key_str));
return 0;
}
@@ -450,11 +449,18 @@ static int dns_cache_put_positive(
return r;
if (log_get_max_level() >= LOG_DEBUG) {
- r = dns_resource_key_to_string(i->key, &key_str);
- if (r < 0)
- return r;
-
- log_debug("Added positive cache entry for %s", key_str);
+ _cleanup_free_ char *t = NULL;
+
+ (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",
+ i->shared_owner ? " shared" : "",
+ dns_resource_key_to_string(i->key, key_str, sizeof key_str),
+ (i->until - timestamp) / USEC_PER_SEC,
+ i->ifindex == 0 ? "*" : strna(if_indextoname(i->ifindex, ifname)),
+ af_to_name_short(i->owner_family),
+ strna(t));
}
i = NULL;
@@ -473,7 +479,7 @@ static int dns_cache_put_negative(
const union in_addr_union *owner_address) {
_cleanup_(dns_cache_item_freep) DnsCacheItem *i = NULL;
- _cleanup_free_ char *key_str = NULL;
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
int r;
assert(c);
@@ -490,14 +496,8 @@ static int dns_cache_put_negative(
return 0;
if (nsec_ttl <= 0 || soa->soa.minimum <= 0 || soa->ttl <= 0) {
- if (log_get_max_level() >= LOG_DEBUG) {
- r = dns_resource_key_to_string(key, &key_str);
- if (r < 0)
- return r;
-
- log_debug("Not caching negative entry with zero SOA/NSEC/NSEC3 TTL: %s", key_str);
- }
-
+ log_debug("Not caching negative entry with zero SOA/NSEC/NSEC3 TTL: %s",
+ dns_resource_key_to_string(key, key_str, sizeof key_str));
return 0;
}
@@ -524,7 +524,7 @@ static int dns_cache_put_negative(
if (i->type == DNS_CACHE_NXDOMAIN) {
/* NXDOMAIN entries should apply equally to all types, so we use ANY as
* a pseudo type for this purpose here. */
- i->key = dns_resource_key_new(key->class, DNS_TYPE_ANY, DNS_RESOURCE_KEY_NAME(key));
+ i->key = dns_resource_key_new(key->class, DNS_TYPE_ANY, dns_resource_key_name(key));
if (!i->key)
return -ENOMEM;
@@ -542,13 +542,10 @@ static int dns_cache_put_negative(
if (r < 0)
return r;
- if (log_get_max_level() >= LOG_DEBUG) {
- r = dns_resource_key_to_string(i->key, &key_str);
- if (r < 0)
- return r;
-
- log_debug("Added %s cache entry for %s", i->type == DNS_CACHE_NODATA ? "NODATA" : "NXDOMAIN", key_str);
- }
+ log_debug("Added %s cache entry for %s "USEC_FMT"s",
+ i->type == DNS_CACHE_NODATA ? "NODATA" : "NXDOMAIN",
+ dns_resource_key_to_string(i->key, key_str, sizeof key_str),
+ (i->until - timestamp) / USEC_PER_SEC);
i = NULL;
return 0;
@@ -628,16 +625,10 @@ int dns_cache_put(
dns_cache_remove_previous(c, key, answer);
if (dns_answer_size(answer) <= 0) {
- if (log_get_max_level() >= LOG_DEBUG) {
- _cleanup_free_ char *key_str = NULL;
-
- r = dns_resource_key_to_string(key, &key_str);
- if (r < 0)
- return r;
-
- log_debug("Not caching negative entry without a SOA record: %s", key_str);
- }
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
+ log_debug("Not caching negative entry without a SOA record: %s",
+ dns_resource_key_to_string(key, key_str, sizeof key_str));
return 0;
}
@@ -649,7 +640,7 @@ int dns_cache_put(
cache_keys = dns_answer_size(answer);
if (key)
- cache_keys ++;
+ cache_keys++;
/* Make some space for our new entries */
dns_cache_make_space(c, cache_keys);
@@ -759,7 +750,7 @@ static DnsCacheItem *dns_cache_get_by_key_follow_cname_dname_nsec(DnsCache *c, D
if (i)
return i;
- n = DNS_RESOURCE_KEY_NAME(k);
+ n = dns_resource_key_name(k);
/* Check if we have an NXDOMAIN cache item for the name, notice that we use
* the pseudo-type ANY for NXDOMAIN cache items. */
@@ -801,10 +792,10 @@ static DnsCacheItem *dns_cache_get_by_key_follow_cname_dname_nsec(DnsCache *c, D
int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **ret, bool *authenticated) {
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
unsigned n = 0;
int r;
bool nxdomain = false;
- _cleanup_free_ char *key_str = NULL;
DnsCacheItem *j, *first, *nsec = NULL;
bool have_authenticated = false, have_non_authenticated = false;
@@ -814,19 +805,12 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r
assert(ret);
assert(authenticated);
- if (key->type == DNS_TYPE_ANY ||
- key->class == DNS_CLASS_ANY) {
-
+ if (key->type == DNS_TYPE_ANY || key->class == DNS_CLASS_ANY) {
/* If we have ANY lookups we don't use the cache, so
* that the caller refreshes via the network. */
- if (log_get_max_level() >= LOG_DEBUG) {
- r = dns_resource_key_to_string(key, &key_str);
- if (r < 0)
- return r;
-
- log_debug("Ignoring cache for ANY lookup: %s", key_str);
- }
+ log_debug("Ignoring cache for ANY lookup: %s",
+ dns_resource_key_to_string(key, key_str, sizeof key_str));
c->n_miss++;
@@ -839,13 +823,8 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r
if (!first) {
/* If one question cannot be answered we need to refresh */
- if (log_get_max_level() >= LOG_DEBUG) {
- r = dns_resource_key_to_string(key, &key_str);
- if (r < 0)
- return r;
-
- log_debug("Cache miss for %s", key_str);
- }
+ log_debug("Cache miss for %s",
+ dns_resource_key_to_string(key, key_str, sizeof key_str));
c->n_miss++;
@@ -873,13 +852,8 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r
/* Note that we won't derive information for DS RRs from an NSEC, because we only cache NSEC RRs from
* the lower-zone of a zone cut, but the DS RRs are on the upper zone. */
- if (log_get_max_level() >= LOG_DEBUG) {
- r = dns_resource_key_to_string(key, &key_str);
- if (r < 0)
- return r;
-
- log_debug("NSEC NODATA cache hit for %s", key_str);
- }
+ log_debug("NSEC NODATA cache hit for %s",
+ dns_resource_key_to_string(key, key_str, sizeof key_str));
/* We only found an NSEC record that matches our name.
* If it says the type doesn't exist report
@@ -900,16 +874,10 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r
return 0;
}
- if (log_get_max_level() >= LOG_DEBUG) {
- r = dns_resource_key_to_string(key, &key_str);
- if (r < 0)
- return r;
-
- log_debug("%s cache hit for %s",
- n > 0 ? "Positive" :
- nxdomain ? "NXDOMAIN" : "NODATA",
- key_str);
- }
+ log_debug("%s cache hit for %s",
+ n > 0 ? "Positive" :
+ nxdomain ? "NXDOMAIN" : "NODATA",
+ dns_resource_key_to_string(key, key_str, sizeof key_str));
if (n <= 0) {
c->n_hit++;
@@ -1019,7 +987,7 @@ int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) {
if (r < 0)
return r;
- ancount ++;
+ ancount++;
}
}
@@ -1031,7 +999,6 @@ int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) {
void dns_cache_dump(DnsCache *cache, FILE *f) {
Iterator iterator;
DnsCacheItem *i;
- int r;
if (!cache)
return;
@@ -1057,14 +1024,9 @@ void dns_cache_dump(DnsCache *cache, FILE *f) {
fputs(t, f);
fputc('\n', f);
} else {
- _cleanup_free_ char *z = NULL;
- r = dns_resource_key_to_string(j->key, &z);
- if (r < 0) {
- log_oom();
- continue;
- }
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
- fputs(z, f);
+ fputs(dns_resource_key_to_string(j->key, key_str, sizeof key_str), f);
fputs(" -- ", f);
fputs(j->type == DNS_CACHE_NODATA ? "NODATA" : "NXDOMAIN", f);
fputc('\n', f);
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-dnssec.c b/src/grp-resolve/systemd-resolved/resolved-dns-dnssec.c
index 7123d2d3a8..a54aed3a63 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-dnssec.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-dnssec.c
@@ -23,6 +23,7 @@
#include "alloc-util.h"
#include "dns-domain.h"
+#include "gcrypt-util.h"
#include "hexdecoct.h"
#include "resolved-dns-dnssec.h"
#include "resolved-dns-packet.h"
@@ -126,19 +127,6 @@ int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) {
#ifdef HAVE_GCRYPT
-static void initialize_libgcrypt(void) {
- const char *p;
-
- if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P))
- return;
-
- p = gcry_check_version("1.4.5");
- assert(p);
-
- gcry_control(GCRYCTL_DISABLE_SECMEM);
- gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
-}
-
static int rr_compare(const void *a, const void *b) {
DnsResourceRecord **x = (DnsResourceRecord**) a, **y = (DnsResourceRecord**) b;
size_t m;
@@ -479,7 +467,7 @@ static int dnssec_rrsig_prepare(DnsResourceRecord *rrsig) {
if (rrsig->rrsig.inception > rrsig->rrsig.expiration)
return -EINVAL;
- name = DNS_RESOURCE_KEY_NAME(rrsig->key);
+ name = dns_resource_key_name(rrsig->key);
n_key_labels = dns_name_count_labels(name);
if (n_key_labels < 0)
@@ -635,9 +623,9 @@ int dnssec_verify_rrset(
assert(rrsig->key->type == DNS_TYPE_RRSIG);
assert(dnskey->key->type == DNS_TYPE_DNSKEY);
- /* Verifies the the RRSet matching the specified "key" in "a",
+ /* Verifies that the RRSet matches the specified "key" in "a",
* using the signature "rrsig" and the key "dnskey". It's
- * assumed the RRSIG and DNSKEY match. */
+ * assumed that RRSIG and DNSKEY match. */
md_algorithm = algorithm_to_gcrypt_md(rrsig->rrsig.algorithm);
if (md_algorithm == -EOPNOTSUPP) {
@@ -663,7 +651,7 @@ int dnssec_verify_rrset(
return 0;
}
- name = DNS_RESOURCE_KEY_NAME(key);
+ name = dns_resource_key_name(key);
/* Some keys may only appear signed in the zone apex, and are invalid anywhere else. (SOA, NS...) */
if (dns_type_apex_only(rrsig->rrsig.type_covered)) {
@@ -737,7 +725,7 @@ int dnssec_verify_rrset(
qsort_safe(list, n, sizeof(DnsResourceRecord*), rr_compare);
/* OK, the RRs are now in canonical order. Let's calculate the digest */
- initialize_libgcrypt();
+ initialize_libgcrypt(false);
hash_size = gcry_md_get_algo_dlen(md_algorithm);
assert(hash_size > 0);
@@ -863,7 +851,7 @@ int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnske
if (dnssec_keytag(dnskey, false) != rrsig->rrsig.key_tag)
return 0;
- return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey->key), rrsig->rrsig.signer);
+ return dns_name_equal(dns_resource_key_name(dnskey->key), rrsig->rrsig.signer);
}
int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig) {
@@ -879,7 +867,7 @@ int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig)
if (rrsig->rrsig.type_covered != key->type)
return 0;
- return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig->key), DNS_RESOURCE_KEY_NAME(key));
+ return dns_name_equal(dns_resource_key_name(rrsig->key), dns_resource_key_name(key));
}
int dnssec_verify_rrset_search(
@@ -1070,7 +1058,7 @@ int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds,
if (dnssec_keytag(dnskey, mask_revoke) != ds->ds.key_tag)
return 0;
- initialize_libgcrypt();
+ initialize_libgcrypt(false);
md_algorithm = digest_to_gcrypt_md(ds->ds.digest_type);
if (md_algorithm < 0)
@@ -1082,7 +1070,7 @@ int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds,
if (ds->ds.digest_size != hash_size)
return 0;
- r = dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey->key), owner_name, sizeof(owner_name));
+ r = dnssec_canonicalize(dns_resource_key_name(dnskey->key), owner_name, sizeof(owner_name));
if (r < 0)
return r;
@@ -1132,7 +1120,7 @@ int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord *dnskey, DnsAnswer *vali
if (ds->key->class != dnskey->key->class)
continue;
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey->key), DNS_RESOURCE_KEY_NAME(ds->key));
+ r = dns_name_equal(dns_resource_key_name(dnskey->key), dns_resource_key_name(ds->key));
if (r < 0)
return r;
if (r == 0)
@@ -1189,7 +1177,7 @@ int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
if (algorithm < 0)
return algorithm;
- initialize_libgcrypt();
+ initialize_libgcrypt(false);
hash_size = gcry_md_get_algo_dlen(algorithm);
assert(hash_size > 0);
@@ -1284,14 +1272,14 @@ static int nsec3_is_good(DnsResourceRecord *rr, DnsResourceRecord *nsec3) {
if (memcmp(rr->nsec3.salt, nsec3->nsec3.salt, rr->nsec3.salt_size) != 0)
return 0;
- a = DNS_RESOURCE_KEY_NAME(rr->key);
+ a = dns_resource_key_name(rr->key);
r = dns_name_parent(&a); /* strip off hash */
if (r < 0)
return r;
if (r == 0)
return 0;
- b = DNS_RESOURCE_KEY_NAME(nsec3->key);
+ b = dns_resource_key_name(nsec3->key);
r = dns_name_parent(&b); /* strip off hash */
if (r < 0)
return r;
@@ -1365,7 +1353,7 @@ static int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecR
* any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3
* records from a given zone in a response must use the same
* parameters. */
- zone = DNS_RESOURCE_KEY_NAME(key);
+ zone = dns_resource_key_name(key);
for (;;) {
DNS_ANSWER_FOREACH_FLAGS(zone_rr, flags, answer) {
r = nsec3_is_good(zone_rr, NULL);
@@ -1374,7 +1362,7 @@ static int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecR
if (r == 0)
continue;
- r = dns_name_equal_skip(DNS_RESOURCE_KEY_NAME(zone_rr->key), 1, zone);
+ r = dns_name_equal_skip(dns_resource_key_name(zone_rr->key), 1, zone);
if (r < 0)
return r;
if (r > 0)
@@ -1394,7 +1382,7 @@ static int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecR
found_zone:
/* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
- p = DNS_RESOURCE_KEY_NAME(key);
+ p = dns_resource_key_name(key);
for (;;) {
_cleanup_free_ char *hashed_domain = NULL;
@@ -1417,7 +1405,7 @@ found_zone:
if (enclosure_rr->nsec3.next_hashed_name_size != (size_t) hashed_size)
continue;
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(enclosure_rr->key), hashed_domain);
+ r = dns_name_equal(dns_resource_key_name(enclosure_rr->key), hashed_domain);
if (r < 0)
return r;
if (r > 0) {
@@ -1516,7 +1504,7 @@ found_closest_encloser:
if (r < 0)
return r;
- r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), next_closer_domain, next_hashed_domain);
+ r = dns_name_between(dns_resource_key_name(rr->key), next_closer_domain, next_hashed_domain);
if (r < 0)
return r;
if (r > 0) {
@@ -1528,7 +1516,7 @@ found_closest_encloser:
no_closer = true;
}
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), wildcard_domain);
+ r = dns_name_equal(dns_resource_key_name(rr->key), wildcard_domain);
if (r < 0)
return r;
if (r > 0) {
@@ -1537,7 +1525,7 @@ found_closest_encloser:
wildcard_rr = rr;
}
- r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), wildcard_domain, next_hashed_domain);
+ r = dns_name_between(dns_resource_key_name(rr->key), wildcard_domain, next_hashed_domain);
if (r < 0)
return r;
if (r > 0) {
@@ -1616,7 +1604,7 @@ static int dnssec_nsec_wildcard_equal(DnsResourceRecord *rr, const char *name) {
if (rr->n_skip_labels_source != 1)
return 0;
- n = DNS_RESOURCE_KEY_NAME(rr->key);
+ n = dns_resource_key_name(rr->key);
r = dns_label_unescape(&n, label, sizeof(label));
if (r <= 0)
return r;
@@ -1655,7 +1643,7 @@ static int dnssec_nsec_in_path(DnsResourceRecord *rr, const char *name) {
return r;
/* If the name we we are interested in is not a prefix of the common suffix of the NSEC RR's owner and next domain names, then we can't say anything either. */
- r = dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr->key), rr->nsec.next_domain_name, &common_suffix);
+ r = dns_name_common_suffix(dns_resource_key_name(rr->key), rr->nsec.next_domain_name, &common_suffix);
if (r < 0)
return r;
@@ -1674,7 +1662,7 @@ static int dnssec_nsec_from_parent_zone(DnsResourceRecord *rr, const char *name)
if (r <= 0)
return r;
- r = dns_name_equal(name, DNS_RESOURCE_KEY_NAME(rr->key));
+ r = dns_name_equal(name, dns_resource_key_name(rr->key));
if (r <= 0)
return r;
@@ -1697,7 +1685,7 @@ static int dnssec_nsec_covers(DnsResourceRecord *rr, const char *name) {
/* Checks whether the "Next Closer" is witin the space covered by the specified RR. */
- r = dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr->key), rr->nsec.next_domain_name, &common_suffix);
+ r = dns_name_common_suffix(dns_resource_key_name(rr->key), rr->nsec.next_domain_name, &common_suffix);
if (r < 0)
return r;
@@ -1718,7 +1706,7 @@ static int dnssec_nsec_covers(DnsResourceRecord *rr, const char *name) {
/* p is now the "Next Closer". */
- return dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), p, rr->nsec.next_domain_name);
+ return dns_name_between(dns_resource_key_name(rr->key), p, rr->nsec.next_domain_name);
}
static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name) {
@@ -1737,7 +1725,7 @@ static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name)
* NSEC yyy.zzz.xoo.bar → bar: indicates that a number of wildcards don#t exist either...
*/
- r = dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr->key), rr->nsec.next_domain_name, &common_suffix);
+ r = dns_name_common_suffix(dns_resource_key_name(rr->key), rr->nsec.next_domain_name, &common_suffix);
if (r < 0)
return r;
@@ -1746,8 +1734,8 @@ static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name)
if (r <= 0)
return r;
- wc = strjoina("*.", common_suffix, NULL);
- return dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), wc, rr->nsec.next_domain_name);
+ wc = strjoina("*.", common_suffix);
+ return dns_name_between(dns_resource_key_name(rr->key), wc, rr->nsec.next_domain_name);
}
int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl) {
@@ -1762,7 +1750,7 @@ int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *r
/* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
- name = DNS_RESOURCE_KEY_NAME(key);
+ name = dns_resource_key_name(key);
DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
@@ -1782,7 +1770,7 @@ int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *r
continue;
/* Check if this is a direct match. If so, we have encountered a NODATA case */
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), name);
+ r = dns_name_equal(dns_resource_key_name(rr->key), name);
if (r < 0)
return r;
if (r == 0) {
@@ -1912,7 +1900,7 @@ static int dnssec_nsec_test_enclosed(DnsAnswer *answer, uint16_t type, const cha
if (r == 0)
continue;
- r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), name, rr->nsec.next_domain_name);
+ r = dns_name_between(dns_resource_key_name(rr->key), name, rr->nsec.next_domain_name);
if (r < 0)
return r;
@@ -1955,7 +1943,7 @@ static int dnssec_nsec_test_enclosed(DnsAnswer *answer, uint16_t type, const cha
if (r < 0)
return r;
- r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), hashed_domain, next_hashed_domain);
+ r = dns_name_between(dns_resource_key_name(rr->key), hashed_domain, next_hashed_domain);
if (r < 0)
return r;
@@ -1989,7 +1977,7 @@ static int dnssec_test_positive_wildcard_nsec3(
/* Run a positive NSEC3 wildcard proof. Specifically:
*
- * A proof that the the "next closer" of the generating wildcard does not exist.
+ * A proof that the "next closer" of the generating wildcard does not exist.
*
* Note a key difference between the NSEC3 and NSEC versions of the proof. NSEC RRs don't have to exist for
* empty non-transients. NSEC3 RRs however have to. This means it's sufficient to check if the next closer name
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-packet.c b/src/grp-resolve/systemd-resolved/resolved-dns-packet.c
index c940dd8929..b7907bb511 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-packet.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-packet.c
@@ -28,6 +28,19 @@
#define EDNS0_OPT_DO (1<<15)
+typedef struct DnsPacketRewinder {
+ DnsPacket *packet;
+ size_t saved_rindex;
+} DnsPacketRewinder;
+
+static void rewind_dns_packet(DnsPacketRewinder *rewinder) {
+ if (rewinder->packet)
+ dns_packet_rewind(rewinder->packet, rewinder->saved_rindex);
+}
+
+#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 mtu) {
DnsPacket *p;
size_t a;
@@ -431,8 +444,7 @@ int dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_
((uint8_t*) d)[0] = (uint8_t) size;
- if (size > 0)
- memcpy(((uint8_t*) d) + 1, s, size);
+ memcpy_safe(((uint8_t*) d) + 1, s, size);
return 0;
}
@@ -565,7 +577,7 @@ int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start)
saved_size = p->size;
- r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), true, true, NULL);
+ r = dns_packet_append_name(p, dns_resource_key_name(k), true, true, NULL);
if (r < 0)
goto fail;
@@ -1072,6 +1084,18 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
r = dns_packet_append_blob(p, rr->tlsa.data, rr->tlsa.data_size, NULL);
break;
+ case DNS_TYPE_CAA:
+ r = dns_packet_append_uint8(p, rr->caa.flags, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_string(p, rr->caa.tag, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_blob(p, rr->caa.value, rr->caa.value_size, NULL);
+ break;
+
case DNS_TYPE_OPT:
case DNS_TYPE_OPENPGPKEY:
case _DNS_TYPE_INVALID: /* unparseable */
@@ -1230,80 +1254,67 @@ int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) {
}
int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) {
- size_t saved_rindex;
+ _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder;
const void *d;
char *t;
uint8_t c;
int r;
assert(p);
-
- saved_rindex = p->rindex;
+ INIT_REWINDER(rewinder, p);
r = dns_packet_read_uint8(p, &c, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read(p, c, &d, NULL);
if (r < 0)
- goto fail;
+ return r;
- if (memchr(d, 0, c)) {
- r = -EBADMSG;
- goto fail;
- }
+ if (memchr(d, 0, c))
+ return -EBADMSG;
t = strndup(d, c);
- if (!t) {
- r = -ENOMEM;
- goto fail;
- }
+ if (!t)
+ return -ENOMEM;
if (!utf8_is_valid(t)) {
free(t);
- r = -EBADMSG;
- goto fail;
+ return -EBADMSG;
}
*ret = t;
if (start)
- *start = saved_rindex;
+ *start = rewinder.saved_rindex;
+ CANCEL_REWINDER(rewinder);
return 0;
-
-fail:
- dns_packet_rewind(p, saved_rindex);
- return r;
}
int dns_packet_read_raw_string(DnsPacket *p, const void **ret, size_t *size, size_t *start) {
- size_t saved_rindex;
+ _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder;
uint8_t c;
int r;
assert(p);
-
- saved_rindex = p->rindex;
+ INIT_REWINDER(rewinder, p);
r = dns_packet_read_uint8(p, &c, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read(p, c, ret, NULL);
if (r < 0)
- goto fail;
+ return r;
if (size)
*size = c;
if (start)
- *start = saved_rindex;
+ *start = rewinder.saved_rindex;
+ CANCEL_REWINDER(rewinder);
return 0;
-
-fail:
- dns_packet_rewind(p, saved_rindex);
- return r;
}
int dns_packet_read_name(
@@ -1312,7 +1323,8 @@ int dns_packet_read_name(
bool allow_compression,
size_t *start) {
- size_t saved_rindex, after_rindex = 0, jump_barrier;
+ _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder;
+ size_t after_rindex = 0, jump_barrier;
_cleanup_free_ char *ret = NULL;
size_t n = 0, allocated = 0;
bool first = true;
@@ -1320,19 +1332,18 @@ int dns_packet_read_name(
assert(p);
assert(_ret);
+ INIT_REWINDER(rewinder, p);
+ jump_barrier = p->rindex;
if (p->refuse_compression)
allow_compression = false;
- saved_rindex = p->rindex;
- jump_barrier = p->rindex;
-
for (;;) {
uint8_t c, d;
r = dns_packet_read_uint8(p, &c, NULL);
if (r < 0)
- goto fail;
+ return r;
if (c == 0)
/* End of name */
@@ -1343,12 +1354,10 @@ int dns_packet_read_name(
/* Literal label */
r = dns_packet_read(p, c, (const void**) &label, NULL);
if (r < 0)
- goto fail;
+ return r;
- if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) {
- r = -ENOMEM;
- goto fail;
- }
+ if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
+ return -ENOMEM;
if (first)
first = false;
@@ -1357,7 +1366,7 @@ int dns_packet_read_name(
r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX);
if (r < 0)
- goto fail;
+ return r;
n += r;
continue;
@@ -1367,13 +1376,11 @@ int dns_packet_read_name(
/* Pointer */
r = dns_packet_read_uint8(p, &d, NULL);
if (r < 0)
- goto fail;
+ return r;
ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
- if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= jump_barrier) {
- r = -EBADMSG;
- goto fail;
- }
+ if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= jump_barrier)
+ return -EBADMSG;
if (after_rindex == 0)
after_rindex = p->rindex;
@@ -1381,16 +1388,12 @@ int dns_packet_read_name(
/* Jumps are limited to a "prior occurrence" (RFC-1035 4.1.4) */
jump_barrier = ptr;
p->rindex = ptr;
- } else {
- r = -EBADMSG;
- goto fail;
- }
+ } else
+ return -EBADMSG;
}
- if (!GREEDY_REALLOC(ret, allocated, n + 1)) {
- r = -ENOMEM;
- goto fail;
- }
+ if (!GREEDY_REALLOC(ret, allocated, n + 1))
+ return -ENOMEM;
ret[n] = 0;
@@ -1401,13 +1404,10 @@ int dns_packet_read_name(
ret = NULL;
if (start)
- *start = saved_rindex;
+ *start = rewinder.saved_rindex;
+ CANCEL_REWINDER(rewinder);
return 0;
-
-fail:
- dns_packet_rewind(p, saved_rindex);
- return r;
}
static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *start) {
@@ -1417,32 +1417,31 @@ static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *sta
uint8_t bit = 0;
unsigned i;
bool found = false;
- size_t saved_rindex;
+ _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder;
int r;
assert(p);
assert(types);
-
- saved_rindex = p->rindex;
+ INIT_REWINDER(rewinder, p);
r = bitmap_ensure_allocated(types);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &window, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &length, NULL);
if (r < 0)
- goto fail;
+ return r;
if (length == 0 || length > 32)
return -EBADMSG;
r = dns_packet_read(p, length, (const void **)&bitmap, NULL);
if (r < 0)
- goto fail;
+ return r;
for (i = 0; i < length; i++) {
uint8_t bitmask = 1 << 7;
@@ -1467,10 +1466,10 @@ static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *sta
r = bitmap_set(*types, n);
if (r < 0)
- goto fail;
+ return r;
}
- bit ++;
+ bit++;
bitmask >>= 1;
}
}
@@ -1479,70 +1478,61 @@ static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *sta
return -EBADMSG;
if (start)
- *start = saved_rindex;
+ *start = rewinder.saved_rindex;
+ CANCEL_REWINDER(rewinder);
return 0;
-fail:
- dns_packet_rewind(p, saved_rindex);
- return r;
}
static int dns_packet_read_type_windows(DnsPacket *p, Bitmap **types, size_t size, size_t *start) {
- size_t saved_rindex;
+ _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder;
int r;
- saved_rindex = p->rindex;
+ INIT_REWINDER(rewinder, p);
- while (p->rindex < saved_rindex + size) {
+ while (p->rindex < rewinder.saved_rindex + size) {
r = dns_packet_read_type_window(p, types, NULL);
if (r < 0)
- goto fail;
+ return r;
/* don't read past end of current RR */
- if (p->rindex > saved_rindex + size) {
- r = -EBADMSG;
- goto fail;
- }
+ if (p->rindex > rewinder.saved_rindex + size)
+ return -EBADMSG;
}
- if (p->rindex != saved_rindex + size) {
- r = -EBADMSG;
- goto fail;
- }
+ if (p->rindex != rewinder.saved_rindex + size)
+ return -EBADMSG;
if (start)
- *start = saved_rindex;
+ *start = rewinder.saved_rindex;
+ CANCEL_REWINDER(rewinder);
return 0;
-fail:
- dns_packet_rewind(p, saved_rindex);
- return r;
}
int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, bool *ret_cache_flush, size_t *start) {
+ _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder;
_cleanup_free_ char *name = NULL;
bool cache_flush = false;
uint16_t class, type;
DnsResourceKey *key;
- size_t saved_rindex;
int r;
assert(p);
assert(ret);
-
- saved_rindex = p->rindex;
+ INIT_REWINDER(rewinder, p);
r = dns_packet_read_name(p, &name, true, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint16(p, &type, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint16(p, &class, NULL);
if (r < 0)
- goto fail;
+ return r;
if (p->protocol == DNS_PROTOCOL_MDNS) {
/* See RFC6762, Section 10.2 */
@@ -1554,10 +1544,8 @@ int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, bool *ret_cache_flus
}
key = dns_resource_key_new_consume(class, type, name);
- if (!key) {
- r = -ENOMEM;
- goto fail;
- }
+ if (!key)
+ return -ENOMEM;
name = NULL;
*ret = key;
@@ -1565,12 +1553,10 @@ int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, bool *ret_cache_flus
if (ret_cache_flush)
*ret_cache_flush = cache_flush;
if (start)
- *start = saved_rindex;
+ *start = rewinder.saved_rindex;
+ CANCEL_REWINDER(rewinder);
return 0;
-fail:
- dns_packet_rewind(p, saved_rindex);
- return r;
}
static bool loc_size_ok(uint8_t size) {
@@ -1582,7 +1568,8 @@ static bool loc_size_ok(uint8_t size) {
int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_flush, size_t *start) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
- size_t saved_rindex, offset;
+ _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder;
+ size_t offset;
uint16_t rdlength;
bool cache_flush;
int r;
@@ -1590,27 +1577,22 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
assert(p);
assert(ret);
- saved_rindex = p->rindex;
+ INIT_REWINDER(rewinder, p);
r = dns_packet_read_key(p, &key, &cache_flush, NULL);
if (r < 0)
- goto fail;
+ return r;
- if (!dns_class_is_valid_rr(key->class)||
- !dns_type_is_valid_rr(key->type)) {
- r = -EBADMSG;
- goto fail;
- }
+ if (!dns_class_is_valid_rr(key->class) || !dns_type_is_valid_rr(key->type))
+ return -EBADMSG;
rr = dns_resource_record_new(key);
- if (!rr) {
- r = -ENOMEM;
- goto fail;
- }
+ if (!rr)
+ return -ENOMEM;
r = dns_packet_read_uint32(p, &rr->ttl, NULL);
if (r < 0)
- goto fail;
+ return r;
/* RFC 2181, Section 8, suggests to
* treat a TTL with the MSB set as a zero TTL. */
@@ -1619,12 +1601,10 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
r = dns_packet_read_uint16(p, &rdlength, NULL);
if (r < 0)
- goto fail;
+ return r;
- if (p->rindex + rdlength > p->size) {
- r = -EBADMSG;
- goto fail;
- }
+ if (p->rindex + rdlength > p->size)
+ return -EBADMSG;
offset = p->rindex;
@@ -1633,13 +1613,13 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
case DNS_TYPE_SRV:
r = dns_packet_read_uint16(p, &rr->srv.priority, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint16(p, &rr->srv.weight, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint16(p, &rr->srv.port, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_name(p, &rr->srv.name, true, NULL);
break;
@@ -1653,7 +1633,7 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
case DNS_TYPE_HINFO:
r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_string(p, &rr->hinfo.os, NULL);
break;
@@ -1709,27 +1689,27 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
case DNS_TYPE_SOA:
r = dns_packet_read_name(p, &rr->soa.mname, true, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_name(p, &rr->soa.rname, true, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint32(p, &rr->soa.serial, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint32(p, &rr->soa.refresh, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint32(p, &rr->soa.retry, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint32(p, &rr->soa.expire, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint32(p, &rr->soa.minimum, NULL);
break;
@@ -1737,7 +1717,7 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
case DNS_TYPE_MX:
r = dns_packet_read_uint16(p, &rr->mx.priority, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_name(p, &rr->mx.exchange, true, NULL);
break;
@@ -1748,49 +1728,43 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
r = dns_packet_read_uint8(p, &t, &pos);
if (r < 0)
- goto fail;
+ return r;
if (t == 0) {
rr->loc.version = t;
r = dns_packet_read_uint8(p, &rr->loc.size, NULL);
if (r < 0)
- goto fail;
+ return r;
- if (!loc_size_ok(rr->loc.size)) {
- r = -EBADMSG;
- goto fail;
- }
+ if (!loc_size_ok(rr->loc.size))
+ return -EBADMSG;
r = dns_packet_read_uint8(p, &rr->loc.horiz_pre, NULL);
if (r < 0)
- goto fail;
+ return r;
- if (!loc_size_ok(rr->loc.horiz_pre)) {
- r = -EBADMSG;
- goto fail;
- }
+ if (!loc_size_ok(rr->loc.horiz_pre))
+ return -EBADMSG;
r = dns_packet_read_uint8(p, &rr->loc.vert_pre, NULL);
if (r < 0)
- goto fail;
+ return r;
- if (!loc_size_ok(rr->loc.vert_pre)) {
- r = -EBADMSG;
- goto fail;
- }
+ if (!loc_size_ok(rr->loc.vert_pre))
+ return -EBADMSG;
r = dns_packet_read_uint32(p, &rr->loc.latitude, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint32(p, &rr->loc.longitude, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint32(p, &rr->loc.altitude, NULL);
if (r < 0)
- goto fail;
+ return r;
break;
} else {
@@ -1803,122 +1777,114 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
case DNS_TYPE_DS:
r = dns_packet_read_uint16(p, &rr->ds.key_tag, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &rr->ds.algorithm, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &rr->ds.digest_type, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_memdup(p, rdlength - 4,
&rr->ds.digest, &rr->ds.digest_size,
NULL);
if (r < 0)
- goto fail;
+ return r;
- if (rr->ds.digest_size <= 0) {
+ if (rr->ds.digest_size <= 0)
/* the accepted size depends on the algorithm, but for now
just ensure that the value is greater than zero */
- r = -EBADMSG;
- goto fail;
- }
+ return -EBADMSG;
break;
case DNS_TYPE_SSHFP:
r = dns_packet_read_uint8(p, &rr->sshfp.algorithm, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &rr->sshfp.fptype, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_memdup(p, rdlength - 2,
&rr->sshfp.fingerprint, &rr->sshfp.fingerprint_size,
NULL);
- if (rr->sshfp.fingerprint_size <= 0) {
+ if (rr->sshfp.fingerprint_size <= 0)
/* the accepted size depends on the algorithm, but for now
just ensure that the value is greater than zero */
- r = -EBADMSG;
- goto fail;
- }
+ return -EBADMSG;
break;
case DNS_TYPE_DNSKEY:
r = dns_packet_read_uint16(p, &rr->dnskey.flags, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &rr->dnskey.protocol, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &rr->dnskey.algorithm, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_memdup(p, rdlength - 4,
&rr->dnskey.key, &rr->dnskey.key_size,
NULL);
- if (rr->dnskey.key_size <= 0) {
+ if (rr->dnskey.key_size <= 0)
/* the accepted size depends on the algorithm, but for now
just ensure that the value is greater than zero */
- r = -EBADMSG;
- goto fail;
- }
+ return -EBADMSG;
break;
case DNS_TYPE_RRSIG:
r = dns_packet_read_uint16(p, &rr->rrsig.type_covered, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &rr->rrsig.algorithm, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &rr->rrsig.labels, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint32(p, &rr->rrsig.original_ttl, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint32(p, &rr->rrsig.expiration, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint32(p, &rr->rrsig.inception, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint16(p, &rr->rrsig.key_tag, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_name(p, &rr->rrsig.signer, false, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_memdup(p, offset + rdlength - p->rindex,
&rr->rrsig.signature, &rr->rrsig.signature_size,
NULL);
- if (rr->rrsig.signature_size <= 0) {
+ if (rr->rrsig.signature_size <= 0)
/* the accepted size depends on the algorithm, but for now
just ensure that the value is greater than zero */
- r = -EBADMSG;
- goto fail;
- }
+ return -EBADMSG;
break;
@@ -1933,11 +1899,9 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
r = dns_packet_read_name(p, &rr->nsec.next_domain_name, allow_compressed, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_type_windows(p, &rr->nsec.types, offset + rdlength - p->rindex, NULL);
- if (r < 0)
- goto fail;
/* We accept empty NSEC bitmaps. The bit indicating the presence of the NSEC record itself
* is redundant and in e.g., RFC4956 this fact is used to define a use for NSEC records
@@ -1950,41 +1914,39 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
r = dns_packet_read_uint8(p, &rr->nsec3.algorithm, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &rr->nsec3.flags, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint16(p, &rr->nsec3.iterations, NULL);
if (r < 0)
- goto fail;
+ return r;
/* this may be zero */
r = dns_packet_read_uint8(p, &size, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_memdup(p, size, &rr->nsec3.salt, &rr->nsec3.salt_size, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &size, NULL);
if (r < 0)
- goto fail;
+ return r;
- if (size <= 0) {
- r = -EBADMSG;
- goto fail;
- }
+ if (size <= 0)
+ return -EBADMSG;
- r = dns_packet_read_memdup(p, size, &rr->nsec3.next_hashed_name, &rr->nsec3.next_hashed_name_size, NULL);
+ r = dns_packet_read_memdup(p, size,
+ &rr->nsec3.next_hashed_name, &rr->nsec3.next_hashed_name_size,
+ NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_type_windows(p, &rr->nsec3.types, offset + rdlength - p->rindex, NULL);
- if (r < 0)
- goto fail;
/* empty non-terminals can have NSEC3 records, so empty bitmaps are allowed */
@@ -1994,25 +1956,39 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
case DNS_TYPE_TLSA:
r = dns_packet_read_uint8(p, &rr->tlsa.cert_usage, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &rr->tlsa.selector, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &rr->tlsa.matching_type, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_memdup(p, rdlength - 3,
&rr->tlsa.data, &rr->tlsa.data_size,
NULL);
- if (rr->tlsa.data_size <= 0) {
+
+ if (rr->tlsa.data_size <= 0)
/* the accepted size depends on the algorithm, but for now
just ensure that the value is greater than zero */
- r = -EBADMSG;
- goto fail;
- }
+ return -EBADMSG;
+
+ break;
+
+ case DNS_TYPE_CAA:
+ r = dns_packet_read_uint8(p, &rr->caa.flags, NULL);
+ if (r < 0)
+ return r;
+
+ r = dns_packet_read_string(p, &rr->caa.tag, NULL);
+ if (r < 0)
+ return r;
+
+ r = dns_packet_read_memdup(p,
+ rdlength + offset - p->rindex,
+ &rr->caa.value, &rr->caa.value_size, NULL);
break;
@@ -2021,16 +1997,13 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
default:
unparseable:
r = dns_packet_read_memdup(p, rdlength, &rr->generic.data, &rr->generic.data_size, NULL);
- if (r < 0)
- goto fail;
+
break;
}
if (r < 0)
- goto fail;
- if (p->rindex != offset + rdlength) {
- r = -EBADMSG;
- goto fail;
- }
+ return r;
+ if (p->rindex != offset + rdlength)
+ return -EBADMSG;
*ret = rr;
rr = NULL;
@@ -2038,12 +2011,10 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
if (ret_cache_flush)
*ret_cache_flush = cache_flush;
if (start)
- *start = saved_rindex;
+ *start = rewinder.saved_rindex;
+ CANCEL_REWINDER(rewinder);
return 0;
-fail:
- dns_packet_rewind(p, saved_rindex);
- return r;
}
static bool opt_is_good(DnsResourceRecord *rr, bool *rfc6975) {
@@ -2091,23 +2062,21 @@ static bool opt_is_good(DnsResourceRecord *rr, bool *rfc6975) {
int dns_packet_extract(DnsPacket *p) {
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
- size_t saved_rindex;
+ _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder = {};
unsigned n, i;
int r;
if (p->extracted)
return 0;
- saved_rindex = p->rindex;
+ INIT_REWINDER(rewinder, p);
dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE);
n = DNS_PACKET_QDCOUNT(p);
if (n > 0) {
question = dns_question_new(n);
- if (!question) {
- r = -ENOMEM;
- goto finish;
- }
+ if (!question)
+ return -ENOMEM;
for (i = 0; i < n; i++) {
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
@@ -2115,21 +2084,17 @@ int dns_packet_extract(DnsPacket *p) {
r = dns_packet_read_key(p, &key, &cache_flush, NULL);
if (r < 0)
- goto finish;
+ return r;
- if (cache_flush) {
- r = -EBADMSG;
- goto finish;
- }
+ if (cache_flush)
+ return -EBADMSG;
- if (!dns_type_is_valid_query(key->type)) {
- r = -EBADMSG;
- goto finish;
- }
+ if (!dns_type_is_valid_query(key->type))
+ return -EBADMSG;
r = dns_question_add(question, key);
if (r < 0)
- goto finish;
+ return r;
}
}
@@ -2139,10 +2104,8 @@ int dns_packet_extract(DnsPacket *p) {
bool bad_opt = false;
answer = dns_answer_new(n);
- if (!answer) {
- r = -ENOMEM;
- goto finish;
- }
+ if (!answer)
+ return -ENOMEM;
for (i = 0; i < n; i++) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
@@ -2150,7 +2113,7 @@ int dns_packet_extract(DnsPacket *p) {
r = dns_packet_read_rr(p, &rr, &cache_flush, NULL);
if (r < 0)
- goto finish;
+ return r;
/* Try to reduce memory usage a bit */
if (previous)
@@ -2167,7 +2130,7 @@ int dns_packet_extract(DnsPacket *p) {
continue;
}
- if (!dns_name_is_root(DNS_RESOURCE_KEY_NAME(rr->key))) {
+ if (!dns_name_is_root(dns_resource_key_name(rr->key))) {
/* If the OPT RR is not owned by the root domain, then it is bad, let's ignore
* it. */
log_debug("OPT RR is not owned by root domain, ignoring.");
@@ -2213,7 +2176,7 @@ int dns_packet_extract(DnsPacket *p) {
(i < DNS_PACKET_ANCOUNT(p) ? DNS_ANSWER_CACHEABLE : 0) |
(p->protocol == DNS_PROTOCOL_MDNS && !cache_flush ? DNS_ANSWER_SHARED_OWNER : 0));
if (r < 0)
- goto finish;
+ return r;
}
/* Remember this RR, so that we potentically can merge it's ->key object with the next RR. Note
@@ -2234,11 +2197,8 @@ int dns_packet_extract(DnsPacket *p) {
p->extracted = true;
- r = 0;
-
-finish:
- p->rindex = saved_rindex;
- return r;
+ /* no CANCEL, always rewind */
+ return 0;
}
int dns_packet_is_reply_for(DnsPacket *p, const DnsResourceKey *key) {
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-packet.h b/src/grp-resolve/systemd-resolved/resolved-dns-packet.h
index 0bf34d270c..416335d0a2 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-packet.h
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-packet.h
@@ -262,11 +262,9 @@ static inline uint64_t SD_RESOLVED_FLAGS_MAKE(DnsProtocol protocol, int family,
return f|(family == AF_INET6 ? SD_RESOLVED_LLMNR_IPV6 : SD_RESOLVED_LLMNR_IPV4);
case DNS_PROTOCOL_MDNS:
- return family == AF_INET6 ? SD_RESOLVED_MDNS_IPV6 : SD_RESOLVED_MDNS_IPV4;
+ return f|(family == AF_INET6 ? SD_RESOLVED_MDNS_IPV6 : SD_RESOLVED_MDNS_IPV4);
default:
- break;
+ return f;
}
-
- return 0;
}
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-query.c b/src/grp-resolve/systemd-resolved/resolved-dns-query.c
index a378b2b7f7..ea04e58d61 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-query.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-query.c
@@ -62,6 +62,7 @@ static void dns_query_candidate_stop(DnsQueryCandidate *c) {
while ((t = set_steal_first(c->transactions))) {
set_remove(t->notify_query_candidates, c);
+ set_remove(t->notify_query_candidates_done, c);
dns_transaction_gc(t);
}
}
@@ -139,6 +140,10 @@ static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResource
if (r < 0)
goto gc;
+ r = set_ensure_allocated(&t->notify_query_candidates_done, NULL);
+ if (r < 0)
+ goto gc;
+
r = set_put(t->notify_query_candidates, c);
if (r < 0)
goto gc;
@@ -421,6 +426,7 @@ int dns_query_new(
DnsResourceKey *key;
bool good = false;
int r;
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
assert(m);
@@ -471,31 +477,20 @@ int dns_query_new(
q->answer_family = AF_UNSPEC;
/* First dump UTF8 question */
- DNS_QUESTION_FOREACH(key, question_utf8) {
- _cleanup_free_ char *p = NULL;
-
- r = dns_resource_key_to_string(key, &p);
- if (r < 0)
- return r;
-
- log_debug("Looking up RR for %s.", strstrip(p));
- }
+ DNS_QUESTION_FOREACH(key, question_utf8)
+ log_debug("Looking up RR for %s.",
+ dns_resource_key_to_string(key, key_str, sizeof key_str));
/* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */
DNS_QUESTION_FOREACH(key, question_idna) {
- _cleanup_free_ char *p = NULL;
-
r = dns_question_contains(question_utf8, key);
if (r < 0)
return r;
if (r > 0)
continue;
- r = dns_resource_key_to_string(key, &p);
- if (r < 0)
- return r;
-
- log_debug("Looking up IDNA RR for %s.", strstrip(p));
+ log_debug("Looking up IDNA RR for %s.",
+ dns_resource_key_to_string(key, key_str, sizeof key_str));
}
LIST_PREPEND(queries, m->dns_queries, q);
@@ -815,7 +810,7 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) {
switch (t->state) {
case DNS_TRANSACTION_SUCCESS: {
- /* We found a successfuly reply, merge it into the answer */
+ /* We found a successfully reply, merge it into the answer */
r = dns_answer_extend(&q->answer, t->answer);
if (r < 0)
goto fail;
@@ -937,7 +932,7 @@ static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname)
assert(q);
- q->n_cname_redirects ++;
+ q->n_cname_redirects++;
if (q->n_cname_redirects > CNAME_MAX)
return -ELOOP;
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-question.c b/src/grp-resolve/systemd-resolved/resolved-dns-question.c
index 8e452e79a4..c8b502d1cd 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-question.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-question.c
@@ -145,7 +145,7 @@ int dns_question_is_valid_for_query(DnsQuestion *q) {
if (q->n_keys > 65535)
return 0;
- name = DNS_RESOURCE_KEY_NAME(q->keys[0]);
+ name = dns_resource_key_name(q->keys[0]);
if (!name)
return 0;
@@ -154,7 +154,7 @@ int dns_question_is_valid_for_query(DnsQuestion *q) {
assert(q->keys[i]);
if (i > 0) {
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), name);
+ r = dns_name_equal(dns_resource_key_name(q->keys[i]), name);
if (r <= 0)
return r;
}
@@ -235,7 +235,7 @@ int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname,
if (cname->key->type == DNS_TYPE_CNAME)
d = cname->cname.name;
else {
- r = dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname->key), cname->dname.name, &destination);
+ r = dns_name_change_suffix(dns_resource_key_name(key), dns_resource_key_name(cname->key), cname->dname.name, &destination);
if (r < 0)
return r;
if (r == 0)
@@ -244,7 +244,7 @@ int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname,
d = destination;
}
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(key), d);
+ r = dns_name_equal(dns_resource_key_name(key), d);
if (r < 0)
return r;
@@ -291,7 +291,7 @@ const char *dns_question_first_name(DnsQuestion *q) {
if (q->n_keys < 1)
return NULL;
- return DNS_RESOURCE_KEY_NAME(q->keys[0]);
+ return dns_resource_key_name(q->keys[0]);
}
int dns_question_new_address(DnsQuestion **ret, int family, const char *name, bool convert_idna) {
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-rr.c b/src/grp-resolve/systemd-resolved/resolved-dns-rr.c
index 40f8e28dfd..6a29a93a26 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-rr.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-rr.c
@@ -22,6 +22,7 @@
#include "alloc-util.h"
#include "dns-domain.h"
#include "dns-type.h"
+#include "escape.h"
#include "hexdecoct.h"
#include "resolved-dns-dnssec.h"
#include "resolved-dns-packet.h"
@@ -65,7 +66,7 @@ DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const D
DnsResourceKey *k;
char *destination = NULL;
- r = dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname->key), cname->dname.name, &destination);
+ r = dns_name_change_suffix(dns_resource_key_name(key), dns_resource_key_name(cname->key), cname->dname.name, &destination);
if (r < 0)
return NULL;
if (r == 0)
@@ -95,7 +96,7 @@ int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key
return 0;
}
- r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), name, &joined);
+ r = dns_name_concat(dns_resource_key_name(key), name, &joined);
if (r < 0)
return r;
@@ -157,6 +158,23 @@ DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) {
return NULL;
}
+const char* dns_resource_key_name(const DnsResourceKey *key) {
+ const char *name;
+
+ if (!key)
+ return NULL;
+
+ if (key->_name)
+ name = key->_name;
+ else
+ name = (char*) key + sizeof(DnsResourceKey);
+
+ if (dns_name_is_root(name))
+ return ".";
+ else
+ return name;
+}
+
bool dns_resource_key_is_address(const DnsResourceKey *key) {
assert(key);
@@ -171,7 +189,7 @@ int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
if (a == b)
return 1;
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
+ r = dns_name_equal(dns_resource_key_name(a), dns_resource_key_name(b));
if (r <= 0)
return r;
@@ -203,18 +221,18 @@ int dns_resource_key_match_rr(const DnsResourceKey *key, DnsResourceRecord *rr,
if (rr->key->type != key->type && key->type != DNS_TYPE_ANY)
return 0;
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
+ r = dns_name_equal(dns_resource_key_name(rr->key), dns_resource_key_name(key));
if (r != 0)
return r;
if (search_domain) {
_cleanup_free_ char *joined = NULL;
- r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined);
+ r = dns_name_concat(dns_resource_key_name(key), search_domain, &joined);
if (r < 0)
return r;
- return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), joined);
+ return dns_name_equal(dns_resource_key_name(rr->key), joined);
}
return 0;
@@ -230,9 +248,9 @@ int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsRe
return 0;
if (cname->type == DNS_TYPE_CNAME)
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname));
+ r = dns_name_equal(dns_resource_key_name(key), dns_resource_key_name(cname));
else if (cname->type == DNS_TYPE_DNAME)
- r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname));
+ r = dns_name_endswith(dns_resource_key_name(key), dns_resource_key_name(cname));
else
return 0;
@@ -242,14 +260,14 @@ int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsRe
if (search_domain) {
_cleanup_free_ char *joined = NULL;
- r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined);
+ r = dns_name_concat(dns_resource_key_name(key), search_domain, &joined);
if (r < 0)
return r;
if (cname->type == DNS_TYPE_CNAME)
- return dns_name_equal(joined, DNS_RESOURCE_KEY_NAME(cname));
+ return dns_name_equal(joined, dns_resource_key_name(cname));
else if (cname->type == DNS_TYPE_DNAME)
- return dns_name_endswith(joined, DNS_RESOURCE_KEY_NAME(cname));
+ return dns_name_endswith(joined, dns_resource_key_name(cname));
}
return 0;
@@ -267,7 +285,7 @@ int dns_resource_key_match_soa(const DnsResourceKey *key, const DnsResourceKey *
if (soa->type != DNS_TYPE_SOA)
return 0;
- return dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(soa));
+ return dns_name_endswith(dns_resource_key_name(key), dns_resource_key_name(soa));
}
static void dns_resource_key_hash_func(const void *i, struct siphash *state) {
@@ -275,7 +293,7 @@ static void dns_resource_key_hash_func(const void *i, struct siphash *state) {
assert(k);
- dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), state);
+ dns_name_hash_func(dns_resource_key_name(k), state);
siphash24_compress(&k->class, sizeof(k->class), state);
siphash24_compress(&k->type, sizeof(k->type), state);
}
@@ -284,7 +302,7 @@ static int dns_resource_key_compare_func(const void *a, const void *b) {
const DnsResourceKey *x = a, *y = b;
int ret;
- ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y));
+ ret = dns_name_compare_func(dns_resource_key_name(x), dns_resource_key_name(y));
if (ret != 0)
return ret;
@@ -306,32 +324,22 @@ const struct hash_ops dns_resource_key_hash_ops = {
.compare = dns_resource_key_compare_func
};
-int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
- char cbuf[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
- const char *c, *t, *n;
- char *s;
+char* dns_resource_key_to_string(const DnsResourceKey *key, char *buf, size_t buf_size) {
+ const char *c, *t;
+ char *ans = buf;
/* If we cannot convert the CLASS/TYPE into a known string,
use the format recommended by RFC 3597, Section 5. */
c = dns_class_to_string(key->class);
- if (!c) {
- sprintf(cbuf, "CLASS%u", key->class);
- c = cbuf;
- }
-
t = dns_type_to_string(key->type);
- if (!t){
- sprintf(tbuf, "TYPE%u", key->type);
- t = tbuf;
- }
- n = DNS_RESOURCE_KEY_NAME(key);
- if (asprintf(&s, "%s%s %s %-5s", n, endswith(n, ".") ? "" : ".", c, t) < 0)
- return -ENOMEM;
+ snprintf(buf, buf_size, "%s %s%s%.0u %s%s%.0u",
+ dns_resource_key_name(key),
+ c ?: "", c ? "" : "CLASS", c ? 0 : key->class,
+ t ?: "", t ? "" : "TYPE", t ? 0 : key->class);
- *ret = s;
- return 0;
+ return ans;
}
bool dns_resource_key_reduce(DnsResourceKey **a, DnsResourceKey **b) {
@@ -490,6 +498,11 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
free(rr->tlsa.data);
break;
+ case DNS_TYPE_CAA:
+ free(rr->caa.tag);
+ free(rr->caa.value);
+ break;
+
case DNS_TYPE_OPENPGPKEY:
default:
free(rr->generic.data);
@@ -697,6 +710,12 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor
a->tlsa.matching_type == b->tlsa.matching_type &&
FIELD_EQUAL(a->tlsa, b->tlsa, data);
+ case DNS_TYPE_CAA:
+ return a->caa.flags == b->caa.flags &&
+ streq(a->caa.tag, b->caa.tag) &&
+ FIELD_EQUAL(a->caa, b->caa, value);
+
+ case DNS_TYPE_OPENPGPKEY:
default:
return FIELD_EQUAL(a->generic, b->generic, data);
}
@@ -818,8 +837,8 @@ static char *format_txt(DnsTxtItem *first) {
}
const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
- _cleanup_free_ char *k = NULL, *t = NULL;
- char *s;
+ _cleanup_free_ char *t = NULL;
+ char *s, k[DNS_RESOURCE_KEY_STRING_MAX];
int r;
assert(rr);
@@ -827,9 +846,7 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
if (rr->to_string)
return rr->to_string;
- r = dns_resource_key_to_string(rr->key, &k);
- if (r < 0)
- return NULL;
+ dns_resource_key_to_string(rr->key, k, sizeof(k));
switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
@@ -966,7 +983,7 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
case DNS_TYPE_DNSKEY: {
_cleanup_free_ char *alg = NULL;
char *ss;
- int n, n1;
+ int n;
uint16_t key_tag;
key_tag = dnssec_keytag(rr, true);
@@ -975,9 +992,8 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
if (r < 0)
return NULL;
- r = asprintf(&s, "%s %n%u %u %s %n",
+ r = asprintf(&s, "%s %u %u %s %n",
k,
- &n1,
rr->dnskey.flags,
rr->dnskey.protocol,
alg,
@@ -992,14 +1008,12 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
return NULL;
r = asprintf(&ss, "%s\n"
- "%*s-- Flags:%s%s%s\n"
- "%*s-- Key tag: %u",
+ " -- Flags:%s%s%s\n"
+ " -- Key tag: %u",
s,
- n1, "",
rr->dnskey.flags & DNSKEY_FLAG_SEP ? " SEP" : "",
rr->dnskey.flags & DNSKEY_FLAG_REVOKE ? " REVOKE" : "",
rr->dnskey.flags & DNSKEY_FLAG_ZONE_KEY ? " ZONE_KEY" : "",
- n1, "",
key_tag);
if (r < 0)
return NULL;
@@ -1102,40 +1116,52 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
case DNS_TYPE_TLSA: {
const char *cert_usage, *selector, *matching_type;
- char *ss;
- int n;
cert_usage = tlsa_cert_usage_to_string(rr->tlsa.cert_usage);
selector = tlsa_selector_to_string(rr->tlsa.selector);
matching_type = tlsa_matching_type_to_string(rr->tlsa.matching_type);
- r = asprintf(&s, "%s %u %u %u %n",
+ t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
+ if (!t)
+ return NULL;
+
+ r = asprintf(&s,
+ "%s %u %u %u %s\n"
+ " -- Cert. usage: %s\n"
+ " -- Selector: %s\n"
+ " -- Matching type: %s",
k,
rr->tlsa.cert_usage,
rr->tlsa.selector,
rr->tlsa.matching_type,
- &n);
+ t,
+ cert_usage,
+ selector,
+ matching_type);
if (r < 0)
return NULL;
- r = base64_append(&s, n,
- rr->tlsa.data, rr->tlsa.data_size,
- 8, columns());
- if (r < 0)
+ break;
+ }
+
+ case DNS_TYPE_CAA: {
+ _cleanup_free_ char *value;
+
+ value = octescape(rr->caa.value, rr->caa.value_size);
+ if (!value)
return NULL;
- r = asprintf(&ss, "%s\n"
- "%*s-- Cert. usage: %s\n"
- "%*s-- Selector: %s\n"
- "%*s-- Matching type: %s",
- s,
- n - 6, "", cert_usage,
- n - 6, "", selector,
- n - 6, "", matching_type);
+ r = asprintf(&s, "%s %u %s \"%s\"%s%s%s%.0u",
+ k,
+ rr->caa.flags,
+ rr->caa.tag,
+ value,
+ rr->caa.flags ? "\n -- Flags:" : "",
+ rr->caa.flags & CAA_FLAG_CRITICAL ? " critical" : "",
+ rr->caa.flags & ~CAA_FLAG_CRITICAL ? " " : "",
+ rr->caa.flags & ~CAA_FLAG_CRITICAL);
if (r < 0)
return NULL;
- free(s);
- s = ss;
break;
}
@@ -1173,6 +1199,47 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
return s;
}
+ssize_t dns_resource_record_payload(DnsResourceRecord *rr, void **out) {
+ assert(rr);
+ assert(out);
+
+ switch(rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
+ case DNS_TYPE_SRV:
+ case DNS_TYPE_PTR:
+ case DNS_TYPE_NS:
+ case DNS_TYPE_CNAME:
+ case DNS_TYPE_DNAME:
+ case DNS_TYPE_HINFO:
+ case DNS_TYPE_SPF:
+ case DNS_TYPE_TXT:
+ case DNS_TYPE_A:
+ case DNS_TYPE_AAAA:
+ case DNS_TYPE_SOA:
+ case DNS_TYPE_MX:
+ case DNS_TYPE_LOC:
+ case DNS_TYPE_DS:
+ case DNS_TYPE_DNSKEY:
+ case DNS_TYPE_RRSIG:
+ case DNS_TYPE_NSEC:
+ case DNS_TYPE_NSEC3:
+ return -EINVAL;
+
+ case DNS_TYPE_SSHFP:
+ *out = rr->sshfp.fingerprint;
+ return rr->sshfp.fingerprint_size;
+
+ case DNS_TYPE_TLSA:
+ *out = rr->tlsa.data;
+ return rr->tlsa.data_size;
+
+
+ case DNS_TYPE_OPENPGPKEY:
+ default:
+ *out = rr->generic.data;
+ return rr->generic.data_size;
+ }
+}
+
int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) {
DnsPacket packet = {
@@ -1230,7 +1297,7 @@ int dns_resource_record_signer(DnsResourceRecord *rr, const char **ret) {
if (rr->n_skip_labels_signer == (unsigned) -1)
return -ENODATA;
- n = DNS_RESOURCE_KEY_NAME(rr->key);
+ n = dns_resource_key_name(rr->key);
r = dns_name_skip(n, rr->n_skip_labels_signer, &n);
if (r < 0)
return r;
@@ -1253,7 +1320,7 @@ int dns_resource_record_source(DnsResourceRecord *rr, const char **ret) {
if (rr->n_skip_labels_source == (unsigned) -1)
return -ENODATA;
- n = DNS_RESOURCE_KEY_NAME(rr->key);
+ n = dns_resource_key_name(rr->key);
r = dns_name_skip(n, rr->n_skip_labels_source, &n);
if (r < 0)
return r;
@@ -1293,14 +1360,14 @@ int dns_resource_record_is_synthetic(DnsResourceRecord *rr) {
if (rr->n_skip_labels_source > 1)
return 1;
- r = dns_name_startswith(DNS_RESOURCE_KEY_NAME(rr->key), "*");
+ r = dns_name_startswith(dns_resource_key_name(rr->key), "*");
if (r < 0)
return r;
return !r;
}
-static void dns_resource_record_hash_func(const void *i, struct siphash *state) {
+void dns_resource_record_hash_func(const void *i, struct siphash *state) {
const DnsResourceRecord *rr = i;
assert(rr);
@@ -1427,7 +1494,13 @@ static void dns_resource_record_hash_func(const void *i, struct siphash *state)
siphash24_compress(&rr->tlsa.cert_usage, sizeof(rr->tlsa.cert_usage), state);
siphash24_compress(&rr->tlsa.selector, sizeof(rr->tlsa.selector), state);
siphash24_compress(&rr->tlsa.matching_type, sizeof(rr->tlsa.matching_type), state);
- siphash24_compress(&rr->tlsa.data, rr->tlsa.data_size, state);
+ siphash24_compress(rr->tlsa.data, rr->tlsa.data_size, state);
+ break;
+
+ case DNS_TYPE_CAA:
+ siphash24_compress(&rr->caa.flags, sizeof(rr->caa.flags), state);
+ string_hash_func(rr->caa.tag, state);
+ siphash24_compress(rr->caa.value, rr->caa.value_size, state);
break;
case DNS_TYPE_OPENPGPKEY:
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-rr.h b/src/grp-resolve/systemd-resolved/resolved-dns-rr.h
index 2e0dfbaba3..020a2abd77 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-rr.h
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-rr.h
@@ -26,6 +26,7 @@
#include "hashmap.h"
#include "in-addr-util.h"
#include "list.h"
+#include "string-util.h"
typedef struct DnsResourceKey DnsResourceKey;
typedef struct DnsResourceRecord DnsResourceRecord;
@@ -81,7 +82,7 @@ enum {
struct DnsResourceKey {
unsigned n_ref; /* (unsigned -1) for const keys, see below */
uint16_t class, type;
- char *_name; /* don't access directy, use DNS_RESOURCE_KEY_NAME()! */
+ char *_name; /* don't access directly, use dns_resource_key_name()! */
};
/* Creates a temporary resource key. This is only useful to quickly
@@ -249,19 +250,17 @@ struct DnsResourceRecord {
void *data;
size_t data_size;
} tlsa;
+
+ /* https://tools.ietf.org/html/rfc6844 */
+ struct {
+ uint8_t flags;
+ char *tag;
+ void *value;
+ size_t value_size;
+ } caa;
};
};
-static inline const char* DNS_RESOURCE_KEY_NAME(const DnsResourceKey *key) {
- if (!key)
- return NULL;
-
- if (key->_name)
- return key->_name;
-
- return (char*) key + sizeof(DnsResourceKey);
-}
-
static inline const void* DNS_RESOURCE_RECORD_RDATA(DnsResourceRecord *rr) {
if (!rr)
return NULL;
@@ -289,12 +288,20 @@ int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key
DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name);
DnsResourceKey* dns_resource_key_ref(DnsResourceKey *key);
DnsResourceKey* dns_resource_key_unref(DnsResourceKey *key);
+const char* dns_resource_key_name(const DnsResourceKey *key);
bool dns_resource_key_is_address(const DnsResourceKey *key);
int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b);
int dns_resource_key_match_rr(const DnsResourceKey *key, DnsResourceRecord *rr, const char *search_domain);
int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsResourceKey *cname, const char *search_domain);
int dns_resource_key_match_soa(const DnsResourceKey *key, const DnsResourceKey *soa);
-int dns_resource_key_to_string(const DnsResourceKey *key, char **ret);
+
+/* _DNS_{CLASS,TYPE}_STRING_MAX include one byte for NUL, which we use for space instead below.
+ * DNS_HOSTNAME_MAX does not include the NUL byte, so we need to add 1. */
+#define DNS_RESOURCE_KEY_STRING_MAX (_DNS_CLASS_STRING_MAX + _DNS_TYPE_STRING_MAX + DNS_HOSTNAME_MAX + 1)
+
+char* dns_resource_key_to_string(const DnsResourceKey *key, char *buf, size_t buf_size);
+ssize_t dns_resource_record_payload(DnsResourceRecord *rr, void **out);
+
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceKey*, dns_resource_key_unref);
static inline bool dns_key_is_shared(const DnsResourceKey *key) {
@@ -323,6 +330,8 @@ int dns_resource_record_is_synthetic(DnsResourceRecord *rr);
DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i);
bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b);
+void dns_resource_record_hash_func(const void *i, struct siphash *state);
+
extern const struct hash_ops dns_resource_key_hash_ops;
extern const struct hash_ops dns_resource_record_hash_ops;
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-scope.c b/src/grp-resolve/systemd-resolved/resolved-dns-scope.c
index a406872a38..66e4585c18 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-scope.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-scope.c
@@ -514,8 +514,8 @@ bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key) {
* that those should be resolved via LLMNR or search
* path only, and should not be leaked onto the
* internet. */
- return !(dns_name_is_single_label(DNS_RESOURCE_KEY_NAME(key)) ||
- dns_name_is_root(DNS_RESOURCE_KEY_NAME(key)));
+ return !(dns_name_is_single_label(dns_resource_key_name(key)) ||
+ dns_name_is_root(dns_resource_key_name(key)));
}
/* On mDNS and LLMNR, send A and AAAA queries only on the
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-server.c b/src/grp-resolve/systemd-resolved/resolved-dns-server.c
index 27342a0e04..3095c042db 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-server.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-server.c
@@ -120,7 +120,7 @@ DnsServer* dns_server_ref(DnsServer *s) {
return NULL;
assert(s->n_ref > 0);
- s->n_ref ++;
+ s->n_ref++;
return s;
}
@@ -130,7 +130,7 @@ DnsServer* dns_server_unref(DnsServer *s) {
return NULL;
assert(s->n_ref > 0);
- s->n_ref --;
+ s->n_ref--;
if (s->n_ref > 0)
return NULL;
@@ -157,6 +157,7 @@ void dns_server_unlink(DnsServer *s) {
assert(s->link);
assert(s->link->n_dns_servers > 0);
LIST_REMOVE(servers, s->link->dns_servers, s);
+ s->link->n_dns_servers--;
break;
case DNS_SERVER_SYSTEM:
@@ -290,9 +291,9 @@ void dns_server_packet_lost(DnsServer *s, int protocol, DnsServerFeatureLevel le
if (s->possible_feature_level == level) {
if (protocol == IPPROTO_UDP)
- s->n_failed_udp ++;
+ s->n_failed_udp++;
else if (protocol == IPPROTO_TCP)
- s->n_failed_tcp ++;
+ s->n_failed_tcp++;
}
if (s->resend_timeout > usec)
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-synthesize.c b/src/grp-resolve/systemd-resolved/resolved-dns-synthesize.c
index f4a43dee8c..e3003411f7 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-synthesize.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-synthesize.c
@@ -86,7 +86,7 @@ static int synthesize_localhost_rr(Manager *m, const DnsResourceKey *key, int if
if (IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_ANY)) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
- rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, DNS_RESOURCE_KEY_NAME(key));
+ rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, dns_resource_key_name(key));
if (!rr)
return -ENOMEM;
@@ -100,7 +100,7 @@ static int synthesize_localhost_rr(Manager *m, const DnsResourceKey *key, int if
if (IN_SET(key->type, DNS_TYPE_AAAA, DNS_TYPE_ANY)) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
- rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, DNS_RESOURCE_KEY_NAME(key));
+ rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, dns_resource_key_name(key));
if (!rr)
return -ENOMEM;
@@ -140,7 +140,7 @@ static int synthesize_localhost_ptr(Manager *m, const DnsResourceKey *key, int i
if (r < 0)
return r;
- r = answer_add_ptr(answer, DNS_RESOURCE_KEY_NAME(key), "localhost", dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
+ r = answer_add_ptr(answer, dns_resource_key_name(key), "localhost", dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
if (r < 0)
return r;
}
@@ -254,11 +254,11 @@ static int synthesize_system_hostname_rr(Manager *m, const DnsResourceKey *key,
.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);
}
}
- return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n);
+ return answer_add_addresses_rr(answer, dns_resource_key_name(key), addresses, n);
}
static int synthesize_system_hostname_ptr(Manager *m, int af, const union in_addr_union *address, int ifindex, DnsAnswer **answer) {
@@ -319,7 +319,7 @@ static int synthesize_gateway_rr(Manager *m, const DnsResourceKey *key, int ifin
return n;
}
- return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n);
+ return answer_add_addresses_rr(answer, dns_resource_key_name(key), addresses, n);
}
static int synthesize_gateway_ptr(Manager *m, int af, const union in_addr_union *address, int ifindex, DnsAnswer **answer) {
@@ -360,7 +360,7 @@ int dns_synthesize_answer(
key->class != DNS_CLASS_ANY)
continue;
- name = DNS_RESOURCE_KEY_NAME(key);
+ name = dns_resource_key_name(key);
if (is_localhost(name)) {
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-transaction.c b/src/grp-resolve/systemd-resolved/resolved-dns-transaction.c
index d48fdd1281..a4a67623e7 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-transaction.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-transaction.c
@@ -52,6 +52,7 @@ static void dns_transaction_flush_dnssec_transactions(DnsTransaction *t) {
while ((z = set_steal_first(t->dnssec_transactions))) {
set_remove(z->notify_transactions, t);
+ set_remove(z->notify_transactions_done, t);
dns_transaction_gc(z);
}
}
@@ -100,20 +101,31 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) {
set_remove(c->transactions, t);
set_free(t->notify_query_candidates);
+ while ((c = set_steal_first(t->notify_query_candidates_done)))
+ set_remove(c->transactions, t);
+ set_free(t->notify_query_candidates_done);
+
while ((i = set_steal_first(t->notify_zone_items)))
i->probe_transaction = NULL;
set_free(t->notify_zone_items);
+ while ((i = set_steal_first(t->notify_zone_items_done)))
+ i->probe_transaction = NULL;
+ set_free(t->notify_zone_items_done);
+
while ((z = set_steal_first(t->notify_transactions)))
set_remove(z->dnssec_transactions, t);
set_free(t->notify_transactions);
+ while ((z = set_steal_first(t->notify_transactions_done)))
+ set_remove(z->dnssec_transactions, t);
+ set_free(t->notify_transactions_done);
+
dns_transaction_flush_dnssec_transactions(t);
set_free(t->dnssec_transactions);
dns_answer_unref(t->validated_keys);
dns_resource_key_unref(t->key);
- free(t->key_string);
free(t);
return NULL;
@@ -128,8 +140,11 @@ bool dns_transaction_gc(DnsTransaction *t) {
return true;
if (set_isempty(t->notify_query_candidates) &&
+ set_isempty(t->notify_query_candidates_done) &&
set_isempty(t->notify_zone_items) &&
- set_isempty(t->notify_transactions)) {
+ set_isempty(t->notify_zone_items_done) &&
+ set_isempty(t->notify_transactions) &&
+ set_isempty(t->notify_transactions_done)) {
dns_transaction_free(t);
return false;
}
@@ -210,7 +225,7 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key)
LIST_PREPEND(transactions_by_scope, s->transactions, t);
t->scope = s;
- s->manager->n_transactions_total ++;
+ s->manager->n_transactions_total++;
if (ret)
*ret = t;
@@ -238,6 +253,7 @@ static void dns_transaction_shuffle_id(DnsTransaction *t) {
static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) {
_cleanup_free_ char *pretty = NULL;
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
DnsZoneItem *z;
assert(t);
@@ -246,15 +262,15 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) {
if (manager_our_packet(t->scope->manager, p) != 0)
return;
- in_addr_to_string(p->family, &p->sender, &pretty);
+ (void) in_addr_to_string(p->family, &p->sender, &pretty);
log_debug("Transaction %" PRIu16 " for <%s> on scope %s on %s/%s got tentative packet from %s.",
t->id,
- dns_transaction_key_string(t),
+ dns_resource_key_to_string(t->key, key_str, sizeof key_str),
dns_protocol_to_string(t->scope->protocol),
t->scope->link ? t->scope->link->name : "*",
- t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family),
- pretty);
+ af_to_name_short(t->scope->family),
+ strnull(pretty));
/* RFC 4795, Section 4.1 says that the peer with the
* lexicographically smaller IP address loses */
@@ -266,6 +282,7 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) {
log_debug("We have the lexicographically larger IP address and thus lost in the conflict.");
t->block_gc++;
+
while ((z = set_first(t->notify_zone_items))) {
/* First, make sure the zone item drops the reference
* to us */
@@ -284,22 +301,25 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
DnsQueryCandidate *c;
DnsZoneItem *z;
DnsTransaction *d;
- Iterator i;
const char *st;
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
assert(t);
assert(!DNS_TRANSACTION_IS_LIVE(state));
- if (state == DNS_TRANSACTION_DNSSEC_FAILED)
+ if (state == DNS_TRANSACTION_DNSSEC_FAILED) {
+ dns_resource_key_to_string(t->key, key_str, sizeof key_str);
+
log_struct(LOG_NOTICE,
LOG_MESSAGE_ID(SD_MESSAGE_DNSSEC_FAILURE),
- LOG_MESSAGE("DNSSEC validation failed for question %s: %s", dns_transaction_key_string(t), dnssec_result_to_string(t->answer_dnssec_result)),
+ LOG_MESSAGE("DNSSEC validation failed for question %s: %s", key_str, dnssec_result_to_string(t->answer_dnssec_result)),
"DNS_TRANSACTION=%" PRIu16, t->id,
- "DNS_QUESTION=%s", dns_transaction_key_string(t),
+ "DNS_QUESTION=%s", key_str,
"DNSSEC_RESULT=%s", dnssec_result_to_string(t->answer_dnssec_result),
"DNS_SERVER=%s", dns_server_string(t->server),
"DNS_SERVER_FEATURE_LEVEL=%s", dns_server_feature_level_to_string(t->server->possible_feature_level),
NULL);
+ }
/* Note that this call might invalidate the query. Callers
* should hence not attempt to access the query or transaction
@@ -312,10 +332,10 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
log_debug("Transaction %" PRIu16 " for <%s> on scope %s on %s/%s now complete with <%s> from %s (%s).",
t->id,
- dns_transaction_key_string(t),
+ dns_resource_key_to_string(t->key, key_str, sizeof key_str),
dns_protocol_to_string(t->scope->protocol),
t->scope->link ? t->scope->link->name : "*",
- t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family),
+ af_to_name_short(t->scope->family),
st,
t->answer_source < 0 ? "none" : dns_transaction_source_to_string(t->answer_source),
t->answer_authenticated ? "authenticated" : "unsigned");
@@ -329,39 +349,17 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
* transaction isn't freed while we are still looking at it */
t->block_gc++;
- SET_FOREACH(c, t->notify_query_candidates, i)
+ SET_FOREACH_MOVE(c, t->notify_query_candidates_done, t->notify_query_candidates)
dns_query_candidate_notify(c);
- SET_FOREACH(z, t->notify_zone_items, i)
- dns_zone_item_notify(z);
-
- if (!set_isempty(t->notify_transactions)) {
- DnsTransaction **nt;
- unsigned j, n = 0;
-
- /* We need to be careful when notifying other
- * transactions, as that might destroy other
- * transactions in our list. Hence, in order to be
- * able to safely iterate through the list of
- * transactions, take a GC lock on all of them
- * first. Then, in a second loop, notify them, but
- * first unlock that specific transaction. */
-
- nt = newa(DnsTransaction*, set_size(t->notify_transactions));
- SET_FOREACH(d, t->notify_transactions, i) {
- nt[n++] = d;
- d->block_gc++;
- }
+ SWAP_TWO(t->notify_query_candidates, t->notify_query_candidates_done);
- assert(n == set_size(t->notify_transactions));
-
- for (j = 0; j < n; j++) {
- if (set_contains(t->notify_transactions, nt[j]))
- dns_transaction_notify(nt[j], t);
+ SET_FOREACH_MOVE(z, t->notify_zone_items_done, t->notify_zone_items)
+ dns_zone_item_notify(z);
+ SWAP_TWO(t->notify_zone_items, t->notify_zone_items_done);
- nt[j]->block_gc--;
- dns_transaction_gc(nt[j]);
- }
- }
+ SET_FOREACH_MOVE(d, t->notify_transactions_done, t->notify_transactions)
+ dns_transaction_notify(d, t);
+ SWAP_TWO(t->notify_transactions, t->notify_transactions_done);
t->block_gc--;
dns_transaction_gc(t);
@@ -522,7 +520,7 @@ static int dns_transaction_open_tcp(DnsTransaction *t) {
* the IP address, in case this is a reverse
* PTR lookup */
- r = dns_name_address(DNS_RESOURCE_KEY_NAME(t->key), &family, &address);
+ r = dns_name_address(dns_resource_key_name(t->key), &family, &address);
if (r < 0)
return r;
if (r == 0)
@@ -1209,7 +1207,7 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) {
return 0;
}
- if (dns_name_is_root(DNS_RESOURCE_KEY_NAME(t->key)) &&
+ if (dns_name_is_root(dns_resource_key_name(t->key)) &&
t->key->type == DNS_TYPE_DS) {
/* Hmm, this is a request for the root DS? A
@@ -1237,8 +1235,7 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) {
* might be DS RRs, but we don't know
* them, and the DNS server won't tell
* them to us (and even if it would,
- * we couldn't validate it and trust
- * it). */
+ * we couldn't validate and trust them. */
dns_transaction_complete(t, DNS_TRANSACTION_NO_TRUST_ANCHOR);
return 0;
@@ -1372,7 +1369,7 @@ static int dns_transaction_make_packet_mdns(DnsTransaction *t) {
other->state = DNS_TRANSACTION_PENDING;
other->next_attempt_after = ts;
- qdcount ++;
+ qdcount++;
if (dns_key_is_shared(other->key))
add_known_answers = true;
@@ -1425,6 +1422,7 @@ static int dns_transaction_make_packet(DnsTransaction *t) {
int dns_transaction_go(DnsTransaction *t) {
usec_t ts;
int r;
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
assert(t);
@@ -1434,12 +1432,12 @@ int dns_transaction_go(DnsTransaction *t) {
if (r <= 0)
return r;
- log_debug("Excercising transaction %" PRIu16 " for <%s> on scope %s on %s/%s.",
+ log_debug("Transaction %" PRIu16 " for <%s> scope %s on %s/%s.",
t->id,
- dns_transaction_key_string(t),
+ dns_resource_key_to_string(t->key, key_str, sizeof key_str),
dns_protocol_to_string(t->scope->protocol),
t->scope->link ? t->scope->link->name : "*",
- t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family));
+ af_to_name_short(t->scope->family));
if (!t->initial_jitter_scheduled &&
(t->scope->protocol == DNS_PROTOCOL_LLMNR ||
@@ -1494,8 +1492,8 @@ int dns_transaction_go(DnsTransaction *t) {
return r;
if (t->scope->protocol == DNS_PROTOCOL_LLMNR &&
- (dns_name_endswith(DNS_RESOURCE_KEY_NAME(t->key), "in-addr.arpa") > 0 ||
- dns_name_endswith(DNS_RESOURCE_KEY_NAME(t->key), "ip6.arpa") > 0)) {
+ (dns_name_endswith(dns_resource_key_name(t->key), "in-addr.arpa") > 0 ||
+ dns_name_endswith(dns_resource_key_name(t->key), "ip6.arpa") > 0)) {
/* RFC 4795, Section 2.4. says reverse lookups shall
* always be made via TCP on LLMNR */
@@ -1602,11 +1600,14 @@ static int dns_transaction_add_dnssec_transaction(DnsTransaction *t, DnsResource
if (r < 0)
return r;
if (r > 0) {
- log_debug("Detected potential cyclic dependency, refusing to add transaction %" PRIu16 " (%s) as dependency for %" PRIu16 " (%s).",
+ char s[DNS_RESOURCE_KEY_STRING_MAX], saux[DNS_RESOURCE_KEY_STRING_MAX];
+
+ log_debug("Potential cyclic dependency, refusing to add transaction %" PRIu16 " (%s) as dependency for %" PRIu16 " (%s).",
aux->id,
- strna(dns_transaction_key_string(aux)),
+ dns_resource_key_to_string(t->key, s, sizeof s),
t->id,
- strna(dns_transaction_key_string(t)));
+ dns_resource_key_to_string(aux->key, saux, sizeof saux));
+
return -ELOOP;
}
}
@@ -1619,6 +1620,10 @@ static int dns_transaction_add_dnssec_transaction(DnsTransaction *t, DnsResource
if (r < 0)
goto gc;
+ r = set_ensure_allocated(&aux->notify_transactions_done, NULL);
+ if (r < 0)
+ goto gc;
+
r = set_put(t->dnssec_transactions, aux);
if (r < 0)
goto gc;
@@ -1678,7 +1683,7 @@ static int dns_transaction_negative_trust_anchor_lookup(DnsTransaction *t, const
assert(t);
- /* Check whether the specified name is in the the NTA
+ /* Check whether the specified name is in the NTA
* database, either in the global one, or the link-local
* one. */
@@ -1708,7 +1713,7 @@ static int dns_transaction_has_unsigned_negative_answer(DnsTransaction *t) {
/* Is this key explicitly listed as a negative trust anchor?
* If so, it's nothing we need to care about */
- r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(t->key));
+ r = dns_transaction_negative_trust_anchor_lookup(t, dns_resource_key_name(t->key));
if (r < 0)
return r;
if (r > 0)
@@ -1799,7 +1804,8 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
* - For unsigned SOA/NS we get the matching DS
* - For unsigned CNAME/DNAME/DS we get the parent SOA RR
* - For other unsigned RRs we get the matching SOA RR
- * - For SOA/NS/DS queries with no matching response RRs, and no NSEC/NSEC3, the parent's SOA RR
+ * - For SOA/NS queries with no matching response RR, and no NSEC/NSEC3, the DS RR
+ * - For DS queries with no matching response RRs, and no NSEC/NSEC3, the parent's SOA RR
* - For other queries with no matching response RRs, and no NSEC/NSEC3, the SOA RR
*/
@@ -1816,7 +1822,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
continue;
/* If this RR is in the negative trust anchor, we don't need to validate it. */
- r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(rr->key));
+ r = dns_transaction_negative_trust_anchor_lookup(t, dns_resource_key_name(rr->key));
if (r < 0)
return r;
if (r > 0)
@@ -1833,7 +1839,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
* already have the DNSKEY, and we don't have
* to look for more. */
if (rr->rrsig.type_covered == DNS_TYPE_DNSKEY) {
- r = dns_name_equal(rr->rrsig.signer, DNS_RESOURCE_KEY_NAME(rr->key));
+ r = dns_name_equal(rr->rrsig.signer, dns_resource_key_name(rr->key));
if (r < 0)
return r;
if (r > 0)
@@ -1851,7 +1857,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
* in another transaction whose additonal RRs
* point back to the original transaction, and
* we deadlock. */
- r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(t->key), rr->rrsig.signer);
+ r = dns_name_endswith(dns_resource_key_name(t->key), rr->rrsig.signer);
if (r < 0)
return r;
if (r == 0)
@@ -1861,7 +1867,8 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
if (!dnskey)
return -ENOMEM;
- log_debug("Requesting DNSKEY to validate transaction %" PRIu16" (%s, RRSIG with key tag: %" PRIu16 ").", t->id, DNS_RESOURCE_KEY_NAME(rr->key), rr->rrsig.key_tag);
+ log_debug("Requesting DNSKEY to validate transaction %" PRIu16" (%s, RRSIG with key tag: %" PRIu16 ").",
+ t->id, dns_resource_key_name(rr->key), rr->rrsig.key_tag);
r = dns_transaction_request_dnssec_rr(t, dnskey);
if (r < 0)
return r;
@@ -1879,17 +1886,18 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
* up in request loops, and want to keep
* additional traffic down. */
- r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(t->key), DNS_RESOURCE_KEY_NAME(rr->key));
+ r = dns_name_endswith(dns_resource_key_name(t->key), dns_resource_key_name(rr->key));
if (r < 0)
return r;
if (r == 0)
continue;
- ds = dns_resource_key_new(rr->key->class, DNS_TYPE_DS, DNS_RESOURCE_KEY_NAME(rr->key));
+ ds = dns_resource_key_new(rr->key->class, DNS_TYPE_DS, dns_resource_key_name(rr->key));
if (!ds)
return -ENOMEM;
- log_debug("Requesting DS to validate transaction %" PRIu16" (%s, DNSKEY with key tag: %" PRIu16 ").", t->id, DNS_RESOURCE_KEY_NAME(rr->key), dnssec_keytag(rr, false));
+ log_debug("Requesting DS to validate transaction %" PRIu16" (%s, DNSKEY with key tag: %" PRIu16 ").",
+ t->id, dns_resource_key_name(rr->key), dnssec_keytag(rr, false));
r = dns_transaction_request_dnssec_rr(t, ds);
if (r < 0)
return r;
@@ -1920,11 +1928,12 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
if (r > 0)
continue;
- ds = dns_resource_key_new(rr->key->class, DNS_TYPE_DS, DNS_RESOURCE_KEY_NAME(rr->key));
+ ds = dns_resource_key_new(rr->key->class, DNS_TYPE_DS, dns_resource_key_name(rr->key));
if (!ds)
return -ENOMEM;
- log_debug("Requesting DS to validate transaction %" PRIu16 " (%s, unsigned SOA/NS RRset).", t->id, DNS_RESOURCE_KEY_NAME(rr->key));
+ log_debug("Requesting DS to validate transaction %" PRIu16 " (%s, unsigned SOA/NS RRset).",
+ t->id, dns_resource_key_name(rr->key));
r = dns_transaction_request_dnssec_rr(t, ds);
if (r < 0)
return r;
@@ -1966,7 +1975,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
if (r > 0)
continue;
- name = DNS_RESOURCE_KEY_NAME(rr->key);
+ name = dns_resource_key_name(rr->key);
r = dns_name_parent(&name);
if (r < 0)
return r;
@@ -1977,7 +1986,8 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
if (!soa)
return -ENOMEM;
- log_debug("Requesting parent SOA to validate transaction %" PRIu16 " (%s, unsigned CNAME/DNAME/DS RRset).", t->id, DNS_RESOURCE_KEY_NAME(rr->key));
+ log_debug("Requesting parent SOA to validate transaction %" PRIu16 " (%s, unsigned CNAME/DNAME/DS RRset).",
+ t->id, dns_resource_key_name(rr->key));
r = dns_transaction_request_dnssec_rr(t, soa);
if (r < 0)
return r;
@@ -2007,11 +2017,12 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
if (r > 0)
continue;
- soa = dns_resource_key_new(rr->key->class, DNS_TYPE_SOA, DNS_RESOURCE_KEY_NAME(rr->key));
+ soa = dns_resource_key_new(rr->key->class, DNS_TYPE_SOA, dns_resource_key_name(rr->key));
if (!soa)
return -ENOMEM;
- log_debug("Requesting SOA to validate transaction %" PRIu16 " (%s, unsigned non-SOA/NS RRset <%s>).", t->id, DNS_RESOURCE_KEY_NAME(rr->key), dns_resource_record_to_string(rr));
+ log_debug("Requesting SOA to validate transaction %" PRIu16 " (%s, unsigned non-SOA/NS RRset <%s>).",
+ t->id, dns_resource_key_name(rr->key), dns_resource_record_to_string(rr));
r = dns_transaction_request_dnssec_rr(t, soa);
if (r < 0)
return r;
@@ -2028,30 +2039,42 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
return r;
if (r > 0) {
const char *name;
+ uint16_t type = 0;
- name = DNS_RESOURCE_KEY_NAME(t->key);
+ name = dns_resource_key_name(t->key);
- /* If this was a SOA or NS request, then this
- * indicates that we are not at a zone apex, hence ask
- * the parent name instead. If this was a DS request,
- * then it's signed when the parent zone is signed,
- * hence ask the parent in that case, too. */
+ /* If this was a SOA or NS request, then check if there's a DS RR for the same domain. Note that this
+ * could also be used as indication that we are not at a zone apex, but in real world setups there are
+ * too many broken DNS servers (Hello, incapdns.net!) where non-terminal zones return NXDOMAIN even
+ * though they have further children. If this was a DS request, then it's signed when the parent zone
+ * is signed, hence ask the parent SOA in that case. If this was any other RR then ask for the SOA RR,
+ * to see if that is signed. */
- if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS, DNS_TYPE_DS)) {
+ if (t->key->type == DNS_TYPE_DS) {
r = dns_name_parent(&name);
- if (r < 0)
- return r;
- if (r > 0)
- log_debug("Requesting parent SOA to validate transaction %" PRIu16 " (%s, unsigned empty SOA/NS/DS response).", t->id, DNS_RESOURCE_KEY_NAME(t->key));
- else
+ if (r > 0) {
+ type = DNS_TYPE_SOA;
+ log_debug("Requesting parent SOA to validate transaction %" PRIu16 " (%s, unsigned empty DS response).",
+ t->id, dns_resource_key_name(t->key));
+ } else
name = NULL;
- } else
- log_debug("Requesting SOA to validate transaction %" PRIu16 " (%s, unsigned empty non-SOA/NS/DS response).", t->id, DNS_RESOURCE_KEY_NAME(t->key));
+
+ } else if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS)) {
+
+ type = DNS_TYPE_DS;
+ log_debug("Requesting DS to validate transaction %" PRIu16 " (%s, unsigned empty SOA/NS response).",
+ t->id, dns_resource_key_name(t->key));
+
+ } else {
+ type = DNS_TYPE_SOA;
+ log_debug("Requesting SOA to validate transaction %" PRIu16 " (%s, unsigned empty non-SOA/NS/DS response).",
+ t->id, dns_resource_key_name(t->key));
+ }
if (name) {
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *soa = NULL;
- soa = dns_resource_key_new(t->key->class, DNS_TYPE_SOA, name);
+ soa = dns_resource_key_new(t->key->class, type, name);
if (!soa)
return -ENOMEM;
@@ -2118,7 +2141,7 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord *
if (dns_type_is_pseudo(rr->key->type))
return -EINVAL;
- r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(rr->key));
+ r = dns_transaction_negative_trust_anchor_lookup(t, dns_resource_key_name(rr->key));
if (r < 0)
return r;
if (r > 0)
@@ -2144,7 +2167,7 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord *
if (dt->key->type != DNS_TYPE_DS)
continue;
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), DNS_RESOURCE_KEY_NAME(rr->key));
+ r = dns_name_equal(dns_resource_key_name(dt->key), dns_resource_key_name(rr->key));
if (r < 0)
return r;
if (r == 0)
@@ -2187,7 +2210,7 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord *
continue;
if (!parent) {
- parent = DNS_RESOURCE_KEY_NAME(rr->key);
+ parent = dns_resource_key_name(rr->key);
r = dns_name_parent(&parent);
if (r < 0)
return r;
@@ -2201,7 +2224,7 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord *
}
}
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), parent);
+ r = dns_name_equal(dns_resource_key_name(dt->key), parent);
if (r < 0)
return r;
if (r == 0)
@@ -2226,7 +2249,7 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord *
if (dt->key->type != DNS_TYPE_SOA)
continue;
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), DNS_RESOURCE_KEY_NAME(rr->key));
+ r = dns_name_equal(dns_resource_key_name(dt->key), dns_resource_key_name(rr->key));
if (r < 0)
return r;
if (r == 0)
@@ -2273,7 +2296,7 @@ static int dns_transaction_in_private_tld(DnsTransaction *t, const DnsResourceKe
if (t->scope->dnssec_mode != DNSSEC_ALLOW_DOWNGRADE)
return false; /* In strict DNSSEC mode what doesn't exist, doesn't exist */
- tld = DNS_RESOURCE_KEY_NAME(key);
+ tld = dns_resource_key_name(key);
r = dns_name_parent(&tld);
if (r < 0)
return r;
@@ -2288,7 +2311,7 @@ static int dns_transaction_in_private_tld(DnsTransaction *t, const DnsResourceKe
if (dt->key->class != key->class)
continue;
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), tld);
+ r = dns_name_equal(dns_resource_key_name(dt->key), tld);
if (r < 0)
return r;
if (r == 0)
@@ -2305,8 +2328,10 @@ static int dns_transaction_in_private_tld(DnsTransaction *t, const DnsResourceKe
}
static int dns_transaction_requires_nsec(DnsTransaction *t) {
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
DnsTransaction *dt;
const char *name;
+ uint16_t type = 0;
Iterator i;
int r;
@@ -2321,7 +2346,7 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) {
if (dns_type_is_pseudo(t->key->type))
return -EINVAL;
- r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(t->key));
+ r = dns_transaction_negative_trust_anchor_lookup(t, dns_resource_key_name(t->key));
if (r < 0)
return r;
if (r > 0)
@@ -2335,28 +2360,32 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) {
* exist, and we are in downgrade mode, hence ignore
* that fact that we didn't get any NSEC RRs.*/
- log_info("Detected a negative query %s in a private DNS zone, permitting unsigned response.", dns_transaction_key_string(t));
+ log_info("Detected a negative query %s in a private DNS zone, permitting unsigned response.",
+ dns_resource_key_to_string(t->key, key_str, sizeof key_str));
return false;
}
- name = DNS_RESOURCE_KEY_NAME(t->key);
+ name = dns_resource_key_name(t->key);
- if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS, DNS_TYPE_DS)) {
+ if (t->key->type == DNS_TYPE_DS) {
- /* We got a negative reply for this SOA/NS lookup? If
- * so, then we are not at a zone apex, and thus should
- * look at the result of the parent SOA lookup.
- *
- * We got a negative reply for this DS lookup? DS RRs
- * are signed when their parent zone is signed, hence
- * also check the parent SOA in this case. */
+ /* We got a negative reply for this DS lookup? DS RRs are signed when their parent zone is signed,
+ * hence check the parent SOA in this case. */
r = dns_name_parent(&name);
if (r < 0)
return r;
if (r == 0)
return true;
- }
+
+ type = DNS_TYPE_SOA;
+
+ } else if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS))
+ /* We got a negative reply for this SOA/NS lookup? If so, check if there's a DS RR for this */
+ type = DNS_TYPE_DS;
+ else
+ /* For all other negative replies, check for the SOA lookup */
+ type = DNS_TYPE_SOA;
/* For all other RRs we check the SOA on the same level to see
* if it's signed. */
@@ -2365,10 +2394,10 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) {
if (dt->key->class != t->key->class)
continue;
- if (dt->key->type != DNS_TYPE_SOA)
+ if (dt->key->type != type)
continue;
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), name);
+ r = dns_name_equal(dns_resource_key_name(dt->key), name);
if (r < 0)
return r;
if (r == 0)
@@ -2390,7 +2419,7 @@ static int dns_transaction_dnskey_authenticated(DnsTransaction *t, DnsResourceRe
* the specified RRset is authenticated (i.e. has a matching
* DS RR). */
- r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(rr->key));
+ r = dns_transaction_negative_trust_anchor_lookup(t, dns_resource_key_name(rr->key));
if (r < 0)
return r;
if (r > 0)
@@ -2413,7 +2442,7 @@ static int dns_transaction_dnskey_authenticated(DnsTransaction *t, DnsResourceRe
if (dt->key->type == DNS_TYPE_DNSKEY) {
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), rrsig->rrsig.signer);
+ r = dns_name_equal(dns_resource_key_name(dt->key), rrsig->rrsig.signer);
if (r < 0)
return r;
if (r == 0)
@@ -2430,7 +2459,7 @@ static int dns_transaction_dnskey_authenticated(DnsTransaction *t, DnsResourceRe
} else if (dt->key->type == DNS_TYPE_DS) {
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), rrsig->rrsig.signer);
+ r = dns_name_equal(dns_resource_key_name(dt->key), rrsig->rrsig.signer);
if (r < 0)
return r;
if (r == 0)
@@ -2460,7 +2489,7 @@ static int dns_transaction_known_signed(DnsTransaction *t, DnsResourceRecord *rr
* not to be signed, there's a problem with the DNS server */
return rr->key->class == DNS_CLASS_IN &&
- dns_name_is_root(DNS_RESOURCE_KEY_NAME(rr->key));
+ dns_name_is_root(dns_resource_key_name(rr->key));
}
static int dns_transaction_check_revoked_trust_anchors(DnsTransaction *t) {
@@ -2541,343 +2570,347 @@ static int dns_transaction_copy_validated(DnsTransaction *t) {
return 0;
}
-int dns_transaction_validate_dnssec(DnsTransaction *t) {
- _cleanup_(dns_answer_unrefp) DnsAnswer *validated = NULL;
- enum {
- PHASE_DNSKEY, /* Phase #1, only validate DNSKEYs */
- PHASE_NSEC, /* Phase #2, only validate NSEC+NSEC3 */
- PHASE_ALL, /* Phase #3, validate everything else */
- } phase;
+typedef enum {
+ DNSSEC_PHASE_DNSKEY, /* Phase #1, only validate DNSKEYs */
+ DNSSEC_PHASE_NSEC, /* Phase #2, only validate NSEC+NSEC3 */
+ DNSSEC_PHASE_ALL, /* Phase #3, validate everything else */
+} Phase;
+
+static int dnssec_validate_records(
+ DnsTransaction *t,
+ Phase phase,
+ bool *have_nsec,
+ DnsAnswer **validated) {
+
DnsResourceRecord *rr;
- DnsAnswerFlags flags;
int r;
- assert(t);
+ /* Returns negative on error, 0 if validation failed, 1 to restart validation, 2 when finished. */
- /* We have now collected all DS and DNSKEY RRs in
- * t->validated_keys, let's see which RRs we can now
- * authenticate with that. */
+ DNS_ANSWER_FOREACH(rr, t->answer) {
+ DnsResourceRecord *rrsig = NULL;
+ DnssecResult result;
- if (t->scope->dnssec_mode == DNSSEC_NO)
- return 0;
+ switch (rr->key->type) {
+ case DNS_TYPE_RRSIG:
+ continue;
- /* Already validated */
- if (t->answer_dnssec_result != _DNSSEC_RESULT_INVALID)
- return 0;
+ case DNS_TYPE_DNSKEY:
+ /* We validate DNSKEYs only in the DNSKEY and ALL phases */
+ if (phase == DNSSEC_PHASE_NSEC)
+ continue;
+ break;
- /* 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;
- return 0;
- }
+ case DNS_TYPE_NSEC:
+ case DNS_TYPE_NSEC3:
+ *have_nsec = true;
- /* Cached stuff is not affected by validation. */
- if (t->answer_source != DNS_TRANSACTION_NETWORK)
- return 0;
+ /* We validate NSEC/NSEC3 only in the NSEC and ALL phases */
+ if (phase == DNSSEC_PHASE_DNSKEY)
+ continue;
+ break;
- if (!dns_transaction_dnssec_supported_full(t)) {
- /* The server does not support DNSSEC, or doesn't augment responses with RRSIGs. */
- t->answer_dnssec_result = DNSSEC_INCOMPATIBLE_SERVER;
- log_debug("Not validating response for %" PRIu16 ", server lacks DNSSEC support.", t->id);
- return 0;
- }
+ default:
+ /* We validate all other RRs only in the ALL phases */
+ if (phase != DNSSEC_PHASE_ALL)
+ continue;
+ }
- log_debug("Validating response from transaction %" PRIu16 " (%s).", t->id, dns_transaction_key_string(t));
+ r = dnssec_verify_rrset_search(t->answer, rr->key, t->validated_keys, USEC_INFINITY, &result, &rrsig);
+ if (r < 0)
+ return r;
- /* First, see if this response contains any revoked trust
- * anchors we care about */
- r = dns_transaction_check_revoked_trust_anchors(t);
- if (r < 0)
- return r;
+ log_debug("Looking at %s: %s", strna(dns_resource_record_to_string(rr)), dnssec_result_to_string(result));
- /* Third, copy all RRs we acquired successfully from auxiliary RRs over. */
- r = dns_transaction_copy_validated(t);
- if (r < 0)
- return r;
+ if (result == DNSSEC_VALIDATED) {
- /* Second, see if there are DNSKEYs we already know a
- * validated DS for. */
- r = dns_transaction_validate_dnskey_by_ds(t);
- if (r < 0)
- return r;
+ if (rr->key->type == DNS_TYPE_DNSKEY) {
+ /* If we just validated a DNSKEY RRset, then let's add these keys to
+ * the set of validated keys for this transaction. */
- /* Fourth, remove all DNSKEY and DS RRs again that our trust
- * anchor says are revoked. After all we might have marked
- * some keys revoked above, but they might still be lingering
- * in our validated_keys list. */
- r = dns_transaction_invalidate_revoked_keys(t);
- if (r < 0)
- return r;
+ r = dns_answer_copy_by_key(&t->validated_keys, t->answer, rr->key, DNS_ANSWER_AUTHENTICATED);
+ if (r < 0)
+ return r;
- phase = PHASE_DNSKEY;
- for (;;) {
- bool changed = false, have_nsec = false;
+ /* Some of the DNSKEYs we just added might already have been revoked,
+ * remove them again in that case. */
+ r = dns_transaction_invalidate_revoked_keys(t);
+ if (r < 0)
+ return r;
+ }
- DNS_ANSWER_FOREACH(rr, t->answer) {
- DnsResourceRecord *rrsig = NULL;
- DnssecResult result;
+ /* Add the validated RRset to the new list of validated
+ * RRsets, and remove it from the unvalidated RRsets.
+ * We mark the RRset as authenticated and cacheable. */
+ r = dns_answer_move_by_key(validated, &t->answer, rr->key, DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE);
+ if (r < 0)
+ return r;
- switch (rr->key->type) {
+ manager_dnssec_verdict(t->scope->manager, DNSSEC_SECURE, rr->key);
- case DNS_TYPE_RRSIG:
- continue;
+ /* Exit the loop, we dropped something from the answer, start from the beginning */
+ return 1;
+ }
- case DNS_TYPE_DNSKEY:
- /* We validate DNSKEYs only in the DNSKEY and ALL phases */
- if (phase == PHASE_NSEC)
- continue;
- break;
+ /* If we haven't read all DNSKEYs yet a negative result of the validation is irrelevant, as
+ * there might be more DNSKEYs coming. Similar, if we haven't read all NSEC/NSEC3 RRs yet,
+ * we cannot do positive wildcard proofs yet, as those require the NSEC/NSEC3 RRs. */
+ if (phase != DNSSEC_PHASE_ALL)
+ continue;
- case DNS_TYPE_NSEC:
- case DNS_TYPE_NSEC3:
- have_nsec = true;
+ if (result == DNSSEC_VALIDATED_WILDCARD) {
+ bool authenticated = false;
+ const char *source;
- /* We validate NSEC/NSEC3 only in the NSEC and ALL phases */
- if (phase == PHASE_DNSKEY)
- continue;
+ /* This RRset validated, but as a wildcard. This means we need
+ * to prove via NSEC/NSEC3 that no matching non-wildcard RR exists.*/
- break;
+ /* First step, determine the source of synthesis */
+ r = dns_resource_record_source(rrsig, &source);
+ if (r < 0)
+ return r;
- default:
- /* We validate all other RRs only in the ALL phases */
- if (phase != PHASE_ALL)
- continue;
+ r = dnssec_test_positive_wildcard(*validated,
+ dns_resource_key_name(rr->key),
+ source,
+ rrsig->rrsig.signer,
+ &authenticated);
- break;
+ /* Unless the NSEC proof showed that the key really doesn't exist something is off. */
+ if (r == 0)
+ result = DNSSEC_INVALID;
+ else {
+ r = dns_answer_move_by_key(validated, &t->answer, rr->key,
+ authenticated ? (DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE) : 0);
+ if (r < 0)
+ return r;
+
+ manager_dnssec_verdict(t->scope->manager, authenticated ? DNSSEC_SECURE : DNSSEC_INSECURE, rr->key);
+
+ /* Exit the loop, we dropped something from the answer, start from the beginning */
+ return 1;
}
+ }
- r = dnssec_verify_rrset_search(t->answer, rr->key, t->validated_keys, USEC_INFINITY, &result, &rrsig);
+ if (result == DNSSEC_NO_SIGNATURE) {
+ r = dns_transaction_requires_rrsig(t, rr);
if (r < 0)
return r;
+ if (r == 0) {
+ /* Data does not require signing. In that case, just copy it over,
+ * but remember that this is by no means authenticated.*/
+ r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0);
+ if (r < 0)
+ return r;
+
+ manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key);
+ return 1;
+ }
- log_debug("Looking at %s: %s", strna(dns_resource_record_to_string(rr)), dnssec_result_to_string(result));
+ r = dns_transaction_known_signed(t, rr);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ /* This is an RR we know has to be signed. If it isn't this means
+ * the server is not attaching RRSIGs, hence complain. */
- if (result == DNSSEC_VALIDATED) {
+ dns_server_packet_rrsig_missing(t->server, t->current_feature_level);
- if (rr->key->type == DNS_TYPE_DNSKEY) {
- /* If we just validated a
- * DNSKEY RRset, then let's
- * add these keys to the set
- * of validated keys for this
- * transaction. */
+ if (t->scope->dnssec_mode == DNSSEC_ALLOW_DOWNGRADE) {
- r = dns_answer_copy_by_key(&t->validated_keys, t->answer, rr->key, DNS_ANSWER_AUTHENTICATED);
- if (r < 0)
- return r;
+ /* Downgrading is OK? If so, just consider the information unsigned */
- /* some of the DNSKEYs we just
- * added might already have
- * been revoked, remove them
- * again in that case. */
- r = dns_transaction_invalidate_revoked_keys(t);
+ r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0);
if (r < 0)
return r;
- }
- /* Add the validated RRset to the new
- * list of validated RRsets, and
- * remove it from the unvalidated
- * RRsets. We mark the RRset as
- * authenticated and cacheable. */
- r = dns_answer_move_by_key(&validated, &t->answer, rr->key, DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE);
- if (r < 0)
- return r;
-
- manager_dnssec_verdict(t->scope->manager, DNSSEC_SECURE, rr->key);
+ manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key);
+ return 1;
+ }
- /* Exit the loop, we dropped something from the answer, start from the beginning */
- changed = true;
- break;
+ /* Otherwise, fail */
+ t->answer_dnssec_result = DNSSEC_INCOMPATIBLE_SERVER;
+ return 0;
}
- /* If we haven't read all DNSKEYs yet a negative result of the validation is irrelevant, as
- * there might be more DNSKEYs coming. Similar, if we haven't read all NSEC/NSEC3 RRs yet, we
- * cannot do positive wildcard proofs yet, as those require the NSEC/NSEC3 RRs. */
- if (phase != PHASE_ALL)
- continue;
+ r = dns_transaction_in_private_tld(t, rr->key);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ char s[DNS_RESOURCE_KEY_STRING_MAX];
- if (result == DNSSEC_VALIDATED_WILDCARD) {
- bool authenticated = false;
- const char *source;
+ /* The data is from a TLD that is proven not to exist, and we are in downgrade
+ * mode, hence ignore the fact that this was not signed. */
- /* This RRset validated, but as a wildcard. This means we need to prove via NSEC/NSEC3
- * that no matching non-wildcard RR exists.*/
+ log_info("Detected RRset %s is in a private DNS zone, permitting unsigned RRs.",
+ dns_resource_key_to_string(rr->key, s, sizeof s));
- /* First step, determine the source of synthesis */
- r = dns_resource_record_source(rrsig, &source);
+ r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0);
if (r < 0)
return r;
- r = dnssec_test_positive_wildcard(
- validated,
- DNS_RESOURCE_KEY_NAME(rr->key),
- source,
- rrsig->rrsig.signer,
- &authenticated);
-
- /* Unless the NSEC proof showed that the key really doesn't exist something is off. */
- if (r == 0)
- result = DNSSEC_INVALID;
- else {
- r = dns_answer_move_by_key(&validated, &t->answer, rr->key, authenticated ? (DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE) : 0);
- if (r < 0)
- return r;
+ manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key);
+ return 1;
+ }
+ }
- manager_dnssec_verdict(t->scope->manager, authenticated ? DNSSEC_SECURE : DNSSEC_INSECURE, rr->key);
+ if (IN_SET(result,
+ DNSSEC_MISSING_KEY,
+ DNSSEC_SIGNATURE_EXPIRED,
+ DNSSEC_UNSUPPORTED_ALGORITHM)) {
- /* Exit the loop, we dropped something from the answer, start from the beginning */
- changed = true;
- break;
- }
- }
+ r = dns_transaction_dnskey_authenticated(t, rr);
+ if (r < 0 && r != -ENXIO)
+ return r;
+ if (r == 0) {
+ /* The DNSKEY transaction was not authenticated, this means there's
+ * no DS for this, which means it's OK if no keys are found for this signature. */
- if (result == DNSSEC_NO_SIGNATURE) {
- r = dns_transaction_requires_rrsig(t, rr);
+ r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0);
if (r < 0)
return r;
- if (r == 0) {
- /* Data does not require signing. In that case, just copy it over,
- * but remember that this is by no means authenticated.*/
- r = dns_answer_move_by_key(&validated, &t->answer, rr->key, 0);
- if (r < 0)
- return r;
- manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key);
- changed = true;
- break;
- }
+ manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key);
+ return 1;
+ }
+ }
- r = dns_transaction_known_signed(t, rr);
+ r = dns_transaction_is_primary_response(t, rr);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ /* Look for a matching DNAME for this CNAME */
+ r = dns_answer_has_dname_for_cname(t->answer, rr);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ /* Also look among the stuff we already validated */
+ r = dns_answer_has_dname_for_cname(*validated, rr);
if (r < 0)
return r;
- if (r > 0) {
- /* This is an RR we know has to be signed. If it isn't this means
- * the server is not attaching RRSIGs, hence complain. */
-
- dns_server_packet_rrsig_missing(t->server, t->current_feature_level);
+ }
- if (t->scope->dnssec_mode == DNSSEC_ALLOW_DOWNGRADE) {
+ if (r == 0) {
+ if (IN_SET(result,
+ DNSSEC_INVALID,
+ DNSSEC_SIGNATURE_EXPIRED,
+ DNSSEC_NO_SIGNATURE))
+ manager_dnssec_verdict(t->scope->manager, DNSSEC_BOGUS, rr->key);
+ else /* DNSSEC_MISSING_KEY or DNSSEC_UNSUPPORTED_ALGORITHM */
+ manager_dnssec_verdict(t->scope->manager, DNSSEC_INDETERMINATE, rr->key);
+
+ /* This is a primary response to our question, and it failed validation.
+ * That's fatal. */
+ t->answer_dnssec_result = result;
+ return 0;
+ }
- /* Downgrading is OK? If so, just consider the information unsigned */
+ /* This is a primary response, but we do have a DNAME RR
+ * in the RR that can replay this CNAME, hence rely on
+ * that, and we can remove the CNAME in favour of it. */
+ }
- r = dns_answer_move_by_key(&validated, &t->answer, rr->key, 0);
- if (r < 0)
- return r;
+ /* This is just some auxiliary data. Just remove the RRset and continue. */
+ r = dns_answer_remove_by_key(&t->answer, rr->key);
+ if (r < 0)
+ return r;
- manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key);
- changed = true;
- break;
- }
+ /* We dropped something from the answer, start from the beginning. */
+ return 1;
+ }
- /* Otherwise, fail */
- t->answer_dnssec_result = DNSSEC_INCOMPATIBLE_SERVER;
- return 0;
- }
+ return 2; /* Finito. */
+}
- r = dns_transaction_in_private_tld(t, rr->key);
- if (r < 0)
- return r;
- if (r > 0) {
- _cleanup_free_ char *s = NULL;
+int dns_transaction_validate_dnssec(DnsTransaction *t) {
+ _cleanup_(dns_answer_unrefp) DnsAnswer *validated = NULL;
+ Phase phase;
+ DnsAnswerFlags flags;
+ int r;
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
- /* The data is from a TLD that is proven not to exist, and we are in downgrade
- * mode, hence ignore the fact that this was not signed. */
+ assert(t);
- (void) dns_resource_key_to_string(rr->key, &s);
- log_info("Detected RRset %s is in a private DNS zone, permitting unsigned RRs.", strna(s ? strstrip(s) : NULL));
+ /* We have now collected all DS and DNSKEY RRs in
+ * t->validated_keys, let's see which RRs we can now
+ * authenticate with that. */
- r = dns_answer_move_by_key(&validated, &t->answer, rr->key, 0);
- if (r < 0)
- return r;
+ if (t->scope->dnssec_mode == DNSSEC_NO)
+ return 0;
- manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key);
- changed = true;
- break;
- }
- }
+ /* Already validated */
+ if (t->answer_dnssec_result != _DNSSEC_RESULT_INVALID)
+ return 0;
- if (IN_SET(result,
- DNSSEC_MISSING_KEY,
- DNSSEC_SIGNATURE_EXPIRED,
- DNSSEC_UNSUPPORTED_ALGORITHM)) {
+ /* 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;
+ return 0;
+ }
- r = dns_transaction_dnskey_authenticated(t, rr);
- if (r < 0 && r != -ENXIO)
- return r;
- if (r == 0) {
- /* The DNSKEY transaction was not authenticated, this means there's
- * no DS for this, which means it's OK if no keys are found for this signature. */
+ /* Cached stuff is not affected by validation. */
+ if (t->answer_source != DNS_TRANSACTION_NETWORK)
+ return 0;
- r = dns_answer_move_by_key(&validated, &t->answer, rr->key, 0);
- if (r < 0)
- return r;
+ if (!dns_transaction_dnssec_supported_full(t)) {
+ /* The server does not support DNSSEC, or doesn't augment responses with RRSIGs. */
+ t->answer_dnssec_result = DNSSEC_INCOMPATIBLE_SERVER;
+ log_debug("Not validating response for %" PRIu16 ", server lacks DNSSEC support.", t->id);
+ return 0;
+ }
- manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key);
- changed = true;
- break;
- }
- }
+ log_debug("Validating response from transaction %" PRIu16 " (%s).",
+ t->id,
+ dns_resource_key_to_string(t->key, key_str, sizeof key_str));
- r = dns_transaction_is_primary_response(t, rr);
- if (r < 0)
- return r;
- if (r > 0) {
+ /* First, see if this response contains any revoked trust
+ * anchors we care about */
+ r = dns_transaction_check_revoked_trust_anchors(t);
+ if (r < 0)
+ return r;
- /* Look for a matching DNAME for this CNAME */
- r = dns_answer_has_dname_for_cname(t->answer, rr);
- if (r < 0)
- return r;
- if (r == 0) {
- /* Also look among the stuff we already validated */
- r = dns_answer_has_dname_for_cname(validated, rr);
- if (r < 0)
- return r;
- }
+ /* Third, copy all RRs we acquired successfully from auxiliary RRs over. */
+ r = dns_transaction_copy_validated(t);
+ if (r < 0)
+ return r;
- if (r == 0) {
- if (IN_SET(result,
- DNSSEC_INVALID,
- DNSSEC_SIGNATURE_EXPIRED,
- DNSSEC_NO_SIGNATURE))
- manager_dnssec_verdict(t->scope->manager, DNSSEC_BOGUS, rr->key);
- else /* DNSSEC_MISSING_KEY or DNSSEC_UNSUPPORTED_ALGORITHM */
- manager_dnssec_verdict(t->scope->manager, DNSSEC_INDETERMINATE, rr->key);
-
- /* This is a primary response to our question, and it failed validation. That's
- * fatal. */
- t->answer_dnssec_result = result;
- return 0;
- }
+ /* Second, see if there are DNSKEYs we already know a
+ * validated DS for. */
+ r = dns_transaction_validate_dnskey_by_ds(t);
+ if (r < 0)
+ return r;
- /* This is a primary response, but we do have a DNAME RR in the RR that can replay this
- * CNAME, hence rely on that, and we can remove the CNAME in favour of it. */
- }
+ /* Fourth, remove all DNSKEY and DS RRs again that our trust
+ * anchor says are revoked. After all we might have marked
+ * some keys revoked above, but they might still be lingering
+ * in our validated_keys list. */
+ r = dns_transaction_invalidate_revoked_keys(t);
+ if (r < 0)
+ return r;
- /* This is just some auxiliary data. Just remove the RRset and continue. */
- r = dns_answer_remove_by_key(&t->answer, rr->key);
- if (r < 0)
- return r;
+ phase = DNSSEC_PHASE_DNSKEY;
+ for (;;) {
+ bool have_nsec = false;
- /* Exit the loop, we dropped something from the answer, start from the beginning */
- changed = true;
- break;
- }
+ r = dnssec_validate_records(t, phase, &have_nsec, &validated);
+ if (r <= 0)
+ return r;
- /* Restart the inner loop as long as we managed to achieve something */
- if (changed)
+ /* Try again as long as we managed to achieve something */
+ if (r == 1)
continue;
- if (phase == PHASE_DNSKEY && have_nsec) {
+ if (phase == DNSSEC_PHASE_DNSKEY && have_nsec) {
/* OK, we processed all DNSKEYs, and there are NSEC/NSEC3 RRs, look at those now. */
- phase = PHASE_NSEC;
+ phase = DNSSEC_PHASE_NSEC;
continue;
}
- if (phase != PHASE_ALL) {
- /* OK, we processed all DNSKEYs and NSEC/NSEC3 RRs, look at all the rest now. Note that in this
- * third phase we start to remove RRs we couldn't validate. */
- phase = PHASE_ALL;
+ if (phase != DNSSEC_PHASE_ALL) {
+ /* OK, we processed all DNSKEYs and NSEC/NSEC3 RRs, look at all the rest now.
+ * Note that in this third phase we start to remove RRs we couldn't validate. */
+ phase = DNSSEC_PHASE_ALL;
continue;
}
@@ -2921,7 +2954,7 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) {
case DNSSEC_NSEC_NXDOMAIN:
/* NSEC proves the domain doesn't exist. Very good. */
- log_debug("Proved NXDOMAIN via NSEC/NSEC3 for transaction %u (%s)", t->id, dns_transaction_key_string(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;
@@ -2931,7 +2964,7 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) {
case DNSSEC_NSEC_NODATA:
/* NSEC proves that there's no data here, very good. */
- log_debug("Proved NODATA via NSEC/NSEC3 for transaction %u (%s)", t->id, dns_transaction_key_string(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;
@@ -2941,7 +2974,7 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) {
case DNSSEC_NSEC_OPTOUT:
/* NSEC3 says the data might not be signed */
- log_debug("Data is NSEC3 opt-out via NSEC/NSEC3 for transaction %u (%s)", t->id, dns_transaction_key_string(t));
+ 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;
@@ -2986,17 +3019,6 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) {
return 1;
}
-const char *dns_transaction_key_string(DnsTransaction *t) {
- assert(t);
-
- if (!t->key_string) {
- if (dns_resource_key_to_string(t->key, &t->key_string) < 0)
- return "n/a";
- }
-
- return strstrip(t->key_string);
-}
-
static const char* const dns_transaction_state_table[_DNS_TRANSACTION_STATE_MAX] = {
[DNS_TRANSACTION_NULL] = "null",
[DNS_TRANSACTION_PENDING] = "pending",
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-transaction.h b/src/grp-resolve/systemd-resolved/resolved-dns-transaction.h
index 4617194711..eaece91533 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-transaction.h
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-transaction.h
@@ -64,7 +64,6 @@ struct DnsTransaction {
DnsScope *scope;
DnsResourceKey *key;
- char *key_string;
DnsTransactionState state;
@@ -119,17 +118,17 @@ struct DnsTransaction {
/* Query candidates this transaction is referenced by and that
* shall be notified about this specific transaction
* completing. */
- Set *notify_query_candidates;
+ Set *notify_query_candidates, *notify_query_candidates_done;
/* Zone items this transaction is referenced by and that shall
* be notified about completion. */
- Set *notify_zone_items;
+ Set *notify_zone_items, *notify_zone_items_done;
/* Other transactions that this transactions is referenced by
* and that shall be notified about completion. This is used
* when transactions want to validate their RRsets, but need
* another DNSKEY or DS RR to do so. */
- Set *notify_transactions;
+ Set *notify_transactions, *notify_transactions_done;
/* The opposite direction: the transactions this transaction
* created in order to request DNSKEY or DS RRs. */
@@ -153,8 +152,6 @@ void dns_transaction_notify(DnsTransaction *t, DnsTransaction *source);
int dns_transaction_validate_dnssec(DnsTransaction *t);
int dns_transaction_request_dnssec_keys(DnsTransaction *t);
-const char *dns_transaction_key_string(DnsTransaction *t);
-
const char* dns_transaction_state_to_string(DnsTransactionState p) _const_;
DnsTransactionState dns_transaction_state_from_string(const char *s) _pure_;
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-trust-anchor.c b/src/grp-resolve/systemd-resolved/resolved-dns-trust-anchor.c
index a75337eb6a..77370e7dd5 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-trust-anchor.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-trust-anchor.c
@@ -651,7 +651,7 @@ static int dns_trust_anchor_check_revoked_one(DnsTrustAnchor *d, DnsResourceReco
}
}
- a = hashmap_get(d->positive_by_key, &DNS_RESOURCE_KEY_CONST(revoked_dnskey->key->class, DNS_TYPE_DS, DNS_RESOURCE_KEY_NAME(revoked_dnskey->key)));
+ a = hashmap_get(d->positive_by_key, &DNS_RESOURCE_KEY_CONST(revoked_dnskey->key->class, DNS_TYPE_DS, dns_resource_key_name(revoked_dnskey->key)));
if (a) {
DnsResourceRecord *anchor;
@@ -698,7 +698,7 @@ int dns_trust_anchor_check_revoked(DnsTrustAnchor *d, DnsResourceRecord *dnskey,
/* Could this be interesting to us at all? If not,
* there's no point in looking for and verifying a
* self-signed RRSIG. */
- if (!dns_trust_anchor_knows_domain_positive(d, DNS_RESOURCE_KEY_NAME(dnskey->key)))
+ if (!dns_trust_anchor_knows_domain_positive(d, dns_resource_key_name(dnskey->key)))
return 0;
/* Look for a self-signed RRSIG in the other rrs belonging to this DNSKEY */
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-zone.c b/src/grp-resolve/systemd-resolved/resolved-dns-zone.c
index f52383cfd1..850eed8cb8 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-zone.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-zone.c
@@ -38,6 +38,7 @@ void dns_zone_item_probe_stop(DnsZoneItem *i) {
i->probe_transaction = NULL;
set_remove(t->notify_zone_items, i);
+ set_remove(t->notify_zone_items_done, i);
dns_transaction_gc(t);
}
@@ -68,12 +69,12 @@ static void dns_zone_item_remove_and_free(DnsZone *z, DnsZoneItem *i) {
else
hashmap_remove(z->by_key, i->rr->key);
- first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(i->rr->key));
+ first = hashmap_get(z->by_name, dns_resource_key_name(i->rr->key));
LIST_REMOVE(by_name, first, i);
if (first)
- assert_se(hashmap_replace(z->by_name, DNS_RESOURCE_KEY_NAME(first->rr->key), first) >= 0);
+ assert_se(hashmap_replace(z->by_name, dns_resource_key_name(first->rr->key), first) >= 0);
else
- hashmap_remove(z->by_name, DNS_RESOURCE_KEY_NAME(i->rr->key));
+ hashmap_remove(z->by_name, dns_resource_key_name(i->rr->key));
dns_zone_item_free(i);
}
@@ -147,12 +148,12 @@ static int dns_zone_link_item(DnsZone *z, DnsZoneItem *i) {
return r;
}
- first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(i->rr->key));
+ first = hashmap_get(z->by_name, dns_resource_key_name(i->rr->key));
if (first) {
LIST_PREPEND(by_name, first, i);
- assert_se(hashmap_replace(z->by_name, DNS_RESOURCE_KEY_NAME(first->rr->key), first) >= 0);
+ assert_se(hashmap_replace(z->by_name, dns_resource_key_name(first->rr->key), first) >= 0);
} else {
- r = hashmap_put(z->by_name, DNS_RESOURCE_KEY_NAME(i->rr->key), i);
+ r = hashmap_put(z->by_name, dns_resource_key_name(i->rr->key), i);
if (r < 0)
return r;
}
@@ -169,11 +170,11 @@ static int dns_zone_item_probe_start(DnsZoneItem *i) {
if (i->probe_transaction)
return 0;
- t = dns_scope_find_transaction(i->scope, &DNS_RESOURCE_KEY_CONST(i->rr->key->class, DNS_TYPE_ANY, DNS_RESOURCE_KEY_NAME(i->rr->key)), false);
+ t = dns_scope_find_transaction(i->scope, &DNS_RESOURCE_KEY_CONST(i->rr->key->class, DNS_TYPE_ANY, dns_resource_key_name(i->rr->key)), false);
if (!t) {
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
- key = dns_resource_key_new(i->rr->key->class, DNS_TYPE_ANY, DNS_RESOURCE_KEY_NAME(i->rr->key));
+ key = dns_resource_key_new(i->rr->key->class, DNS_TYPE_ANY, dns_resource_key_name(i->rr->key));
if (!key)
return -ENOMEM;
@@ -186,6 +187,10 @@ static int dns_zone_item_probe_start(DnsZoneItem *i) {
if (r < 0)
goto gc;
+ r = set_ensure_allocated(&t->notify_zone_items_done, NULL);
+ if (r < 0)
+ goto gc;
+
r = set_put(t->notify_zone_items, i);
if (r < 0)
goto gc;
@@ -303,7 +308,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns
* go through the list by the name and look
* for everything manually */
- first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key));
+ first = hashmap_get(z->by_name, dns_resource_key_name(key));
LIST_FOREACH(by_name, j, first) {
if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
continue;
@@ -339,7 +344,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns
}
if (!found) {
- first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key));
+ first = hashmap_get(z->by_name, dns_resource_key_name(key));
LIST_FOREACH(by_name, j, first) {
if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
continue;
@@ -370,7 +375,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns
bool found = false, added = false;
int k;
- first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key));
+ first = hashmap_get(z->by_name, dns_resource_key_name(key));
LIST_FOREACH(by_name, j, first) {
if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
continue;
@@ -393,7 +398,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns
}
if (found && !added) {
- r = dns_answer_add_soa(soa, DNS_RESOURCE_KEY_NAME(key), LLMNR_DEFAULT_TTL);
+ r = dns_answer_add_soa(soa, dns_resource_key_name(key), LLMNR_DEFAULT_TTL);
if (r < 0)
return r;
}
@@ -418,7 +423,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns
if (!found) {
bool add_soa = false;
- first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key));
+ first = hashmap_get(z->by_name, dns_resource_key_name(key));
LIST_FOREACH(by_name, j, first) {
if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
continue;
@@ -430,7 +435,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns
}
if (add_soa) {
- r = dns_answer_add_soa(soa, DNS_RESOURCE_KEY_NAME(key), LLMNR_DEFAULT_TTL);
+ r = dns_answer_add_soa(soa, dns_resource_key_name(key), LLMNR_DEFAULT_TTL);
if (r < 0)
return r;
}
@@ -482,7 +487,7 @@ void dns_zone_item_conflict(DnsZoneItem *i) {
i->state = DNS_ZONE_ITEM_WITHDRAWN;
/* Maybe change the hostname */
- if (manager_is_own_hostname(i->scope->manager, DNS_RESOURCE_KEY_NAME(i->rr->key)) > 0)
+ if (manager_is_own_hostname(i->scope->manager, dns_resource_key_name(i->rr->key)) > 0)
manager_next_hostname(i->scope->manager);
}
@@ -562,7 +567,7 @@ int dns_zone_check_conflicts(DnsZone *zone, DnsResourceRecord *rr) {
* so, we'll verify our RRs. */
/* No conflict if we don't have the name at all. */
- first = hashmap_get(zone->by_name, DNS_RESOURCE_KEY_NAME(rr->key));
+ first = hashmap_get(zone->by_name, dns_resource_key_name(rr->key));
if (!first)
return 0;
@@ -593,7 +598,7 @@ int dns_zone_verify_conflicts(DnsZone *zone, DnsResourceKey *key) {
/* Somebody else notified us about a possible conflict. Let's
* verify if that's true. */
- first = hashmap_get(zone->by_name, DNS_RESOURCE_KEY_NAME(key));
+ first = hashmap_get(zone->by_name, dns_resource_key_name(key));
if (!first)
return 0;
diff --git a/src/grp-resolve/systemd-resolved/resolved-etc-hosts.c b/src/grp-resolve/systemd-resolved/resolved-etc-hosts.c
index ee82c96822..40d650949d 100644
--- a/src/grp-resolve/systemd-resolved/resolved-etc-hosts.c
+++ b/src/grp-resolve/systemd-resolved/resolved-etc-hosts.c
@@ -301,7 +301,7 @@ int manager_etc_hosts_read(Manager *m) {
FOREACH_LINE(line, f, return log_error_errno(errno, "Failed to read /etc/hosts: %m")) {
char *l;
- nr ++;
+ nr++;
l = strstrip(line);
if (isempty(l))
@@ -363,7 +363,7 @@ int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer) {
if (!IN_SET(t->class, DNS_CLASS_IN, DNS_CLASS_ANY))
continue;
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(t), name);
+ r = dns_name_equal(dns_resource_key_name(t), name);
if (r < 0)
return r;
if (r > 0) {
@@ -413,7 +413,7 @@ int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer) {
if (!IN_SET(t->class, DNS_CLASS_IN, DNS_CLASS_ANY))
continue;
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(t), name);
+ r = dns_name_equal(dns_resource_key_name(t), name);
if (r < 0)
return r;
if (r == 0)
diff --git a/src/grp-resolve/systemd-resolved/resolved-link-bus.c b/src/grp-resolve/systemd-resolved/resolved-link-bus.c
index df7516f4f4..7f21891819 100644
--- a/src/grp-resolve/systemd-resolved/resolved-link-bus.c
+++ b/src/grp-resolve/systemd-resolved/resolved-link-bus.c
@@ -239,7 +239,7 @@ clear:
return r;
}
-int bus_link_method_set_search_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Link *l = userdata;
int r;
@@ -457,10 +457,10 @@ const sd_bus_vtable link_vtable[] = {
SD_BUS_PROPERTY("MulticastDNS", "s", property_get_resolve_support, offsetof(Link, mdns_support), 0),
SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, offsetof(Link, dnssec_mode), 0),
SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0),
- SD_BUS_PROPERTY("DNSSECSupport", "b", property_get_dnssec_supported, 0, 0),
+ SD_BUS_PROPERTY("DNSSECSupported", "b", property_get_dnssec_supported, 0, 0),
SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, 0),
- SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_search_domains, 0),
+ SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_domains, 0),
SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, 0),
SD_BUS_METHOD("SetMulticastDNS", "s", NULL, bus_link_method_set_mdns, 0),
SD_BUS_METHOD("SetDNSSEC", "s", NULL, bus_link_method_set_dnssec, 0),
diff --git a/src/grp-resolve/systemd-resolved/resolved-link-bus.h b/src/grp-resolve/systemd-resolved/resolved-link-bus.h
index 5a8ee08ec7..b1ac57961d 100644
--- a/src/grp-resolve/systemd-resolved/resolved-link-bus.h
+++ b/src/grp-resolve/systemd-resolved/resolved-link-bus.h
@@ -30,7 +30,7 @@ char *link_bus_path(Link *link);
int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error);
-int bus_link_method_set_search_domains(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error);
diff --git a/src/grp-resolve/systemd-resolved/resolved-link.c b/src/grp-resolve/systemd-resolved/resolved-link.c
index 65df95bb1f..4eef20599a 100644
--- a/src/grp-resolve/systemd-resolved/resolved-link.c
+++ b/src/grp-resolve/systemd-resolved/resolved-link.c
@@ -468,7 +468,7 @@ static void link_read_settings(Link *l) {
}
if (r > 0) {
- /* If this link used to be managed, but is now unmanaged, flush all our settings -- but only once. */
+ /* If this link used to be managed, but is now unmanaged, flush all our settings — but only once. */
if (l->is_managed)
link_flush_settings(l);
diff --git a/src/grp-resolve/systemd-resolved/resolved-llmnr.c b/src/grp-resolve/systemd-resolved/resolved-llmnr.c
index ef12abfbb5..8b1d71a3eb 100644
--- a/src/grp-resolve/systemd-resolved/resolved-llmnr.c
+++ b/src/grp-resolve/systemd-resolved/resolved-llmnr.c
@@ -286,7 +286,7 @@ static int on_llmnr_stream_packet(DnsStream *s) {
scope = manager_find_scope(s->manager, s->read_packet);
if (!scope) {
- log_warning("Got LLMNR TCP packet on unknown scope. Ignroing.");
+ log_warning("Got LLMNR TCP packet on unknown scope. Ignoring.");
return 0;
}
diff --git a/src/grp-resolve/systemd-resolved/resolved-manager.c b/src/grp-resolve/systemd-resolved/resolved-manager.c
index e82c6ec563..7166b94d71 100644
--- a/src/grp-resolve/systemd-resolved/resolved-manager.c
+++ b/src/grp-resolve/systemd-resolved/resolved-manager.c
@@ -485,7 +485,7 @@ int manager_new(Manager **ret) {
m->llmnr_support = RESOLVE_SUPPORT_YES;
m->mdns_support = RESOLVE_SUPPORT_NO;
- m->dnssec_mode = DNSSEC_NO;
+ m->dnssec_mode = DEFAULT_DNSSEC_MODE;
m->read_resolv_conf = true;
m->need_builtin_fallbacks = true;
m->etc_hosts_last = m->etc_hosts_mtime = USEC_INFINITY;
@@ -1213,11 +1213,11 @@ void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResource
assert(verdict < _DNSSEC_VERDICT_MAX);
if (log_get_max_level() >= LOG_DEBUG) {
- _cleanup_free_ char *s = NULL;
+ char s[DNS_RESOURCE_KEY_STRING_MAX];
- (void) dns_resource_key_to_string(key, &s);
-
- log_debug("Found verdict for lookup %s: %s", s ? strstrip(s) : "n/a", dnssec_verdict_to_string(verdict));
+ log_debug("Found verdict for lookup %s: %s",
+ dns_resource_key_to_string(key, s, sizeof s),
+ dnssec_verdict_to_string(verdict));
}
m->n_dnssec_verdict[verdict]++;
diff --git a/src/grp-resolve/systemd-resolved/resolved-mdns.c b/src/grp-resolve/systemd-resolved/resolved-mdns.c
index bc8b8b809b..b13b1d0144 100644
--- a/src/grp-resolve/systemd-resolved/resolved-mdns.c
+++ b/src/grp-resolve/systemd-resolved/resolved-mdns.c
@@ -106,7 +106,7 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us
dns_scope_check_conflicts(scope, p);
DNS_ANSWER_FOREACH(rr, p->answer) {
- const char *name = DNS_RESOURCE_KEY_NAME(rr->key);
+ const char *name = dns_resource_key_name(rr->key);
DnsTransaction *t;
/* If the received reply packet contains ANY record that is not .local or .in-addr.arpa,
diff --git a/src/grp-resolve/systemd-resolved/resolved-resolv-conf.c b/src/grp-resolve/systemd-resolved/resolved-resolv-conf.c
index 065427b690..ff03acc772 100644
--- a/src/grp-resolve/systemd-resolved/resolved-resolv-conf.c
+++ b/src/grp-resolve/systemd-resolved/resolved-resolv-conf.c
@@ -158,7 +158,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);
- (*count) ++;
+ (*count)++;
fprintf(f, "nameserver %s\n", s->server_string);
}
@@ -184,7 +184,7 @@ static void write_resolv_conf_search(
}
(*length) += strlen(domain);
- (*count) ++;
+ (*count)++;
fputc(' ', f);
fputs(domain, f);
diff --git a/src/grp-resolve/systemd-resolved/resolved.c b/src/grp-resolve/systemd-resolved/resolved.c
index 07e6bfb54a..086a2fcac7 100644
--- a/src/grp-resolve/systemd-resolved/resolved.c
+++ b/src/grp-resolve/systemd-resolved/resolved.c
@@ -48,7 +48,7 @@ int main(int argc, char *argv[]) {
umask(0022);
- r = mac_selinux_init(NULL);
+ r = mac_selinux_init();
if (r < 0) {
log_error_errno(r, "SELinux setup failed: %m");
goto finish;
diff --git a/src/grp-resolve/systemd-resolved/resolved.conf.in b/src/grp-resolve/systemd-resolved/resolved.conf.in
index efc9c6733a..a288588924 100644
--- a/src/grp-resolve/systemd-resolved/resolved.conf.in
+++ b/src/grp-resolve/systemd-resolved/resolved.conf.in
@@ -16,4 +16,4 @@
#FallbackDNS=@DNS_SERVERS@
#Domains=
#LLMNR=yes
-#DNSSEC=no
+#DNSSEC=@DEFAULT_DNSSEC_MODE@
diff --git a/src/grp-resolve/systemd-resolved/test-data/_443._tcp.fedoraproject.org.pkts b/src/grp-resolve/systemd-resolved/test-data/_443._tcp.fedoraproject.org.pkts
new file mode 100644
index 0000000000..a383c6286d
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/_443._tcp.fedoraproject.org.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-data/_openpgpkey.fedoraproject.org.pkts b/src/grp-resolve/systemd-resolved/test-data/_openpgpkey.fedoraproject.org.pkts
new file mode 100644
index 0000000000..15de02e997
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/_openpgpkey.fedoraproject.org.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-data/fake-caa.pkts b/src/grp-resolve/systemd-resolved/test-data/fake-caa.pkts
new file mode 100644
index 0000000000..1c3ecc5491
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/fake-caa.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-data/fedoraproject.org.pkts b/src/grp-resolve/systemd-resolved/test-data/fedoraproject.org.pkts
new file mode 100644
index 0000000000..17874844d9
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/fedoraproject.org.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-data/gandi.net.pkts b/src/grp-resolve/systemd-resolved/test-data/gandi.net.pkts
new file mode 100644
index 0000000000..5ef51e0c8e
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/gandi.net.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-data/google.com.pkts b/src/grp-resolve/systemd-resolved/test-data/google.com.pkts
new file mode 100644
index 0000000000..f98c4cd855
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/google.com.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-data/kyhwana.org.pkts b/src/grp-resolve/systemd-resolved/test-data/kyhwana.org.pkts
new file mode 100644
index 0000000000..e28a725c9a
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/kyhwana.org.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-data/root.pkts b/src/grp-resolve/systemd-resolved/test-data/root.pkts
new file mode 100644
index 0000000000..54ba668c75
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/root.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts b/src/grp-resolve/systemd-resolved/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts
new file mode 100644
index 0000000000..a854249532
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-data/teamits.com.pkts b/src/grp-resolve/systemd-resolved/test-data/teamits.com.pkts
new file mode 100644
index 0000000000..11deb39677
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/teamits.com.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-data/zbyszek@fedoraproject.org.pkts b/src/grp-resolve/systemd-resolved/test-data/zbyszek@fedoraproject.org.pkts
new file mode 100644
index 0000000000..f0a6f982df
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/zbyszek@fedoraproject.org.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-dns-packet.c b/src/grp-resolve/systemd-resolved/test-dns-packet.c
new file mode 100644
index 0000000000..c232a69ce1
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-dns-packet.c
@@ -0,0 +1,114 @@
+/***
+ This file is part of systemd
+
+ Copyright 2016 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <net/if.h>
+#include <glob.h>
+
+#include "alloc-util.h"
+#include "fileio.h"
+#include "glob-util.h"
+#include "log.h"
+#include "macro.h"
+#include "resolved-dns-packet.h"
+#include "resolved-dns-rr.h"
+#include "string-util.h"
+#include "strv.h"
+
+#define HASH_KEY SD_ID128_MAKE(d3,1e,48,90,4b,fa,4c,fe,af,9d,d5,a1,d7,2e,8a,b1)
+
+static uint64_t hash(DnsResourceRecord *rr) {
+ struct siphash state;
+
+ siphash24_init(&state, HASH_KEY.bytes);
+ dns_resource_record_hash_func(rr, &state);
+ return siphash24_finalize(&state);
+}
+
+static void test_packet_from_file(const char* filename, bool canonical) {
+ _cleanup_free_ char *data = NULL;
+ size_t data_size, packet_size, offset;
+
+ assert_se(read_full_file(filename, &data, &data_size) >= 0);
+ assert_se(data);
+ assert_se(data_size > 8);
+
+ log_info("============== %s %s==============", filename, canonical ? "canonical " : "");
+
+ for (offset = 0; offset < data_size; offset += 8 + packet_size) {
+ _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL, *p2 = NULL;
+ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL, *rr2 = NULL;
+ const char *s, *s2;
+ uint64_t hash1, hash2;
+
+ packet_size = le64toh( *(uint64_t*)(data + offset) );
+ 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_append_blob(p, data + offset + 8, packet_size, NULL) >= 0);
+ assert_se(dns_packet_read_rr(p, &rr, NULL, NULL) >= 0);
+
+ s = dns_resource_record_to_string(rr);
+ assert_se(s);
+ puts(s);
+
+ hash1 = hash(rr);
+
+ 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_append_blob(p2, rr->wire_format, rr->wire_format_size, NULL) >= 0);
+ assert_se(dns_packet_read_rr(p2, &rr2, NULL, NULL) >= 0);
+
+ s2 = dns_resource_record_to_string(rr);
+ assert_se(s2);
+ assert_se(streq(s, s2));
+
+ hash2 = hash(rr);
+ assert_se(hash1 == hash2);
+ }
+}
+
+int main(int argc, char **argv) {
+ int i, N;
+ _cleanup_globfree_ glob_t g = {};
+ char **fnames;
+
+ log_parse_environment();
+
+ if (argc >= 2) {
+ N = argc - 1;
+ fnames = argv + 1;
+ } else {
+ assert_se(glob(RESOLVE_TEST_DIR "/*.pkts", GLOB_NOSORT, NULL, &g) == 0);
+ N = g.gl_pathc;
+ fnames = g.gl_pathv;
+ }
+
+ for (i = 0; i < N; i++) {
+ test_packet_from_file(fnames[i], false);
+ puts("");
+ test_packet_from_file(fnames[i], true);
+ if (i + 1 < N)
+ puts("");
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/grp-resolve/systemd-resolved/test-dnssec.c b/src/grp-resolve/systemd-resolved/test-dnssec.c
index a093d86a91..b3018e8239 100644
--- a/src/grp-resolve/systemd-resolved/test-dnssec.c
+++ b/src/grp-resolve/systemd-resolved/test-dnssec.c
@@ -27,77 +27,89 @@
#include "string-util.h"
#include "hexdecoct.h"
-static void test_dnssec_verify_rrset2(void) {
+static void test_dnssec_canonicalize_one(const char *original, const char *canonical, int r) {
+ char canonicalized[DNSSEC_CANONICAL_HOSTNAME_MAX];
- static const uint8_t signature_blob[] = {
- 0x48, 0x45, 0xc8, 0x8b, 0xc0, 0x14, 0x92, 0xf5, 0x15, 0xc6, 0x84, 0x9d, 0x2f, 0xe3, 0x32, 0x11,
- 0x7d, 0xf1, 0xe6, 0x87, 0xb9, 0x42, 0xd3, 0x8b, 0x9e, 0xaf, 0x92, 0x31, 0x0a, 0x53, 0xad, 0x8b,
- 0xa7, 0x5c, 0x83, 0x39, 0x8c, 0x28, 0xac, 0xce, 0x6e, 0x9c, 0x18, 0xe3, 0x31, 0x16, 0x6e, 0xca,
- 0x38, 0x31, 0xaf, 0xd9, 0x94, 0xf1, 0x84, 0xb1, 0xdf, 0x5a, 0xc2, 0x73, 0x22, 0xf6, 0xcb, 0xa2,
- 0xe7, 0x8c, 0x77, 0x0c, 0x74, 0x2f, 0xc2, 0x13, 0xb0, 0x93, 0x51, 0xa9, 0x4f, 0xae, 0x0a, 0xda,
- 0x45, 0xcc, 0xfd, 0x43, 0x99, 0x36, 0x9a, 0x0d, 0x21, 0xe0, 0xeb, 0x30, 0x65, 0xd4, 0xa0, 0x27,
- 0x37, 0x3b, 0xe4, 0xc1, 0xc5, 0xa1, 0x2a, 0xd1, 0x76, 0xc4, 0x7e, 0x64, 0x0e, 0x5a, 0xa6, 0x50,
- 0x24, 0xd5, 0x2c, 0xcc, 0x6d, 0xe5, 0x37, 0xea, 0xbd, 0x09, 0x34, 0xed, 0x24, 0x06, 0xa1, 0x22,
- };
+ assert_se(dnssec_canonicalize(original, canonicalized, sizeof(canonicalized)) == r);
+ if (r < 0)
+ return;
+
+ assert_se(streq(canonicalized, canonical));
+}
+static void test_dnssec_canonicalize(void) {
+ test_dnssec_canonicalize_one("", ".", 1);
+ test_dnssec_canonicalize_one(".", ".", 1);
+ test_dnssec_canonicalize_one("foo", "foo.", 4);
+ test_dnssec_canonicalize_one("foo.", "foo.", 4);
+ test_dnssec_canonicalize_one("FOO.", "foo.", 4);
+ test_dnssec_canonicalize_one("FOO.bar.", "foo.bar.", 8);
+ test_dnssec_canonicalize_one("FOO..bar.", NULL, -EINVAL);
+}
+
+#ifdef HAVE_GCRYPT
+
+static void test_dnssec_verify_dns_key(void) {
+
+ static const uint8_t ds1_fprint[] = {
+ 0x46, 0x8B, 0xC8, 0xDD, 0xC7, 0xE8, 0x27, 0x03, 0x40, 0xBB, 0x8A, 0x1F, 0x3B, 0x2E, 0x45, 0x9D,
+ 0x80, 0x67, 0x14, 0x01,
+ };
+ static const uint8_t ds2_fprint[] = {
+ 0x8A, 0xEE, 0x80, 0x47, 0x05, 0x5F, 0x83, 0xD1, 0x48, 0xBA, 0x8F, 0xF6, 0xDD, 0xA7, 0x60, 0xCE,
+ 0x94, 0xF7, 0xC7, 0x5E, 0x52, 0x4C, 0xF2, 0xE9, 0x50, 0xB9, 0x2E, 0xCB, 0xEF, 0x96, 0xB9, 0x98,
+ };
static const uint8_t dnskey_blob[] = {
- 0x03, 0x01, 0x00, 0x01, 0xc3, 0x7f, 0x1d, 0xd1, 0x1c, 0x97, 0xb1, 0x13, 0x34, 0x3a, 0x9a, 0xea,
- 0xee, 0xd9, 0x5a, 0x11, 0x1b, 0x17, 0xc7, 0xe3, 0xd4, 0xda, 0x20, 0xbc, 0x5d, 0xba, 0x74, 0xe3,
- 0x37, 0x99, 0xec, 0x25, 0xce, 0x93, 0x7f, 0xbd, 0x22, 0x73, 0x7e, 0x14, 0x71, 0xe0, 0x60, 0x07,
- 0xd4, 0x39, 0x8b, 0x5e, 0xe9, 0xba, 0x25, 0xe8, 0x49, 0xe9, 0x34, 0xef, 0xfe, 0x04, 0x5c, 0xa5,
- 0x27, 0xcd, 0xa9, 0xda, 0x70, 0x05, 0x21, 0xab, 0x15, 0x82, 0x24, 0xc3, 0x94, 0xf5, 0xd7, 0xb7,
- 0xc4, 0x66, 0xcb, 0x32, 0x6e, 0x60, 0x2b, 0x55, 0x59, 0x28, 0x89, 0x8a, 0x72, 0xde, 0x88, 0x56,
- 0x27, 0x95, 0xd9, 0xac, 0x88, 0x4f, 0x65, 0x2b, 0x68, 0xfc, 0xe6, 0x41, 0xc1, 0x1b, 0xef, 0x4e,
- 0xd6, 0xc2, 0x0f, 0x64, 0x88, 0x95, 0x5e, 0xdd, 0x3a, 0x02, 0x07, 0x50, 0xa9, 0xda, 0xa4, 0x49,
- 0x74, 0x62, 0xfe, 0xd7,
+ 0x03, 0x01, 0x00, 0x01, 0xa8, 0x12, 0xda, 0x4f, 0xd2, 0x7d, 0x54, 0x14, 0x0e, 0xcc, 0x5b, 0x5e,
+ 0x45, 0x9c, 0x96, 0x98, 0xc0, 0xc0, 0x85, 0x81, 0xb1, 0x47, 0x8c, 0x7d, 0xe8, 0x39, 0x50, 0xcc,
+ 0xc5, 0xd0, 0xf2, 0x00, 0x81, 0x67, 0x79, 0xf6, 0xcc, 0x9d, 0xad, 0x6c, 0xbb, 0x7b, 0x6f, 0x48,
+ 0x97, 0x15, 0x1c, 0xfd, 0x0b, 0xfe, 0xd3, 0xd7, 0x7d, 0x9f, 0x81, 0x26, 0xd3, 0xc5, 0x65, 0x49,
+ 0xcf, 0x46, 0x62, 0xb0, 0x55, 0x6e, 0x47, 0xc7, 0x30, 0xef, 0x51, 0xfb, 0x3e, 0xc6, 0xef, 0xde,
+ 0x27, 0x3f, 0xfa, 0x57, 0x2d, 0xa7, 0x1d, 0x80, 0x46, 0x9a, 0x5f, 0x14, 0xb3, 0xb0, 0x2c, 0xbe,
+ 0x72, 0xca, 0xdf, 0xb2, 0xff, 0x36, 0x5b, 0x4f, 0xec, 0x58, 0x8e, 0x8d, 0x01, 0xe9, 0xa9, 0xdf,
+ 0xb5, 0x60, 0xad, 0x52, 0x4d, 0xfc, 0xa9, 0x3e, 0x8d, 0x35, 0x95, 0xb3, 0x4e, 0x0f, 0xca, 0x45,
+ 0x1b, 0xf7, 0xef, 0x3a, 0x88, 0x25, 0x08, 0xc7, 0x4e, 0x06, 0xc1, 0x62, 0x1a, 0xce, 0xd8, 0x77,
+ 0xbd, 0x02, 0x65, 0xf8, 0x49, 0xfb, 0xce, 0xf6, 0xa8, 0x09, 0xfc, 0xde, 0xb2, 0x09, 0x9d, 0x39,
+ 0xf8, 0x63, 0x9c, 0x32, 0x42, 0x7c, 0xa0, 0x30, 0x86, 0x72, 0x7a, 0x4a, 0xc6, 0xd4, 0xb3, 0x2d,
+ 0x24, 0xef, 0x96, 0x3f, 0xc2, 0xda, 0xd3, 0xf2, 0x15, 0x6f, 0xda, 0x65, 0x4b, 0x81, 0x28, 0x68,
+ 0xf4, 0xfe, 0x3e, 0x71, 0x4f, 0x50, 0x96, 0x72, 0x58, 0xa1, 0x89, 0xdd, 0x01, 0x61, 0x39, 0x39,
+ 0xc6, 0x76, 0xa4, 0xda, 0x02, 0x70, 0x3d, 0xc0, 0xdc, 0x8d, 0x70, 0x72, 0x04, 0x90, 0x79, 0xd4,
+ 0xec, 0x65, 0xcf, 0x49, 0x35, 0x25, 0x3a, 0x14, 0x1a, 0x45, 0x20, 0xeb, 0x31, 0xaf, 0x92, 0xba,
+ 0x20, 0xd3, 0xcd, 0xa7, 0x13, 0x44, 0xdc, 0xcf, 0xf0, 0x27, 0x34, 0xb9, 0xe7, 0x24, 0x6f, 0x73,
+ 0xe7, 0xea, 0x77, 0x03,
};
- _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL;
- _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
- DnssecResult result;
-
- nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov");
- assert_se(nsec);
+ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds1 = NULL, *ds2 = NULL;
- nsec->nsec.next_domain_name = strdup("3D-Printing.nasa.gov");
- assert_se(nsec->nsec.next_domain_name);
+ /* The two DS RRs in effect for nasa.gov on 2015-12-01. */
+ ds1 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "nasa.gov");
+ assert_se(ds1);
- nsec->nsec.types = bitmap_new();
- assert_se(nsec->nsec.types);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_A) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NS) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_SOA) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_MX) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_TXT) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_RRSIG) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NSEC) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_DNSKEY) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, 65534) >= 0);
+ ds1->ds.key_tag = 47857;
+ ds1->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256;
+ ds1->ds.digest_type = DNSSEC_DIGEST_SHA1;
+ ds1->ds.digest_size = sizeof(ds1_fprint);
+ ds1->ds.digest = memdup(ds1_fprint, ds1->ds.digest_size);
+ assert_se(ds1->ds.digest);
- log_info("NSEC: %s", strna(dns_resource_record_to_string(nsec)));
+ log_info("DS1: %s", strna(dns_resource_record_to_string(ds1)));
- rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV.");
- assert_se(rrsig);
+ ds2 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "NASA.GOV");
+ assert_se(ds2);
- rrsig->rrsig.type_covered = DNS_TYPE_NSEC;
- rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_RSASHA256;
- rrsig->rrsig.labels = 2;
- rrsig->rrsig.original_ttl = 300;
- rrsig->rrsig.expiration = 0x5689002f;
- rrsig->rrsig.inception = 0x56617230;
- rrsig->rrsig.key_tag = 30390;
- rrsig->rrsig.signer = strdup("Nasa.Gov.");
- assert_se(rrsig->rrsig.signer);
- rrsig->rrsig.signature_size = sizeof(signature_blob);
- rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size);
- assert_se(rrsig->rrsig.signature);
+ ds2->ds.key_tag = 47857;
+ ds2->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256;
+ ds2->ds.digest_type = DNSSEC_DIGEST_SHA256;
+ ds2->ds.digest_size = sizeof(ds2_fprint);
+ ds2->ds.digest = memdup(ds2_fprint, ds2->ds.digest_size);
+ assert_se(ds2->ds.digest);
- log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig)));
+ log_info("DS2: %s", strna(dns_resource_record_to_string(ds2)));
- dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV");
+ dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nasa.GOV");
assert_se(dnskey);
- dnskey->dnskey.flags = 256;
+ dnskey->dnskey.flags = 257;
dnskey->dnskey.protocol = 3;
dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256;
dnskey->dnskey.key_size = sizeof(dnskey_blob);
@@ -107,16 +119,8 @@ static void test_dnssec_verify_rrset2(void) {
log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false));
- assert_se(dnssec_key_match_rrsig(nsec->key, rrsig) > 0);
- assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0);
-
- answer = dns_answer_new(1);
- assert_se(answer);
- assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
-
- /* Validate the RR as it if was 2015-12-11 today */
- assert_se(dnssec_verify_rrset(answer, nsec->key, rrsig, dnskey, 1449849318*USEC_PER_SEC, &result) >= 0);
- assert_se(result == DNSSEC_VALIDATED);
+ assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds1, false) > 0);
+ assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds2, false) > 0);
}
static void test_dnssec_verify_rrset(void) {
@@ -198,67 +202,77 @@ static void test_dnssec_verify_rrset(void) {
assert_se(result == DNSSEC_VALIDATED);
}
-static void test_dnssec_verify_dns_key(void) {
+static void test_dnssec_verify_rrset2(void) {
- static const uint8_t ds1_fprint[] = {
- 0x46, 0x8B, 0xC8, 0xDD, 0xC7, 0xE8, 0x27, 0x03, 0x40, 0xBB, 0x8A, 0x1F, 0x3B, 0x2E, 0x45, 0x9D,
- 0x80, 0x67, 0x14, 0x01,
- };
- static const uint8_t ds2_fprint[] = {
- 0x8A, 0xEE, 0x80, 0x47, 0x05, 0x5F, 0x83, 0xD1, 0x48, 0xBA, 0x8F, 0xF6, 0xDD, 0xA7, 0x60, 0xCE,
- 0x94, 0xF7, 0xC7, 0x5E, 0x52, 0x4C, 0xF2, 0xE9, 0x50, 0xB9, 0x2E, 0xCB, 0xEF, 0x96, 0xB9, 0x98,
+ static const uint8_t signature_blob[] = {
+ 0x48, 0x45, 0xc8, 0x8b, 0xc0, 0x14, 0x92, 0xf5, 0x15, 0xc6, 0x84, 0x9d, 0x2f, 0xe3, 0x32, 0x11,
+ 0x7d, 0xf1, 0xe6, 0x87, 0xb9, 0x42, 0xd3, 0x8b, 0x9e, 0xaf, 0x92, 0x31, 0x0a, 0x53, 0xad, 0x8b,
+ 0xa7, 0x5c, 0x83, 0x39, 0x8c, 0x28, 0xac, 0xce, 0x6e, 0x9c, 0x18, 0xe3, 0x31, 0x16, 0x6e, 0xca,
+ 0x38, 0x31, 0xaf, 0xd9, 0x94, 0xf1, 0x84, 0xb1, 0xdf, 0x5a, 0xc2, 0x73, 0x22, 0xf6, 0xcb, 0xa2,
+ 0xe7, 0x8c, 0x77, 0x0c, 0x74, 0x2f, 0xc2, 0x13, 0xb0, 0x93, 0x51, 0xa9, 0x4f, 0xae, 0x0a, 0xda,
+ 0x45, 0xcc, 0xfd, 0x43, 0x99, 0x36, 0x9a, 0x0d, 0x21, 0xe0, 0xeb, 0x30, 0x65, 0xd4, 0xa0, 0x27,
+ 0x37, 0x3b, 0xe4, 0xc1, 0xc5, 0xa1, 0x2a, 0xd1, 0x76, 0xc4, 0x7e, 0x64, 0x0e, 0x5a, 0xa6, 0x50,
+ 0x24, 0xd5, 0x2c, 0xcc, 0x6d, 0xe5, 0x37, 0xea, 0xbd, 0x09, 0x34, 0xed, 0x24, 0x06, 0xa1, 0x22,
};
+
static const uint8_t dnskey_blob[] = {
- 0x03, 0x01, 0x00, 0x01, 0xa8, 0x12, 0xda, 0x4f, 0xd2, 0x7d, 0x54, 0x14, 0x0e, 0xcc, 0x5b, 0x5e,
- 0x45, 0x9c, 0x96, 0x98, 0xc0, 0xc0, 0x85, 0x81, 0xb1, 0x47, 0x8c, 0x7d, 0xe8, 0x39, 0x50, 0xcc,
- 0xc5, 0xd0, 0xf2, 0x00, 0x81, 0x67, 0x79, 0xf6, 0xcc, 0x9d, 0xad, 0x6c, 0xbb, 0x7b, 0x6f, 0x48,
- 0x97, 0x15, 0x1c, 0xfd, 0x0b, 0xfe, 0xd3, 0xd7, 0x7d, 0x9f, 0x81, 0x26, 0xd3, 0xc5, 0x65, 0x49,
- 0xcf, 0x46, 0x62, 0xb0, 0x55, 0x6e, 0x47, 0xc7, 0x30, 0xef, 0x51, 0xfb, 0x3e, 0xc6, 0xef, 0xde,
- 0x27, 0x3f, 0xfa, 0x57, 0x2d, 0xa7, 0x1d, 0x80, 0x46, 0x9a, 0x5f, 0x14, 0xb3, 0xb0, 0x2c, 0xbe,
- 0x72, 0xca, 0xdf, 0xb2, 0xff, 0x36, 0x5b, 0x4f, 0xec, 0x58, 0x8e, 0x8d, 0x01, 0xe9, 0xa9, 0xdf,
- 0xb5, 0x60, 0xad, 0x52, 0x4d, 0xfc, 0xa9, 0x3e, 0x8d, 0x35, 0x95, 0xb3, 0x4e, 0x0f, 0xca, 0x45,
- 0x1b, 0xf7, 0xef, 0x3a, 0x88, 0x25, 0x08, 0xc7, 0x4e, 0x06, 0xc1, 0x62, 0x1a, 0xce, 0xd8, 0x77,
- 0xbd, 0x02, 0x65, 0xf8, 0x49, 0xfb, 0xce, 0xf6, 0xa8, 0x09, 0xfc, 0xde, 0xb2, 0x09, 0x9d, 0x39,
- 0xf8, 0x63, 0x9c, 0x32, 0x42, 0x7c, 0xa0, 0x30, 0x86, 0x72, 0x7a, 0x4a, 0xc6, 0xd4, 0xb3, 0x2d,
- 0x24, 0xef, 0x96, 0x3f, 0xc2, 0xda, 0xd3, 0xf2, 0x15, 0x6f, 0xda, 0x65, 0x4b, 0x81, 0x28, 0x68,
- 0xf4, 0xfe, 0x3e, 0x71, 0x4f, 0x50, 0x96, 0x72, 0x58, 0xa1, 0x89, 0xdd, 0x01, 0x61, 0x39, 0x39,
- 0xc6, 0x76, 0xa4, 0xda, 0x02, 0x70, 0x3d, 0xc0, 0xdc, 0x8d, 0x70, 0x72, 0x04, 0x90, 0x79, 0xd4,
- 0xec, 0x65, 0xcf, 0x49, 0x35, 0x25, 0x3a, 0x14, 0x1a, 0x45, 0x20, 0xeb, 0x31, 0xaf, 0x92, 0xba,
- 0x20, 0xd3, 0xcd, 0xa7, 0x13, 0x44, 0xdc, 0xcf, 0xf0, 0x27, 0x34, 0xb9, 0xe7, 0x24, 0x6f, 0x73,
- 0xe7, 0xea, 0x77, 0x03,
+ 0x03, 0x01, 0x00, 0x01, 0xc3, 0x7f, 0x1d, 0xd1, 0x1c, 0x97, 0xb1, 0x13, 0x34, 0x3a, 0x9a, 0xea,
+ 0xee, 0xd9, 0x5a, 0x11, 0x1b, 0x17, 0xc7, 0xe3, 0xd4, 0xda, 0x20, 0xbc, 0x5d, 0xba, 0x74, 0xe3,
+ 0x37, 0x99, 0xec, 0x25, 0xce, 0x93, 0x7f, 0xbd, 0x22, 0x73, 0x7e, 0x14, 0x71, 0xe0, 0x60, 0x07,
+ 0xd4, 0x39, 0x8b, 0x5e, 0xe9, 0xba, 0x25, 0xe8, 0x49, 0xe9, 0x34, 0xef, 0xfe, 0x04, 0x5c, 0xa5,
+ 0x27, 0xcd, 0xa9, 0xda, 0x70, 0x05, 0x21, 0xab, 0x15, 0x82, 0x24, 0xc3, 0x94, 0xf5, 0xd7, 0xb7,
+ 0xc4, 0x66, 0xcb, 0x32, 0x6e, 0x60, 0x2b, 0x55, 0x59, 0x28, 0x89, 0x8a, 0x72, 0xde, 0x88, 0x56,
+ 0x27, 0x95, 0xd9, 0xac, 0x88, 0x4f, 0x65, 0x2b, 0x68, 0xfc, 0xe6, 0x41, 0xc1, 0x1b, 0xef, 0x4e,
+ 0xd6, 0xc2, 0x0f, 0x64, 0x88, 0x95, 0x5e, 0xdd, 0x3a, 0x02, 0x07, 0x50, 0xa9, 0xda, 0xa4, 0x49,
+ 0x74, 0x62, 0xfe, 0xd7,
};
- _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds1 = NULL, *ds2 = NULL;
+ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL;
+ _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
+ DnssecResult result;
- /* The two DS RRs in effect for nasa.gov on 2015-12-01. */
- ds1 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "nasa.gov");
- assert_se(ds1);
+ nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov");
+ assert_se(nsec);
- ds1->ds.key_tag = 47857;
- ds1->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256;
- ds1->ds.digest_type = DNSSEC_DIGEST_SHA1;
- ds1->ds.digest_size = sizeof(ds1_fprint);
- ds1->ds.digest = memdup(ds1_fprint, ds1->ds.digest_size);
- assert_se(ds1->ds.digest);
+ nsec->nsec.next_domain_name = strdup("3D-Printing.nasa.gov");
+ assert_se(nsec->nsec.next_domain_name);
- log_info("DS1: %s", strna(dns_resource_record_to_string(ds1)));
+ nsec->nsec.types = bitmap_new();
+ assert_se(nsec->nsec.types);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_A) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NS) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_SOA) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_MX) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_TXT) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_RRSIG) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NSEC) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_DNSKEY) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, 65534) >= 0);
- ds2 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "NASA.GOV");
- assert_se(ds2);
+ log_info("NSEC: %s", strna(dns_resource_record_to_string(nsec)));
- ds2->ds.key_tag = 47857;
- ds2->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256;
- ds2->ds.digest_type = DNSSEC_DIGEST_SHA256;
- ds2->ds.digest_size = sizeof(ds2_fprint);
- ds2->ds.digest = memdup(ds2_fprint, ds2->ds.digest_size);
- assert_se(ds2->ds.digest);
+ rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV.");
+ assert_se(rrsig);
- log_info("DS2: %s", strna(dns_resource_record_to_string(ds2)));
+ rrsig->rrsig.type_covered = DNS_TYPE_NSEC;
+ rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_RSASHA256;
+ rrsig->rrsig.labels = 2;
+ rrsig->rrsig.original_ttl = 300;
+ rrsig->rrsig.expiration = 0x5689002f;
+ rrsig->rrsig.inception = 0x56617230;
+ rrsig->rrsig.key_tag = 30390;
+ rrsig->rrsig.signer = strdup("Nasa.Gov.");
+ assert_se(rrsig->rrsig.signer);
+ rrsig->rrsig.signature_size = sizeof(signature_blob);
+ rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size);
+ assert_se(rrsig->rrsig.signature);
- dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nasa.GOV");
+ log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig)));
+
+ dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV");
assert_se(dnskey);
- dnskey->dnskey.flags = 257;
+ dnskey->dnskey.flags = 256;
dnskey->dnskey.protocol = 3;
dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256;
dnskey->dnskey.key_size = sizeof(dnskey_blob);
@@ -268,28 +282,16 @@ static void test_dnssec_verify_dns_key(void) {
log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false));
- assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds1, false) > 0);
- assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds2, false) > 0);
-}
-
-static void test_dnssec_canonicalize_one(const char *original, const char *canonical, int r) {
- char canonicalized[DNSSEC_CANONICAL_HOSTNAME_MAX];
-
- assert_se(dnssec_canonicalize(original, canonicalized, sizeof(canonicalized)) == r);
- if (r < 0)
- return;
+ assert_se(dnssec_key_match_rrsig(nsec->key, rrsig) > 0);
+ assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0);
- assert_se(streq(canonicalized, canonical));
-}
+ answer = dns_answer_new(1);
+ assert_se(answer);
+ assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
-static void test_dnssec_canonicalize(void) {
- test_dnssec_canonicalize_one("", ".", 1);
- test_dnssec_canonicalize_one(".", ".", 1);
- test_dnssec_canonicalize_one("foo", "foo.", 4);
- test_dnssec_canonicalize_one("foo.", "foo.", 4);
- test_dnssec_canonicalize_one("FOO.", "foo.", 4);
- test_dnssec_canonicalize_one("FOO.bar.", "foo.bar.", 8);
- test_dnssec_canonicalize_one("FOO..bar.", NULL, -EINVAL);
+ /* Validate the RR as it if was 2015-12-11 today */
+ assert_se(dnssec_verify_rrset(answer, nsec->key, rrsig, dnskey, 1449849318*USEC_PER_SEC, &result) >= 0);
+ assert_se(result == DNSSEC_VALIDATED);
}
static void test_dnssec_nsec3_hash(void) {
@@ -324,13 +326,18 @@ static void test_dnssec_nsec3_hash(void) {
assert_se(strcasecmp(b, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM") == 0);
}
+#endif
+
int main(int argc, char*argv[]) {
test_dnssec_canonicalize();
+
+#ifdef HAVE_GCRYPT
test_dnssec_verify_dns_key();
test_dnssec_verify_rrset();
test_dnssec_verify_rrset2();
test_dnssec_nsec3_hash();
+#endif
return 0;
}
diff --git a/src/grp-resolve/systemd-resolved/test-resolve-tables.c b/src/grp-resolve/systemd-resolved/test-resolve-tables.c
index 63660afc87..2d615130e1 100644
--- a/src/grp-resolve/systemd-resolved/test-resolve-tables.c
+++ b/src/grp-resolve/systemd-resolved/test-resolve-tables.c
@@ -21,7 +21,44 @@
#include "test-tables.h"
int main(int argc, char **argv) {
+ uint16_t i;
+
test_table_sparse(dns_type, DNS_TYPE);
+ log_info("/* DNS_TYPE */");
+ for (i = 0; i < _DNS_TYPE_MAX; i++) {
+ const char *s;
+
+ s = dns_type_to_string(i);
+ assert_se(s == NULL || strlen(s) < _DNS_TYPE_STRING_MAX);
+
+ if (s)
+ log_info("%-*s %s%s%s%s%s%s%s%s%s",
+ (int) _DNS_TYPE_STRING_MAX - 1, s,
+ dns_type_is_pseudo(i) ? "pseudo " : "",
+ dns_type_is_valid_query(i) ? "valid_query " : "",
+ dns_type_is_valid_rr(i) ? "is_valid_rr " : "",
+ dns_type_may_redirect(i) ? "may_redirect " : "",
+ dns_type_is_dnssec(i) ? "dnssec " : "",
+ dns_type_is_obsolete(i) ? "obsolete " : "",
+ dns_type_may_wildcard(i) ? "wildcard " : "",
+ dns_type_apex_only(i) ? "apex_only " : "",
+ dns_type_needs_authentication(i) ? "needs_authentication" : "");
+ }
+
+ log_info("/* DNS_CLASS */");
+ for (i = 0; i < _DNS_CLASS_MAX; i++) {
+ const char *s;
+
+ s = dns_class_to_string(i);
+ assert_se(s == NULL || strlen(s) < _DNS_CLASS_STRING_MAX);
+
+ if (s)
+ log_info("%-*s %s%s",
+ (int) _DNS_CLASS_STRING_MAX - 1, s,
+ dns_class_is_pseudo(i) ? "is_pseudo " : "",
+ dns_class_is_valid_rr(i) ? "is_valid_rr " : "");
+ }
+
return EXIT_SUCCESS;
}