summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am6
-rw-r--r--NEWS17
-rw-r--r--configure.ac28
-rw-r--r--man/systemd-resolve.xml51
-rw-r--r--src/basic/af-list.h16
-rw-r--r--src/basic/missing.h8
-rw-r--r--src/basic/socket-util.c34
-rw-r--r--src/basic/socket-util.h2
-rw-r--r--src/basic/time-util.c14
-rw-r--r--src/basic/time-util.h1
-rw-r--r--src/core/load-fragment.c11
-rw-r--r--src/core/main.c1
-rw-r--r--src/core/timer.c2
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c25
-rw-r--r--src/libsystemd-network/sd-dhcp-server.c9
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c13
-rw-r--r--src/libsystemd-network/sd-ndisc.c13
-rw-r--r--src/login/logind-session.c15
-rw-r--r--src/login/logind-user.c15
-rw-r--r--src/machine/machine.c15
-rw-r--r--src/network/networkd-manager.c19
-rw-r--r--src/resolve/dns-type.c17
-rw-r--r--src/resolve/dns-type.h8
-rw-r--r--src/resolve/resolve-tool.c165
-rw-r--r--src/resolve/resolved-bus.c36
-rw-r--r--src/resolve/resolved-dns-answer.c8
-rw-r--r--src/resolve/resolved-dns-cache.c142
-rw-r--r--src/resolve/resolved-dns-dnssec.c52
-rw-r--r--src/resolve/resolved-dns-packet.c4
-rw-r--r--src/resolve/resolved-dns-query.c22
-rw-r--r--src/resolve/resolved-dns-question.c10
-rw-r--r--src/resolve/resolved-dns-rr.c123
-rw-r--r--src/resolve/resolved-dns-rr.h23
-rw-r--r--src/resolve/resolved-dns-scope.c4
-rw-r--r--src/resolve/resolved-dns-synthesize.c14
-rw-r--r--src/resolve/resolved-dns-transaction.c653
-rw-r--r--src/resolve/resolved-dns-transaction.h3
-rw-r--r--src/resolve/resolved-dns-trust-anchor.c4
-rw-r--r--src/resolve/resolved-dns-zone.c34
-rw-r--r--src/resolve/resolved-etc-hosts.c4
-rw-r--r--src/resolve/resolved-manager.c20
-rw-r--r--src/resolve/resolved-mdns.c2
-rw-r--r--src/resolve/resolved.conf.in2
-rw-r--r--src/resolve/test-resolve-tables.c37
-rw-r--r--src/shared/bus-util.c45
-rw-r--r--src/shared/bus-util.h2
-rw-r--r--src/systemctl/systemctl.c17
-rw-r--r--src/test/test-execute.c5
-rw-r--r--src/udev/udevd.c2
-rw-r--r--test/test-execute/exec-spec-interpolation.service6
50 files changed, 1033 insertions, 746 deletions
diff --git a/Makefile.am b/Makefile.am
index 9bc0bf2c05..5e3c12c47f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1476,8 +1476,6 @@ tests += \
test-af-list \
test-arphrd-list \
test-dns-domain \
- test-dns-packet \
- test-resolve-tables \
test-install-root \
test-rlimit-util \
test-signal-util
@@ -5208,7 +5206,8 @@ bin_PROGRAMS += \
systemd-resolve
tests += \
- test-dns-domain \
+ test-dns-packet \
+ test-resolve-tables \
test-dnssec
manual_tests += \
@@ -5759,6 +5758,7 @@ substitutions = \
'|PYTHON=$(PYTHON)|' \
'|NTP_SERVERS=$(NTP_SERVERS)|' \
'|DNS_SERVERS=$(DNS_SERVERS)|' \
+ '|DEFAULT_DNSSEC_MODE=$(DEFAULT_DNSSEC_MODE)|' \
'|systemuidmax=$(SYSTEM_UID_MAX)|' \
'|systemgidmax=$(SYSTEM_GID_MAX)|' \
'|TTY_GID=$(TTY_GID)|' \
diff --git a/NEWS b/NEWS
index 80e59c53d3..0cce79443b 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,23 @@ systemd System and Service Manager
CHANGES WITH 230 in spe:
+ * DNSSEC is now turned on by default in systemd-resolved (in
+ "allow-downgrade" mode), but may be turned off during compile time by
+ passing "--with-default-dnssec=no" to "configure" (and of course,
+ during runtime with DNSSEC= in resolved.conf). We recommend
+ downstreams to leave this on at least during development cycles and
+ report any issues with the DNSSEC logic upstream. We are very
+ interested in collecting feedback about the DNSSEC validator and its
+ limitations in the wild. Note however, that DNSSEC support is
+ probably nothing downstreams should turn on in stable distros just
+ yet, as it might create incompabilities with a few DNS servers and
+ networks. We tried hard to make sure we downgrade to non-DNSSEC mode
+ automatically whenever we detect such incompatible setups, but there
+ might be systems we do not cover yet. Hence: please help us testing
+ the DNSSEC code, leave this on where you can, report back, but then
+ again don't consider turning this on in your stable, LTS or
+ production release just yet.
+
* Testing tool /usr/lib/systemd/systemd-activate is renamed to
systemd-socket-activate and installed into /usr/bin. It is now fully
supported.
diff --git a/configure.ac b/configure.ac
index b42f64dde0..f51533c2b3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -295,10 +295,8 @@ CAP_LIBS="$LIBS"
LIBS="$save_LIBS"
AC_SUBST(CAP_LIBS)
-AC_CHECK_FUNCS([memfd_create])
AC_CHECK_FUNCS([__secure_getenv secure_getenv])
-AC_CHECK_DECLS([gettid, pivot_root, name_to_handle_at, setns, getrandom, renameat2,
- kcmp, keyctl, key_serial_t, char16_t, char32_t, LO_FLAGS_PARTSCAN],
+AC_CHECK_DECLS([memfd_create, gettid, pivot_root, name_to_handle_at, setns, getrandom, renameat2, kcmp, keyctl, LO_FLAGS_PARTSCAN],
[], [], [[
#include <sys/types.h>
#include <unistd.h>
@@ -309,6 +307,11 @@ AC_CHECK_DECLS([gettid, pivot_root, name_to_handle_at, setns, getrandom, renamea
#include <linux/random.h>
]])
+AC_CHECK_TYPES([char16_t, char32_t, key_serial_t],
+ [], [], [[
+#include <uchar.h>
+]])
+
AC_CHECK_DECLS([IFLA_INET6_ADDR_GEN_MODE,
IFLA_MACVLAN_FLAGS,
IFLA_IPVLAN_MODE,
@@ -1136,6 +1139,20 @@ AC_ARG_WITH(dns-servers,
AC_DEFINE_UNQUOTED(DNS_SERVERS, ["$DNS_SERVERS"], [Default DNS Servers])
AC_SUBST(DNS_SERVERS)
+AC_ARG_WITH(default-dnssec,
+ AS_HELP_STRING([--with-default-dnssec=MODE],
+ [Default DNSSEC mode, defaults to "allow-downgrade"]),
+ [DEFAULT_DNSSEC_MODE="$withval"],
+ [DEFAULT_DNSSEC_MODE="allow-downgrade"])
+
+AS_CASE("x${DEFAULT_DNSSEC_MODE}",
+ [xno], [mode=DNSSEC_NO],
+ [xyes], [mode=DNSSEC_YES],
+ [xallow-downgrade], [mode=DNSSEC_ALLOW_DOWNGRADE],
+ AC_MSG_ERROR(Bad DNSSEC mode ${DEFAULT_DNSSEC_MODE}))
+AC_DEFINE_UNQUOTED(DEFAULT_DNSSEC_MODE, [$mode], [Default DNSSEC mode])
+AC_SUBST(DEFAULT_DNSSEC_MODE)
+
# ------------------------------------------------------------------------------
have_networkd=no
AC_ARG_ENABLE(networkd, AS_HELP_STRING([--disable-networkd], [disable networkd]))
@@ -1567,12 +1584,13 @@ AC_MSG_RESULT([
hostnamed: ${have_hostnamed}
timedated: ${have_timedated}
timesyncd: ${have_timesyncd}
- default NTP servers: ${NTP_SERVERS}
+ Default NTP servers: ${NTP_SERVERS}
time epoch: ${TIME_EPOCH}
localed: ${have_localed}
networkd: ${have_networkd}
resolved: ${have_resolved}
- default DNS servers: ${DNS_SERVERS}
+ Default DNS servers: ${DNS_SERVERS}
+ Default DNSSEC mode: ${DEFAULT_DNSSEC_MODE}
coredump: ${have_coredump}
polkit: ${have_polkit}
efi: ${have_efi}
diff --git a/man/systemd-resolve.xml b/man/systemd-resolve.xml
index 802d9cbbe6..c288fd974e 100644
--- a/man/systemd-resolve.xml
+++ b/man/systemd-resolve.xml
@@ -65,7 +65,7 @@
<command>systemd-resolve</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
<command> --type=<replaceable>TYPE</replaceable></command>
- <arg choice="plain" rep="repeat"><replaceable>RRDOMAIN</replaceable></arg>
+ <arg choice="plain" rep="repeat"><replaceable>DOMAIN</replaceable></arg>
</cmdsynopsis>
<cmdsynopsis>
@@ -233,6 +233,16 @@
</varlistentry>
<varlistentry>
+ <term><option>--raw</option><optional>=payload|packet</optional></term>
+
+ <listitem><para>Dump the answer as binary data. If there is no argument or if the argument is
+ <literal>payload</literal>, the payload of the packet is exported. If the argument is
+ <literal>packet</literal>, the whole packet is dumped in wire format, prefixed by
+ length specified as a little-endian 64-bit number. This format allows multiple packets
+ to be dumped and unambigously parsed.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>--legend=</option><replaceable>BOOL</replaceable></term>
<listitem><para>Takes a boolean parameter. If true (the default), column headers and meta information about the
@@ -263,27 +273,58 @@
<example>
<title>Retrieve the addresses of the <literal>www.0pointer.net</literal> domain</title>
- <programlisting>$ systemd-resolve www.0pointer.net</programlisting>
+ <programlisting>$ systemd-resolve www.0pointer.net
+www.0pointer.net: 2a01:238:43ed:c300:10c3:bcf3:3266:da74
+ 85.214.157.71
+
+-- Information acquired via protocol DNS in 611.6ms.
+-- Data is authenticated: no
+</programlisting>
</example>
<example>
<title>Retrieve the domain of the <literal>85.214.157.71</literal> IP address</title>
- <programlisting>$ systemd-resolve 85.214.157.71</programlisting>
+ <programlisting>$ systemd-resolve 85.214.157.71
+85.214.157.71: gardel.0pointer.net
+
+-- Information acquired via protocol DNS in 1.2997s.
+-- Data is authenticated: no
+</programlisting>
</example>
<example>
<title>Retrieve the MX record of the <literal>0pointer.net</literal> domain</title>
- <programlisting>$ systemd-resolve -t MX 0pointer.net</programlisting>
+ <programlisting>$ systemd-resolve -t MX yahoo.com --legend=no
+yahoo.com. IN MX 1 mta7.am0.yahoodns.net
+yahoo.com. IN MX 1 mta6.am0.yahoodns.net
+yahoo.com. IN MX 1 mta5.am0.yahoodns.net
+</programlisting>
</example>
<example>
<title>Resolve an SRV service</title>
- <programlisting>$ systemd-resolve --service _xmpp-server._tcp gmail.com</programlisting>
+ <programlisting>$ systemd-resolve --service _xmpp-server._tcp gmail.com
+_xmpp-server._tcp/gmail.com: alt1.xmpp-server.l.google.com:5269 [priority=20, weight=0]
+ 173.194.210.125
+ alt4.xmpp-server.l.google.com:5269 [priority=20, weight=0]
+ 173.194.65.125
+ ...
+</programlisting>
</example>
+ <example>
+ <title>Retrieve a PGP key</title>
+
+ <programlisting>$ systemd-resolve --openpgp zbyszek@fedoraproject.org
+d08ee310438ca124a6149ea5cc21b6313b390dce485576eff96f8722._openpgpkey.fedoraproject.org. IN OPENPGPKEY
+ mQINBFBHPMsBEACeInGYJCb+7TurKfb6wGyTottCDtiSJB310i37/6ZYoeIay/5soJjlMyf
+ MFQ9T2XNT/0LM6gTa0MpC1st9LnzYTMsT6tzRly1D1UbVI6xw0g0vE5y2Cjk3xUwAynCsSs
+ ...
+</programlisting>
+ </example>
</refsect1>
<refsect1>
diff --git a/src/basic/af-list.h b/src/basic/af-list.h
index 135248dc64..6a4cc03839 100644
--- a/src/basic/af-list.h
+++ b/src/basic/af-list.h
@@ -19,7 +19,23 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "string-util.h"
+
const char *af_to_name(int id);
int af_from_name(const char *name);
+static inline const char* af_to_name_short(int id) {
+ const char *f;
+
+ if (id == AF_UNSPEC)
+ return "*";
+
+ f = af_to_name(id);
+ if (!f)
+ return "unknown";
+
+ assert(startswith(f, "AF_"));
+ return f + 3;
+}
+
int af_max(void);
diff --git a/src/basic/missing.h b/src/basic/missing.h
index 4d3764c022..f3d32362bd 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -167,7 +167,7 @@ static inline int pivot_root(const char *new_root, const char *put_old) {
# endif
#endif
-#ifndef HAVE_MEMFD_CREATE
+#if !HAVE_DECL_MEMFD_CREATE
static inline int memfd_create(const char *name, unsigned int flags) {
return syscall(__NR_memfd_create, name, flags);
}
@@ -1089,7 +1089,7 @@ static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, uns
#define INPUT_PROP_ACCELEROMETER 0x06
#endif
-#if !HAVE_DECL_KEY_SERIAL_T
+#ifndef HAVE_KEY_SERIAL_T
typedef int32_t key_serial_t;
#endif
@@ -1160,11 +1160,11 @@ static inline key_serial_t request_key(const char *type, const char *description
#ifndef IF_OPER_UP
#define IF_OPER_UP 6
-#ifndef HAVE_DECL_CHAR32_T
+#ifndef HAVE_CHAR32_T
#define char32_t uint32_t
#endif
-#ifndef HAVE_DECL_CHAR16_T
+#ifndef HAVE_CHAR16_T
#define char16_t uint16_t
#endif
diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c
index 49e5f5b125..58512686e3 100644
--- a/src/basic/socket-util.c
+++ b/src/basic/socket-util.c
@@ -936,3 +936,37 @@ int receive_one_fd(int transport_fd, int flags) {
return *(int*) CMSG_DATA(found);
}
+
+ssize_t next_datagram_size_fd(int fd) {
+ ssize_t l;
+ int k;
+
+ /* This is a bit like FIONREAD/SIOCINQ, however a bit more powerful. The difference being: recv(MSG_PEEK) will
+ * actually cause the next datagram in the queue to be validated regarding checksums, which FIONREAD dosn't
+ * do. This difference is actually of major importance as we need to be sure that the size returned here
+ * actually matches what we will read with recvmsg() next, as otherwise we might end up allocating a buffer of
+ * the wrong size. */
+
+ l = recv(fd, NULL, 0, MSG_PEEK|MSG_TRUNC);
+ if (l < 0) {
+ if (errno == EOPNOTSUPP)
+ goto fallback;
+
+ return -errno;
+ }
+ if (l == 0)
+ goto fallback;
+
+ return l;
+
+fallback:
+ k = 0;
+
+ /* Some sockets (AF_PACKET) do not support null-sized recv() with MSG_TRUNC set, let's fall back to FIONREAD
+ * for them. Checksums don't matter for raw sockets anyway, hence this should be fine. */
+
+ if (ioctl(fd, FIONREAD, &k) < 0)
+ return -errno;
+
+ return (ssize_t) k;
+}
diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h
index 92edc1dc22..d17a2f35f8 100644
--- a/src/basic/socket-util.h
+++ b/src/basic/socket-util.h
@@ -133,5 +133,7 @@ int send_one_fd_sa(int transport_fd,
#define send_one_fd(transport_fd, fd, flags) send_one_fd_sa(transport_fd, fd, NULL, 0, flags)
int receive_one_fd(int transport_fd, int flags);
+ssize_t next_datagram_size_fd(int fd);
+
#define CMSG_FOREACH(cmsg, mh) \
for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index 510f018d9b..0b4f5ab5b9 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -449,7 +449,7 @@ int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
assert(t);
if (sscanf(value, "%llu %llu", &a, &b) != 2) {
- log_debug("Failed to parse finish timestamp value %s.", value);
+ log_debug("Failed to parse dual timestamp value \"%s\": %m", value);
return -EINVAL;
}
@@ -459,6 +459,18 @@ int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
return 0;
}
+int timestamp_deserialize(const char *value, usec_t *timestamp) {
+ int r;
+
+ assert(value);
+
+ r = safe_atou64(value, timestamp);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to parse timestamp value \"%s\": %m", value);
+
+ return r;
+}
+
int parse_timestamp(const char *t, usec_t *usec) {
static const struct {
const char *name;
diff --git a/src/basic/time-util.h b/src/basic/time-util.h
index 9894e626c5..77e3cd08d4 100644
--- a/src/basic/time-util.h
+++ b/src/basic/time-util.h
@@ -99,6 +99,7 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy);
void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t);
int dual_timestamp_deserialize(const char *value, dual_timestamp *t);
+int timestamp_deserialize(const char *value, usec_t *timestamp);
int parse_timestamp(const char *t, usec_t *usec);
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index b31bf83f47..4a65d174b8 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -574,9 +574,7 @@ int config_parse_exec(
void *data,
void *userdata) {
- _cleanup_free_ char *cmd = NULL;
ExecCommand **e = data;
- Unit *u = userdata;
const char *p;
bool semicolon;
int r;
@@ -585,7 +583,6 @@ int config_parse_exec(
assert(lvalue);
assert(rvalue);
assert(e);
- assert(u);
e += ltype;
rvalue += strspn(rvalue, WHITESPACE);
@@ -596,13 +593,7 @@ int config_parse_exec(
return 0;
}
- r = unit_full_printf(u, rvalue, &cmd);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
- return 0;
- }
-
- p = cmd;
+ p = rvalue;
do {
_cleanup_free_ char *path = NULL, *firstword = NULL;
bool separate_argv0 = false, ignore = false;
diff --git a/src/core/main.c b/src/core/main.c
index e2088574c0..c725a686f1 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -1313,7 +1313,6 @@ int main(int argc, char *argv[]) {
/* This is compatibility support for SysV, where
* calling init as a user is identical to telinit. */
- errno = -ENOENT;
execv(SYSTEMCTL_BINARY_PATH, argv);
log_error_errno(errno, "Failed to exec " SYSTEMCTL_BINARY_PATH ": %m");
return 1;
diff --git a/src/core/timer.c b/src/core/timer.c
index 6f3e6a8db3..3d0bae16e5 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -334,7 +334,7 @@ static void add_random(Timer *t, usec_t *v) {
usec_t add;
assert(t);
- assert(*v);
+ assert(v);
if (t->random_usec == 0)
return;
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index cad1a52c09..62099dd3f4 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -958,7 +958,7 @@ static int client_initialize_time_events(sd_dhcp_client *client) {
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
if (client->start_delay) {
- sd_event_now(client->event, clock_boottime_or_monotonic(), &usec);
+ assert_se(sd_event_now(client->event, clock_boottime_or_monotonic(), &usec) >= 0);
usec += client->start_delay;
}
@@ -1525,20 +1525,17 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
uint32_t revents, void *userdata) {
sd_dhcp_client *client = userdata;
_cleanup_free_ DHCPMessage *message = NULL;
- int buflen = 0, len, r;
const struct ether_addr zero_mac = { { 0, 0, 0, 0, 0, 0 } };
const struct ether_addr *expected_chaddr = NULL;
uint8_t expected_hlen = 0;
+ ssize_t len, buflen;
assert(s);
assert(client);
- r = ioctl(fd, FIONREAD, &buflen);
- if (r < 0)
- return -errno;
- else if (buflen < 0)
- /* this can't be right */
- return -EIO;
+ buflen = next_datagram_size_fd(fd);
+ if (buflen < 0)
+ return buflen;
message = malloc0(buflen);
if (!message)
@@ -1616,17 +1613,15 @@ static int client_receive_message_raw(sd_event_source *s, int fd,
};
struct cmsghdr *cmsg;
bool checksum = true;
- int buflen = 0, len, r;
+ ssize_t buflen, len;
+ int r;
assert(s);
assert(client);
- r = ioctl(fd, FIONREAD, &buflen);
- if (r < 0)
- return -errno;
- else if (buflen < 0)
- /* this can't be right */
- return -EIO;
+ buflen = next_datagram_size_fd(fd);
+ if (buflen < 0)
+ return buflen;
packet = malloc0(buflen);
if (!packet)
diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c
index ad3a37b722..54ff1a3f28 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -955,14 +955,13 @@ static int server_receive_message(sd_event_source *s, int fd,
.msg_controllen = sizeof(cmsgbuf),
};
struct cmsghdr *cmsg;
- int buflen = 0, len;
+ ssize_t buflen, len;
assert(server);
- if (ioctl(fd, FIONREAD, &buflen) < 0)
- return -errno;
- else if (buflen < 0)
- return -EIO;
+ buflen = next_datagram_size_fd(fd);
+ if (buflen < 0)
+ return buflen;
message = malloc(buflen);
if (!message)
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index 5b6b9cbcac..7d56d4cc60 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -33,6 +33,7 @@
#include "in-addr-util.h"
#include "network-internal.h"
#include "random-util.h"
+#include "socket-util.h"
#include "string-table.h"
#include "util.h"
@@ -891,18 +892,16 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
sd_dhcp6_client *client = userdata;
DHCP6_CLIENT_DONT_DESTROY(client);
_cleanup_free_ DHCP6Message *message = NULL;
- int r, buflen, len;
+ ssize_t buflen, len;
+ int r = 0;
assert(s);
assert(client);
assert(client->event);
- r = ioctl(fd, FIONREAD, &buflen);
- if (r < 0)
- return -errno;
- else if (buflen < 0)
- /* This really should not happen */
- return -EIO;
+ buflen = next_datagram_size_fd(fd);
+ if (buflen < 0)
+ return buflen;
message = malloc(buflen);
if (!message)
diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c
index 519d2aa36b..bae6a49fe6 100644
--- a/src/libsystemd-network/sd-ndisc.c
+++ b/src/libsystemd-network/sd-ndisc.c
@@ -491,19 +491,16 @@ static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r
struct cmsghdr *cmsg;
struct in6_addr *gw;
unsigned lifetime;
- ssize_t len;
- int r, pref, stateful, buflen = 0;
+ ssize_t len, buflen;
+ int r, pref, stateful;
assert(s);
assert(nd);
assert(nd->event);
- r = ioctl(fd, FIONREAD, &buflen);
- if (r < 0)
- return -errno;
- else if (buflen < 0)
- /* This really should not happen */
- return -EIO;
+ buflen = next_datagram_size_fd(fd);
+ if (buflen < 0)
+ return buflen;
iov.iov_len = buflen;
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index 417b7f5d98..e088225beb 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -446,17 +446,10 @@ int session_load(Session *s) {
safe_close(fd);
}
- if (realtime) {
- unsigned long long l;
- if (sscanf(realtime, "%llu", &l) > 0)
- s->timestamp.realtime = l;
- }
-
- if (monotonic) {
- unsigned long long l;
- if (sscanf(monotonic, "%llu", &l) > 0)
- s->timestamp.monotonic = l;
- }
+ if (realtime)
+ timestamp_deserialize(realtime, &s->timestamp.realtime);
+ if (monotonic)
+ timestamp_deserialize(monotonic, &s->timestamp.monotonic);
if (controller) {
if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0)
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
index 6b9c69cc45..a826321bf0 100644
--- a/src/login/logind-user.c
+++ b/src/login/logind-user.c
@@ -321,17 +321,10 @@ int user_load(User *u) {
if (s && s->display && display_is_local(s->display))
u->display = s;
- if (realtime) {
- unsigned long long l;
- if (sscanf(realtime, "%llu", &l) > 0)
- u->timestamp.realtime = l;
- }
-
- if (monotonic) {
- unsigned long long l;
- if (sscanf(monotonic, "%llu", &l) > 0)
- u->timestamp.monotonic = l;
- }
+ if (realtime)
+ timestamp_deserialize(realtime, &u->timestamp.realtime);
+ if (monotonic)
+ timestamp_deserialize(monotonic, &u->timestamp.monotonic);
return r;
}
diff --git a/src/machine/machine.c b/src/machine/machine.c
index 406d5a4b85..7a7a1bb42b 100644
--- a/src/machine/machine.c
+++ b/src/machine/machine.c
@@ -299,17 +299,10 @@ int machine_load(Machine *m) {
m->class = c;
}
- if (realtime) {
- unsigned long long l;
- if (sscanf(realtime, "%llu", &l) > 0)
- m->timestamp.realtime = l;
- }
-
- if (monotonic) {
- unsigned long long l;
- if (sscanf(monotonic, "%llu", &l) > 0)
- m->timestamp.monotonic = l;
- }
+ if (realtime)
+ timestamp_deserialize(realtime, &m->timestamp.realtime);
+ if (monotonic)
+ timestamp_deserialize(monotonic, &m->timestamp.monotonic);
if (netif) {
size_t allocated = 0, nr = 0;
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index b527191a5a..b8cb7f875d 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -1091,22 +1091,19 @@ static bool manager_check_idle(void *userdata) {
assert(m);
+ /* Check whether we are idle now. The only case when we decide to be idle is when there's only a loopback
+ * device around, for which we have no configuration, and which already left the PENDING state. In all other
+ * cases we are not idle. */
+
HASHMAP_FOREACH(link, m->links, i) {
- /* we are not woken on udev activity, so let's just wait for the
- * pending udev event */
+ /* We are not woken on udev activity, so let's just wait for the pending udev event */
if (link->state == LINK_STATE_PENDING)
return false;
- if (!link->network)
- continue;
+ if ((link->flags & IFF_LOOPBACK) == 0)
+ return false;
- /* we are not woken on netork activity, so let's stay around */
- if (link_lldp_enabled(link) ||
- link_ipv4ll_enabled(link) ||
- link_dhcp4_server_enabled(link) ||
- link_dhcp4_enabled(link) ||
- link_dhcp6_enabled(link) ||
- link_ipv6_accept_ra_enabled(link))
+ if (link->network)
return false;
}
diff --git a/src/resolve/dns-type.c b/src/resolve/dns-type.c
index b2f479cae5..78d9d5733f 100644
--- a/src/resolve/dns-type.c
+++ b/src/resolve/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/resolve/dns-type.h b/src/resolve/dns-type.h
index f18ac6eef3..db9666b970 100644
--- a/src/resolve/dns-type.h
+++ b/src/resolve/dns-type.h
@@ -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 */
diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c
index 9aade8e490..a519074278 100644
--- a/src/resolve/resolve-tool.c
+++ b/src/resolve/resolve-tool.c
@@ -44,6 +44,14 @@ static uint16_t arg_class = 0;
static bool arg_legend = true;
static uint64_t arg_flags = 0;
+typedef enum RawType {
+ RAW_NONE,
+ RAW_PAYLOAD,
+ RAW_PACKET,
+} RawType;
+
+static RawType arg_raw = RAW_NONE;
+
static enum {
MODE_RESOLVE_HOST,
MODE_RESOLVE_RECORD,
@@ -331,6 +339,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;
@@ -339,6 +391,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);
@@ -376,9 +429,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;
@@ -398,29 +448,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");
-
- s = dns_resource_record_to_string(rr);
- if (!s)
- return log_oom();
+ fwrite(&u64, sizeof(u64), 1, stdout);
+ fwrite(d, 1, l, stdout);
+ } else {
+ r = output_rr_packet(d, l, ifindex);
+ if (r < 0)
+ return r;
+ }
- ifname[0] = 0;
- if (ifindex > 0 && !if_indextoname(ifindex, ifname))
- log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
+ if (dns_type_needs_authentication(t))
+ needs_authentication = true;
- printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname);
n++;
}
if (r < 0)
@@ -441,6 +482,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;
}
@@ -959,27 +1012,33 @@ 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"
- " --openpgp Query OpenPGP public key\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"
+ " --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[]) {
@@ -991,6 +1050,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_SERVICE_ADDRESS,
ARG_SERVICE_TXT,
ARG_OPENPGP,
+ ARG_RAW,
ARG_SEARCH,
ARG_STATISTICS,
ARG_RESET_STATISTICS,
@@ -1009,6 +1069,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
{ "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
{ "openpgp", no_argument, NULL, ARG_OPENPGP },
+ { "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 },
@@ -1122,6 +1183,24 @@ static int parse_argv(int argc, char *argv[]) {
arg_mode = MODE_RESOLVE_OPENPGP;
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)
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c
index 6f08c43327..a138be2421 100644
--- a/src/resolve/resolved-bus.c
+++ b/src/resolve/resolved-bus.c
@@ -140,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;
@@ -199,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;
@@ -395,13 +402,19 @@ 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;
@@ -671,6 +684,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;
@@ -727,10 +741,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;
@@ -776,9 +794,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;
@@ -933,7 +959,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;
diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c
index 7eb303ab95..c08f7a7edd 100644
--- a/src/resolve/resolved-dns-answer.c
+++ b/src/resolve/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)
@@ -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/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c
index 9bcc71724e..4b7672fbbf 100644
--- a/src/resolve/resolved-dns-cache.c
+++ b/src/resolve/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(i->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(i->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;
}
@@ -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++;
@@ -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/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c
index 7098265929..0af7551425 100644
--- a/src/resolve/resolved-dns-dnssec.c
+++ b/src/resolve/resolved-dns-dnssec.c
@@ -467,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)
@@ -651,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)) {
@@ -851,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) {
@@ -867,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 +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;
@@ -1120,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)
@@ -1272,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;
@@ -1353,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);
@@ -1362,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)
@@ -1382,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;
@@ -1405,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) {
@@ -1504,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) {
@@ -1516,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) {
@@ -1525,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) {
@@ -1604,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;
@@ -1643,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;
@@ -1662,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;
@@ -1685,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;
@@ -1706,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) {
@@ -1725,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;
@@ -1735,7 +1735,7 @@ static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name)
return r;
wc = strjoina("*.", common_suffix, NULL);
- return dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), wc, rr->nsec.next_domain_name);
+ 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) {
@@ -1750,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) {
@@ -1770,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) {
@@ -1900,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;
@@ -1943,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;
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index c2fc1d8b05..2e41dae656 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -577,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;
@@ -2130,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.");
diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c
index a378b2b7f7..a7496aa586 100644
--- a/src/resolve/resolved-dns-query.c
+++ b/src/resolve/resolved-dns-query.c
@@ -421,6 +421,7 @@ int dns_query_new(
DnsResourceKey *key;
bool good = false;
int r;
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
assert(m);
@@ -471,31 +472,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);
diff --git a/src/resolve/resolved-dns-question.c b/src/resolve/resolved-dns-question.c
index 8e452e79a4..c8b502d1cd 100644
--- a/src/resolve/resolved-dns-question.c
+++ b/src/resolve/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/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index 6397005a68..d0a86ef206 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -66,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)
@@ -96,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;
@@ -158,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);
@@ -172,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;
@@ -204,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;
@@ -231,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;
@@ -243,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;
@@ -268,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) {
@@ -276,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);
}
@@ -285,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;
@@ -307,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) {
@@ -830,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);
@@ -839,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) {
@@ -1204,6 +1209,44 @@ 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_SSHFP:
+ case DNS_TYPE_DNSKEY:
+ case DNS_TYPE_RRSIG:
+ case DNS_TYPE_NSEC:
+ case DNS_TYPE_NSEC3:
+ return -EINVAL;
+
+ 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 = {
@@ -1261,7 +1304,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;
@@ -1284,7 +1327,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;
@@ -1324,7 +1367,7 @@ 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;
diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h
index 23749790b4..646e34598d 100644
--- a/src/resolve/resolved-dns-rr.h
+++ b/src/resolve/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 directy, use dns_resource_key_name()! */
};
/* Creates a temporary resource key. This is only useful to quickly
@@ -260,16 +261,6 @@ struct DnsResourceRecord {
};
};
-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;
@@ -297,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) {
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index a406872a38..66e4585c18 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/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/resolve/resolved-dns-synthesize.c b/src/resolve/resolved-dns-synthesize.c
index f4a43dee8c..e3003411f7 100644
--- a/src/resolve/resolved-dns-synthesize.c
+++ b/src/resolve/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/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 060c430f3a..3443f71976 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -113,7 +113,6 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) {
dns_answer_unref(t->validated_keys);
dns_resource_key_unref(t->key);
- free(t->key_string);
free(t);
return NULL;
@@ -238,6 +237,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);
@@ -250,10 +250,10 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) {
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),
+ af_to_name_short(t->scope->family),
pretty);
/* RFC 4795, Section 4.1 says that the peer with the
@@ -286,20 +286,24 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
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 +316,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");
@@ -522,7 +526,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 +1213,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 +1241,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;
@@ -1425,6 +1428,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 +1438,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 +1498,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 +1606,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;
}
}
@@ -1708,7 +1715,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)
@@ -1816,7 +1823,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 +1840,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 +1858,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 +1868,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 +1887,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 +1929,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 +1976,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 +1987,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 +2018,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;
@@ -2029,7 +2041,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
if (r > 0) {
const char *name;
- 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
@@ -2042,11 +2054,13 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
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));
+ 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
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));
+ 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;
@@ -2118,7 +2132,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 +2158,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 +2201,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 +2215,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 +2240,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 +2287,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 +2302,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)
@@ -2309,6 +2323,7 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) {
const char *name;
Iterator i;
int r;
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
assert(t);
@@ -2321,7 +2336,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,11 +2350,12 @@ 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)) {
@@ -2368,7 +2384,7 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) {
if (dt->key->type != DNS_TYPE_SOA)
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 +2406,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 +2429,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 +2446,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 +2476,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 +2557,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;
- log_debug("Looking at %s: %s", strna(dns_resource_record_to_string(rr)), dnssec_result_to_string(result));
+ manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key);
+ return 1;
+ }
- if (result == DNSSEC_VALIDATED) {
+ 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 (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. */
+ dns_server_packet_rrsig_missing(t->server, t->current_feature_level);
- r = dns_answer_copy_by_key(&t->validated_keys, t->answer, rr->key, DNS_ANSWER_AUTHENTICATED);
- if (r < 0)
- return r;
+ if (t->scope->dnssec_mode == DNSSEC_ALLOW_DOWNGRADE) {
+
+ /* 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 +2941,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 +2951,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 +2961,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 +3006,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/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h
index 4617194711..491c62d772 100644
--- a/src/resolve/resolved-dns-transaction.h
+++ b/src/resolve/resolved-dns-transaction.h
@@ -64,7 +64,6 @@ struct DnsTransaction {
DnsScope *scope;
DnsResourceKey *key;
- char *key_string;
DnsTransactionState state;
@@ -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/resolve/resolved-dns-trust-anchor.c b/src/resolve/resolved-dns-trust-anchor.c
index a75337eb6a..77370e7dd5 100644
--- a/src/resolve/resolved-dns-trust-anchor.c
+++ b/src/resolve/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/resolve/resolved-dns-zone.c b/src/resolve/resolved-dns-zone.c
index f52383cfd1..03813da6a2 100644
--- a/src/resolve/resolved-dns-zone.c
+++ b/src/resolve/resolved-dns-zone.c
@@ -68,12 +68,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 +147,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 +169,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;
@@ -303,7 +303,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 +339,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 +370,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 +393,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 +418,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 +430,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 +482,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 +562,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 +593,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/resolve/resolved-etc-hosts.c b/src/resolve/resolved-etc-hosts.c
index ee82c96822..6ccbdca20e 100644
--- a/src/resolve/resolved-etc-hosts.c
+++ b/src/resolve/resolved-etc-hosts.c
@@ -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/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index bf5efe4cfa..b3ff46b5da 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/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;
@@ -617,18 +617,16 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
struct msghdr mh = {};
struct cmsghdr *cmsg;
struct iovec iov;
- int ms = 0, r;
- ssize_t l;
+ ssize_t ms, l;
+ int r;
assert(m);
assert(fd >= 0);
assert(ret);
- r = ioctl(fd, FIONREAD, &ms);
- if (r < 0)
- return -errno;
+ ms = next_datagram_size_fd(fd);
if (ms < 0)
- return -EIO;
+ return ms;
r = dns_packet_new(&p, protocol, ms);
if (r < 0)
@@ -1215,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;
-
- (void) dns_resource_key_to_string(key, &s);
+ char s[DNS_RESOURCE_KEY_STRING_MAX];
- 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/resolve/resolved-mdns.c b/src/resolve/resolved-mdns.c
index bc8b8b809b..b13b1d0144 100644
--- a/src/resolve/resolved-mdns.c
+++ b/src/resolve/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/resolve/resolved.conf.in b/src/resolve/resolved.conf.in
index efc9c6733a..a288588924 100644
--- a/src/resolve/resolved.conf.in
+++ b/src/resolve/resolved.conf.in
@@ -16,4 +16,4 @@
#FallbackDNS=@DNS_SERVERS@
#Domains=
#LLMNR=yes
-#DNSSEC=no
+#DNSSEC=@DEFAULT_DNSSEC_MODE@
diff --git a/src/resolve/test-resolve-tables.c b/src/resolve/test-resolve-tables.c
index 63660afc87..2d615130e1 100644
--- a/src/resolve/test-resolve-tables.c
+++ b/src/resolve/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;
}
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index 38557f0b8d..c87eaf63d8 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -2028,20 +2028,21 @@ static const struct {
{ "start-limit", "start of the service was attempted too often" }
};
-static void log_job_error_with_service_result(const char* service, const char *result, const char *extra_args) {
- _cleanup_free_ char *service_shell_quoted = NULL, *systemctl_extra_args = NULL;
+static void log_job_error_with_service_result(const char* service, const char *result, const char* const* extra_args) {
+ _cleanup_free_ char *service_shell_quoted = NULL;
+ const char *systemctl = "systemctl", *journalctl = "journalct";
assert(service);
service_shell_quoted = shell_maybe_quote(service);
- systemctl_extra_args = strjoin("systemctl ", extra_args, " ", NULL);
- if (!systemctl_extra_args) {
- log_oom();
- return;
- }
+ if (extra_args && extra_args[1]) {
+ _cleanup_free_ char *t;
- systemctl_extra_args = strstrip(systemctl_extra_args);
+ t = strv_join((char**) extra_args, " ");
+ systemctl = strjoina("systemctl ", t ?: "<args>", NULL);
+ journalctl = strjoina("journalctl ", t ?: "<args>", NULL);
+ }
if (!isempty(result)) {
unsigned i;
@@ -2051,30 +2052,34 @@ static void log_job_error_with_service_result(const char* service, const char *r
break;
if (i < ELEMENTSOF(explanations)) {
- log_error("Job for %s failed because %s. See \"%s status %s\" and \"journalctl -xe\" for details.\n",
+ log_error("Job for %s failed because %s.\n"
+ "See \"%s status %s\" and \"%s -xe\" for details.\n",
service,
explanations[i].explanation,
- systemctl_extra_args,
- strna(service_shell_quoted));
-
+ systemctl,
+ service_shell_quoted ?: "<service>",
+ journalctl);
goto finish;
}
}
- log_error("Job for %s failed. See \"%s status %s\" and \"journalctl -xe\" for details.\n",
+ log_error("Job for %s failed.\n"
+ "See \"%s status %s\" and \"%s -xe\" for details.\n",
service,
- systemctl_extra_args,
- strna(service_shell_quoted));
+ systemctl,
+ service_shell_quoted ?: "<service>",
+ journalctl);
finish:
/* For some results maybe additional explanation is required */
if (streq_ptr(result, "start-limit"))
- log_info("To force a start use \"%1$s reset-failed %2$s\" followed by \"%1$s start %2$s\" again.",
- systemctl_extra_args,
- strna(service_shell_quoted));
+ log_info("To force a start use \"%1$s reset-failed %2$s\"\n"
+ "followed by \"%1$s start %2$s\" again.",
+ systemctl,
+ service_shell_quoted ?: "<service>");
}
-static int check_wait_response(BusWaitForJobs *d, bool quiet, const char *extra_args) {
+static int check_wait_response(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
int r = 0;
assert(d->result);
@@ -2125,7 +2130,7 @@ static int check_wait_response(BusWaitForJobs *d, bool quiet, const char *extra_
return r;
}
-int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char *extra_args) {
+int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
int r = 0;
assert(d);
diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h
index 204da55682..fcda1b2c6c 100644
--- a/src/shared/bus-util.h
+++ b/src/shared/bus-util.h
@@ -180,7 +180,7 @@ typedef struct BusWaitForJobs BusWaitForJobs;
int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret);
void bus_wait_for_jobs_free(BusWaitForJobs *d);
int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path);
-int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char *extra_args);
+int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args);
int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet);
DEFINE_TRIVIAL_CLEANUP_FUNC(BusWaitForJobs*, bus_wait_for_jobs_free);
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 908ccabf8a..c75d12c136 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -2778,9 +2778,22 @@ static int start_unit(int argc, char *argv[], void *userdata) {
}
if (!arg_no_block) {
- int q;
+ int q, arg_count = 0;
+ const char* extra_args[4] = {};
+
+ if (arg_scope != UNIT_FILE_SYSTEM)
+ extra_args[arg_count++] = "--user";
+
+ assert(IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_REMOTE, BUS_TRANSPORT_MACHINE));
+ if (arg_transport == BUS_TRANSPORT_REMOTE) {
+ extra_args[arg_count++] = "-H";
+ extra_args[arg_count++] = arg_host;
+ } else if (arg_transport == BUS_TRANSPORT_MACHINE) {
+ extra_args[arg_count++] = "-M";
+ extra_args[arg_count++] = arg_host;
+ }
- q = bus_wait_for_jobs(w, arg_quiet, arg_scope != UNIT_FILE_SYSTEM ? "--user" : NULL);
+ q = bus_wait_for_jobs(w, arg_quiet, extra_args);
if (q < 0)
return q;
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index 92857cb5e2..d021be4671 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -263,6 +263,10 @@ static void test_exec_ioschedulingclass(Manager *m) {
test(m, "exec-ioschedulingclass-best-effort.service", 0, CLD_EXITED);
}
+static void test_exec_spec_interpolation(Manager *m) {
+ test(m, "exec-spec-interpolation.service", 0, CLD_EXITED);
+}
+
int main(int argc, char *argv[]) {
test_function_t tests[] = {
test_exec_workingdirectory,
@@ -284,6 +288,7 @@ int main(int argc, char *argv[]) {
test_exec_capabilityambientset,
test_exec_oomscoreadjust,
test_exec_ioschedulingclass,
+ test_exec_spec_interpolation,
NULL,
};
test_function_t *test = NULL;
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 2c1c4a967b..bb92f16352 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -1715,7 +1715,7 @@ int main(int argc, char *argv[]) {
by PID1. otherwise we are not guaranteed to have a dedicated cgroup */
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &cgroup);
if (r < 0) {
- if (r == -ENOENT || r == -ENOEXEC)
+ if (r == -ENOENT || r == -ENOMEDIUM)
log_debug_errno(r, "did not find dedicated cgroup: %m");
else
log_warning_errno(r, "failed to get cgroup: %m");
diff --git a/test/test-execute/exec-spec-interpolation.service b/test/test-execute/exec-spec-interpolation.service
new file mode 100644
index 0000000000..3e62662aa9
--- /dev/null
+++ b/test/test-execute/exec-spec-interpolation.service
@@ -0,0 +1,6 @@
+[Unit]
+Description=https://github.com/systemd/systemd/issues/2637
+
+[Service]
+Type=oneshot
+ExecStart=/bin/sh -x -c "perl -e 'exit(!(qq{%%U} eq qq{\\x25U}))'"