summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/busctl.xml2
-rw-r--r--man/machinectl.xml2
-rw-r--r--man/sd-event.xml2
-rw-r--r--man/sd_bus_creds_get_pid.xml2
-rw-r--r--man/sd_event_add_child.xml2
-rw-r--r--man/sd_event_add_defer.xml2
-rw-r--r--man/sd_event_add_io.xml6
-rw-r--r--man/sd_event_add_signal.xml2
-rw-r--r--man/sd_event_add_time.xml4
-rw-r--r--man/sd_event_exit.xml2
-rw-r--r--man/sd_event_now.xml2
-rw-r--r--man/sd_event_source_set_enabled.xml2
-rw-r--r--man/sd_event_source_set_prepare.xml2
-rw-r--r--man/sd_event_source_set_priority.xml2
-rw-r--r--man/sd_event_wait.xml4
-rw-r--r--man/sd_notify.xml2
-rw-r--r--man/sd_seat_get_active.xml2
-rw-r--r--man/systemctl.xml2
-rw-r--r--man/systemd-resolved.service.xml2
-rw-r--r--man/systemd.network.xml4
-rw-r--r--man/systemd.special.xml2
-rw-r--r--man/systemd.timer.xml2
-rw-r--r--man/systemd.unit.xml2
-rw-r--r--man/tmpfiles.d.xml2
-rw-r--r--src/resolve-host/resolve-host.c8
-rw-r--r--src/resolve/resolved-dns-cache.c49
-rw-r--r--src/resolve/resolved-dns-dnssec.c382
-rw-r--r--src/resolve/resolved-dns-rr.c1
-rw-r--r--src/resolve/resolved-dns-rr.h4
-rw-r--r--src/resolve/resolved-dns-transaction.c15
-rw-r--r--src/shared/dns-domain.c14
-rw-r--r--src/test/test-dns-domain.c6
32 files changed, 388 insertions, 149 deletions
diff --git a/man/busctl.xml b/man/busctl.xml
index d8c1085021..26d778d4dd 100644
--- a/man/busctl.xml
+++ b/man/busctl.xml
@@ -448,7 +448,7 @@ ARRAY "s" {
<example>
<title>Invoking a Method</title>
- <para>The following command invokes a the
+ <para>The following command invokes the
<literal>StartUnit</literal> method on the
<literal>org.freedesktop.systemd1.Manager</literal>
interface of the
diff --git a/man/machinectl.xml b/man/machinectl.xml
index a7288c249b..f9395f3d72 100644
--- a/man/machinectl.xml
+++ b/man/machinectl.xml
@@ -247,7 +247,7 @@
<literal>checksum</literal> is specified, the download is
checked for integrity after the transfer is complete, but no
signatures are verified. If <literal>signature</literal> is
- specified, the checksum is verified and the images's signature
+ specified, the checksum is verified and the image's signature
is checked against a local keyring of trustable vendors. It is
strongly recommended to set this option to
<literal>signature</literal> if the server and protocol
diff --git a/man/sd-event.xml b/man/sd-event.xml
index 47989f4421..fc615f0906 100644
--- a/man/sd-event.xml
+++ b/man/sd-event.xml
@@ -136,7 +136,7 @@
<listitem><para>Event sources may be assigned a 64bit priority
value, that controls the order in which event sources are
- dispatched if multiple are pending simultanously. See
+ dispatched if multiple are pending simultaneously. See
<citerefentry><refentrytitle>sd_event_source_set_priority</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
<listitem><para>The event loop may automatically send watchdog
diff --git a/man/sd_bus_creds_get_pid.xml b/man/sd_bus_creds_get_pid.xml
index aec12bda16..3bcda46656 100644
--- a/man/sd_bus_creds_get_pid.xml
+++ b/man/sd_bus_creds_get_pid.xml
@@ -470,7 +470,7 @@
modified by the caller.</para>
<para>All functions that take a <parameter>char***</parameter>
- parameter will store the answer there as an address of a an array
+ parameter will store the answer there as an address of an array
of strings. Each individual string is NUL-terminated, and the
array is NULL-terminated as a whole. It will be valid as long as
<parameter>c</parameter> remains valid, and should not be freed or
diff --git a/man/sd_event_add_child.xml b/man/sd_event_add_child.xml
index d4b180cf03..bc732db7fa 100644
--- a/man/sd_event_add_child.xml
+++ b/man/sd_event_add_child.xml
@@ -127,7 +127,7 @@
<constant>SD_EVENT_OFF</constant> with
<citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
- <para>If the the second parameter of
+ <para>If the second parameter of
<function>sd_event_add_child()</function> is passed as NULL no
reference to the event source object is returned. In this case the
event source is considered "floating", and will be destroyed
diff --git a/man/sd_event_add_defer.xml b/man/sd_event_add_defer.xml
index 6a13ede76e..d9ebd3b179 100644
--- a/man/sd_event_add_defer.xml
+++ b/man/sd_event_add_defer.xml
@@ -108,7 +108,7 @@
handler will be called once
(<constant>SD_EVENT_ONESHOT</constant>). Note that if the event
source is set to <constant>SD_EVENT_ON</constant> the event loop
- will never go to sleep again, but continously call the handler,
+ will never go to sleep again, but continuously call the handler,
possibly interleaved with other event sources.</para>
<para><function>sd_event_add_post()</function> adds a new event
diff --git a/man/sd_event_add_io.xml b/man/sd_event_add_io.xml
index 4cc0428e29..eeb406ba5b 100644
--- a/man/sd_event_add_io.xml
+++ b/man/sd_event_add_io.xml
@@ -141,14 +141,14 @@
<constant>EPOLLHUP</constant> set.</para>
<para>By default, the I/O event source will stay enabled
- continously (<constant>SD_EVENT_ON</constant>), but this may be
+ continuously (<constant>SD_EVENT_ON</constant>), but this may be
changed with
<citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
If the handler function returns a negative error code, it will be
disabled after the invocation, even if the
<constant>SD_EVENT_ON</constant> mode was requested before. Note
that an I/O event source set to <constant>SD_EVENT_ON</constant> will
- fire continously unless data is read or written to the file
+ fire continuously unless data is read or written to the file
descriptor in order to reset the mask of events seen.
</para>
@@ -169,7 +169,7 @@
<constant>SD_EVENT_OFF</constant> with
<citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
- <para>If the the second parameter of
+ <para>If the second parameter of
<function>sd_event_add_io()</function> is passed as NULL no
reference to the event source object is returned. In this case the
event source is considered "floating", and will be destroyed
diff --git a/man/sd_event_add_signal.xml b/man/sd_event_add_signal.xml
index b5312735d2..a2aabd3c1a 100644
--- a/man/sd_event_add_signal.xml
+++ b/man/sd_event_add_signal.xml
@@ -128,7 +128,7 @@
<constant>SD_EVENT_OFF</constant> with
<citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
- <para>If the the second parameter of
+ <para>If the second parameter of
<function>sd_event_add_signal()</function> is passed as NULL no
reference to the event source object is returned. In this case the
event source is considered "floating", and will be destroyed
diff --git a/man/sd_event_add_time.xml b/man/sd_event_add_time.xml
index df38f52fc9..b58d740bd8 100644
--- a/man/sd_event_add_time.xml
+++ b/man/sd_event_add_time.xml
@@ -159,7 +159,7 @@
disabled after the invocation, even if the
<constant>SD_EVENT_ON</constant> mode was requested before. Note
that a timer event set to <constant>SD_EVENT_ON</constant> will
- fire continously unless its configured time is updated using
+ fire continuously unless its configured time is updated using
<function>sd_event_source_set_time()</function>.
</para>
@@ -172,7 +172,7 @@
<constant>SD_EVENT_OFF</constant> with
<citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
- <para>If the the second parameter of
+ <para>If the second parameter of
<function>sd_event_add_time()</function> is passed as NULL no
reference to the event source object is returned. In this case the
event source is considered "floating", and will be destroyed
diff --git a/man/sd_event_exit.xml b/man/sd_event_exit.xml
index 4f34f3b122..9846a3eaf4 100644
--- a/man/sd_event_exit.xml
+++ b/man/sd_event_exit.xml
@@ -76,7 +76,7 @@
exit. The <parameter>code</parameter> parameter may be any integer
value and is returned as-is by
<citerefentry><refentrytitle>sd_event_loop</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- after the last event loop iteration. It may also be be queried
+ after the last event loop iteration. It may also be queried
using <function>sd_event_get_exit_code()</function>, see
below. </para>
diff --git a/man/sd_event_now.xml b/man/sd_event_now.xml
index f577e44c0e..58d7375eac 100644
--- a/man/sd_event_now.xml
+++ b/man/sd_event_now.xml
@@ -67,7 +67,7 @@
<para><function>sd_event_now()</function> returns the timestamp
the most recent event loop iteration began. This timestamp is
- taken right after after returning from the event sleep, and before
+ taken right after returning from the event sleep, and before
dispatching any event sources. The <parameter>event</parameter>
parameter takes the even loop object to retrieve the timestamp
from. The <parameter>clock</parameter> parameter specifies the clock to
diff --git a/man/sd_event_source_set_enabled.xml b/man/sd_event_source_set_enabled.xml
index 74c02e87bb..6844f29a49 100644
--- a/man/sd_event_source_set_enabled.xml
+++ b/man/sd_event_source_set_enabled.xml
@@ -105,7 +105,7 @@
with calls such as
<citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>. However,
- depending on the event source type they are enabled continously
+ depending on the event source type they are enabled continuously
(<constant>SD_EVENT_ON</constant>) or only for a single invocation
of the event source handler
(<constant>SD_EVENT_ONESHOT</constant>). For details see the
diff --git a/man/sd_event_source_set_prepare.xml b/man/sd_event_source_set_prepare.xml
index 7066a55306..24861d01d9 100644
--- a/man/sd_event_source_set_prepare.xml
+++ b/man/sd_event_source_set_prepare.xml
@@ -71,7 +71,7 @@
<title>Description</title>
<para><function>sd_event_source_set_prepare()</function> may be
- used to set a prepartion callback for the event source object
+ used to set a preparation callback for the event source object
specified as <parameter>source</parameter>. The callback function
specified as <parameter>callback</parameter> will be invoked
immediately before the event loop goes to sleep to wait for
diff --git a/man/sd_event_source_set_priority.xml b/man/sd_event_source_set_priority.xml
index cc0f5a0103..9234f4233e 100644
--- a/man/sd_event_source_set_priority.xml
+++ b/man/sd_event_source_set_priority.xml
@@ -111,7 +111,7 @@
dispatched is undefined, but the event loop generally tries to
dispatch them in the order it learnt about events on them. As the
backing kernel primitives do not provide accurate information
- about the order in which events occured this is not necessarily
+ about the order in which events occurred this is not necessarily
reliable. However, it is guaranteed that if events are seen on
multiple same-priority event sources at the same time, each one is
not dispatched again until all others have been dispatched
diff --git a/man/sd_event_wait.xml b/man/sd_event_wait.xml
index 1eefa80700..f2aea00e98 100644
--- a/man/sd_event_wait.xml
+++ b/man/sd_event_wait.xml
@@ -107,7 +107,7 @@
and
<citerefentry><refentrytitle>sd_event_loop</refentrytitle><manvolnum>3</manvolnum></citerefentry>
for higher-level functions that execute individual but complete
- iterations of an event loop or run it continously.</para>
+ iterations of an event loop or run it continuously.</para>
<para><function>sd_event_prepare()</function> checks for pending
events and arms necessary timers. If any events are ready to be
@@ -169,7 +169,7 @@
<term><constant>SD_EVENT_PREPARING</constant></term>
<listitem><para>An event source is currently being prepared,
- i.e. the preparation handler is currently being excuted, as
+ i.e. the preparation handler is currently being executed, as
set with
<citerefentry><refentrytitle>sd_event_set_prepare</refentrytitle><manvolnum>3</manvolnum></citerefentry>. This
state is only seen in the event source preparation handler
diff --git a/man/sd_notify.xml b/man/sd_notify.xml
index dbf6330453..bd6cfdcd29 100644
--- a/man/sd_notify.xml
+++ b/man/sd_notify.xml
@@ -242,7 +242,7 @@
multiple file descriptors are submitted at once, the specified
name will be assigned to all of them. In order to assign
different names to submitted file descriptors, submit them in
- seperate invocations of
+ separate invocations of
<function>sd_pid_notify_with_fds()</function>. The name may
consist of any ASCII character, but must not contain control
characters or <literal>:</literal>. It may not be longer than
diff --git a/man/sd_seat_get_active.xml b/man/sd_seat_get_active.xml
index 6e1d505dce..c5e6ddab02 100644
--- a/man/sd_seat_get_active.xml
+++ b/man/sd_seat_get_active.xml
@@ -192,7 +192,7 @@
<function>sd_seat_get_sessions()</function>,
<function>sd_seat_can_multi_session()</function>,
<function>sd_seat_can_tty()</function> and
- <function>sd_seat_can_grapical()</function> interfaces are
+ <function>sd_seat_can_graphical()</function> interfaces are
available as a shared library, which can be compiled and linked to
with the
<constant>libsystemd</constant> <citerefentry project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry>
diff --git a/man/systemctl.xml b/man/systemctl.xml
index cf914f4cb2..a55e06059a 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -1176,7 +1176,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
</row>
<row>
<entry><literal>bad</literal></entry>
- <entry>Unit file is invalid or another error occured. Note that <command>is-enabled</command> will not actually return this state, but print an error message instead. However the unit file listing printed by <command>list-unit-files</command> might show it.</entry>
+ <entry>Unit file is invalid or another error occurred. Note that <command>is-enabled</command> will not actually return this state, but print an error message instead. However the unit file listing printed by <command>list-unit-files</command> might show it.</entry>
<entry>&gt; 0</entry>
</row>
</tbody>
diff --git a/man/systemd-resolved.service.xml b/man/systemd-resolved.service.xml
index 43d568c6f7..10198812e1 100644
--- a/man/systemd-resolved.service.xml
+++ b/man/systemd-resolved.service.xml
@@ -117,7 +117,7 @@
<listitem><para>Multi-label names are routed to all local
interfaces that have a DNS sever configured, plus the globally
configured DNS server if there is one. Address lookups from the
- link-local addres range are never routed to
+ link-local address range are never routed to
DNS.</para></listitem>
</itemizedlist>
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index e6dedb027d..5ad03f75e6 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -228,7 +228,7 @@
<literal>ipv4</literal>, or <literal>ipv6</literal>.</para>
<para>Note that DHCPv6 will by default be triggered by Router
- Advertisment, if that is enabled, regardless of this parameter.
+ Advertisement, if that is enabled, regardless of this parameter.
By enabling DHCPv6 support explicitly, the DHCPv6 client will
be started regardless of the presence of routers on the link,
or what flags the routers pass. See
@@ -673,7 +673,7 @@
<term><varname>UseTimezone=</varname></term>
<listitem><para>When true, the timezone received from the
- DHCP server will be set as as timezone of the local
+ DHCP server will be set as timezone of the local
system. Defaults to <literal>no</literal>.</para></listitem>
</varlistentry>
diff --git a/man/systemd.special.xml b/man/systemd.special.xml
index 54e7c49a9e..d28f3d5f90 100644
--- a/man/systemd.special.xml
+++ b/man/systemd.special.xml
@@ -587,7 +587,7 @@
<varlistentry>
<term><filename>umount.target</filename></term>
<listitem>
- <para>A special target unit that umounts all mount and
+ <para>A special target unit that unmounts all mount and
automount points on system shutdown.</para>
<para>Mounts that shall be unmounted on system shutdown
diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml
index cfa13015b0..29e235e2dc 100644
--- a/man/systemd.timer.xml
+++ b/man/systemd.timer.xml
@@ -284,7 +284,7 @@
unloaded. Turning this off is particularly useful for
transient timer units that shall disappear after they first
elapse. Note that this setting has an effect on repeatedly
- starting the a timer unit that only elapses once: if
+ starting a timer unit that only elapses once: if
<varname>RemainAfterElapse=</varname> is on, it will not be
started again, and is guaranteed to elapse only once. However,
if <varname>RemainAfterLeapse=</varname> is off, it might be
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index 5b12378eda..126b1b5cb4 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -918,7 +918,7 @@
<filename>/var</filename> on the next following boot. Units
making use of this condition should order themselves before
<citerefentry><refentrytitle>systemd-update-done.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- to make sure they run before the stamp files's modification
+ to make sure they run before the stamp file's modification
time gets reset indicating a completed update.</para>
<para><varname>ConditionFirstBoot=</varname> takes a boolean
diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml
index 5bf1f2956b..3c847d74a9 100644
--- a/man/tmpfiles.d.xml
+++ b/man/tmpfiles.d.xml
@@ -421,7 +421,7 @@
<command>systemd-tmpfiles</command> will automatically add
the required base entries for user and group based on the
access mode of the file, unless base entries already exist
- or are explictly specified. The mask will be added if not
+ or are explicitly specified. The mask will be added if not
specified explicitly or already present. Lines of this type
accept shell-style globs in place of normal path names. This
can be useful for allowing additional access to certain
diff --git a/src/resolve-host/resolve-host.c b/src/resolve-host/resolve-host.c
index fa0dffc03c..dc82769ac6 100644
--- a/src/resolve-host/resolve-host.c
+++ b/src/resolve-host/resolve-host.c
@@ -408,13 +408,11 @@ static int resolve_record(sd_bus *bus, const char *name) {
r = dns_packet_read_rr(p, &rr, NULL, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to parse RR.");
+ return log_error_errno(r, "Failed to parse RR: %m");
s = dns_resource_record_to_string(rr);
- if (!s) {
- log_error("Failed to format RR.");
- return -ENOMEM;
- }
+ if (!s)
+ return log_oom();
ifname[0] = 0;
if (ifindex > 0 && !if_indextoname(ifindex, ifname))
diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c
index 49d5090d36..3193985542 100644
--- a/src/resolve/resolved-dns-cache.c
+++ b/src/resolve/resolved-dns-cache.c
@@ -272,6 +272,42 @@ static DnsCacheItem* dns_cache_get(DnsCache *c, DnsResourceRecord *rr) {
return NULL;
}
+static usec_t calculate_until(DnsResourceRecord *rr, usec_t timestamp, bool use_soa_minimum) {
+ uint32_t ttl;
+ usec_t u;
+
+ assert(rr);
+
+ ttl = rr->ttl;
+ if (rr->key->type == DNS_TYPE_SOA && use_soa_minimum) {
+ /* If this is a SOA RR, and it is requested, clamp to
+ * the SOA's minimum field. This is used when we do
+ * negative caching, to determine the TTL for the
+ * negative caching entry. See RFC 2308, Section
+ * 5. */
+
+ if (ttl > rr->soa.minimum)
+ ttl = rr->soa.minimum;
+ }
+
+ u = ttl * USEC_PER_SEC;
+ if (u > CACHE_TTL_MAX_USEC)
+ u = CACHE_TTL_MAX_USEC;
+
+ if (rr->expiry != USEC_INFINITY) {
+ usec_t left;
+
+ /* Make use of the DNSSEC RRSIG expiry info, if we
+ * have it */
+
+ left = LESS_BY(rr->expiry, now(CLOCK_REALTIME));
+ if (u > left)
+ u = left;
+ }
+
+ return timestamp + u;
+}
+
static void dns_cache_item_update_positive(
DnsCache *c,
DnsCacheItem *i,
@@ -302,7 +338,7 @@ static void dns_cache_item_update_positive(
dns_resource_key_unref(i->key);
i->key = dns_resource_key_ref(rr->key);
- i->until = timestamp + MIN(rr->ttl * USEC_PER_SEC, CACHE_TTL_MAX_USEC);
+ i->until = calculate_until(rr, timestamp, false);
i->authenticated = authenticated;
i->shared_owner = shared_owner;
@@ -383,7 +419,7 @@ static int dns_cache_put_positive(
i->type = DNS_CACHE_POSITIVE;
i->key = dns_resource_key_ref(rr->key);
i->rr = dns_resource_record_ref(rr);
- i->until = timestamp + MIN(i->rr->ttl * USEC_PER_SEC, CACHE_TTL_MAX_USEC);
+ i->until = calculate_until(rr, timestamp, false);
i->authenticated = authenticated;
i->shared_owner = shared_owner;
i->owner_family = owner_family;
@@ -412,7 +448,7 @@ static int dns_cache_put_negative(
int rcode,
bool authenticated,
usec_t timestamp,
- uint32_t soa_ttl,
+ DnsResourceRecord *soa,
int owner_family,
const union in_addr_union *owner_address) {
@@ -422,6 +458,7 @@ static int dns_cache_put_negative(
assert(c);
assert(key);
+ assert(soa);
assert(owner_address);
/* Never cache pseudo RR keys. DNS_TYPE_ANY is particularly
@@ -432,7 +469,7 @@ static int dns_cache_put_negative(
if (dns_type_is_pseudo(key->type))
return 0;
- if (soa_ttl <= 0) {
+ if (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)
@@ -458,7 +495,7 @@ static int dns_cache_put_negative(
return -ENOMEM;
i->type = rcode == DNS_RCODE_SUCCESS ? DNS_CACHE_NODATA : DNS_CACHE_NXDOMAIN;
- i->until = timestamp + MIN(soa_ttl * USEC_PER_SEC, CACHE_TTL_MAX_USEC);
+ i->until = calculate_until(soa, timestamp, true);
i->authenticated = authenticated;
i->owner_family = owner_family;
i->owner_address = *owner_address;
@@ -632,7 +669,7 @@ int dns_cache_put(
rcode,
authenticated,
timestamp,
- MIN(soa->soa.minimum, soa->ttl),
+ soa,
owner_family, owner_address);
if (r < 0)
goto fail;
diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c
index fae4762eb6..a3aa90e98d 100644
--- a/src/resolve/resolved-dns-dnssec.c
+++ b/src/resolve/resolved-dns-dnssec.c
@@ -40,10 +40,9 @@
* - multi-label zone compatibility
* - cname/dname compatibility
* - per-interface DNSSEC setting
- * - fix TTL for cache entries to match RRSIG TTL
+ * - nxdomain on qname
* - retry on failed validation?
- * - DSA support
- * - EC support?
+ * - DSA support?
*
* */
@@ -77,14 +76,6 @@ static void initialize_libgcrypt(void) {
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
}
-static bool dnssec_algorithm_supported(int algorithm) {
- return IN_SET(algorithm,
- DNSSEC_ALGORITHM_RSASHA1,
- DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1,
- DNSSEC_ALGORITHM_RSASHA256,
- DNSSEC_ALGORITHM_RSASHA512);
-}
-
uint16_t dnssec_keytag(DnsResourceRecord *dnskey) {
const uint8_t *p;
uint32_t sum;
@@ -136,7 +127,7 @@ static int rr_compare(const void *a, const void *b) {
return 0;
}
-static int dnssec_rsa_verify(
+static int dnssec_rsa_verify_raw(
const char *hash_algorithm,
const void *signature, size_t signature_size,
const void *data, size_t data_size,
@@ -226,6 +217,196 @@ finish:
return r;
}
+static int dnssec_rsa_verify(
+ const char *hash_algorithm,
+ const void *hash, size_t hash_size,
+ DnsResourceRecord *rrsig,
+ DnsResourceRecord *dnskey) {
+
+ size_t exponent_size, modulus_size;
+ void *exponent, *modulus;
+
+ assert(hash_algorithm);
+ assert(hash);
+ assert(hash_size > 0);
+ assert(rrsig);
+ assert(dnskey);
+
+ if (*(uint8_t*) dnskey->dnskey.key == 0) {
+ /* exponent is > 255 bytes long */
+
+ exponent = (uint8_t*) dnskey->dnskey.key + 3;
+ exponent_size =
+ ((size_t) (((uint8_t*) dnskey->dnskey.key)[0]) << 8) |
+ ((size_t) ((uint8_t*) dnskey->dnskey.key)[1]);
+
+ if (exponent_size < 256)
+ return -EINVAL;
+
+ if (3 + exponent_size >= dnskey->dnskey.key_size)
+ return -EINVAL;
+
+ modulus = (uint8_t*) dnskey->dnskey.key + 3 + exponent_size;
+ modulus_size = dnskey->dnskey.key_size - 3 - exponent_size;
+
+ } else {
+ /* exponent is <= 255 bytes long */
+
+ exponent = (uint8_t*) dnskey->dnskey.key + 1;
+ exponent_size = (size_t) ((uint8_t*) dnskey->dnskey.key)[0];
+
+ if (exponent_size <= 0)
+ return -EINVAL;
+
+ if (1 + exponent_size >= dnskey->dnskey.key_size)
+ return -EINVAL;
+
+ modulus = (uint8_t*) dnskey->dnskey.key + 1 + exponent_size;
+ modulus_size = dnskey->dnskey.key_size - 1 - exponent_size;
+ }
+
+ return dnssec_rsa_verify_raw(
+ hash_algorithm,
+ rrsig->rrsig.signature, rrsig->rrsig.signature_size,
+ hash, hash_size,
+ exponent, exponent_size,
+ modulus, modulus_size);
+}
+
+static int dnssec_ecdsa_verify_raw(
+ const char *hash_algorithm,
+ const char *curve,
+ const void *signature_r, size_t signature_r_size,
+ const void *signature_s, size_t signature_s_size,
+ const void *data, size_t data_size,
+ const void *key, size_t key_size) {
+
+ gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
+ gcry_mpi_t q = NULL, r = NULL, s = NULL;
+ gcry_error_t ge;
+ int k;
+
+ assert(hash_algorithm);
+
+ ge = gcry_mpi_scan(&r, GCRYMPI_FMT_USG, signature_r, signature_r_size, NULL);
+ if (ge != 0) {
+ k = -EIO;
+ goto finish;
+ }
+
+ ge = gcry_mpi_scan(&s, GCRYMPI_FMT_USG, signature_s, signature_s_size, NULL);
+ if (ge != 0) {
+ k = -EIO;
+ goto finish;
+ }
+
+ ge = gcry_mpi_scan(&q, GCRYMPI_FMT_USG, key, key_size, NULL);
+ if (ge != 0) {
+ k = -EIO;
+ goto finish;
+ }
+
+ ge = gcry_sexp_build(&signature_sexp,
+ NULL,
+ "(sig-val (ecdsa (r %m) (s %m)))",
+ r,
+ s);
+ if (ge != 0) {
+ k = -EIO;
+ goto finish;
+ }
+
+ ge = gcry_sexp_build(&data_sexp,
+ NULL,
+ "(data (flags rfc6979) (hash %s %b))",
+ hash_algorithm,
+ (int) data_size,
+ data);
+ if (ge != 0) {
+ k = -EIO;
+ goto finish;
+ }
+
+ ge = gcry_sexp_build(&public_key_sexp,
+ NULL,
+ "(public-key (ecc (curve %s) (q %m)))",
+ curve,
+ q);
+ if (ge != 0) {
+ k = -EIO;
+ goto finish;
+ }
+
+ ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
+ if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
+ k = 0;
+ else if (ge != 0) {
+ log_debug("ECDSA signature check failed: %s", gpg_strerror(ge));
+ k = -EIO;
+ } else
+ k = 1;
+finish:
+ if (r)
+ gcry_mpi_release(r);
+ if (s)
+ gcry_mpi_release(s);
+ if (q)
+ gcry_mpi_release(q);
+
+ if (public_key_sexp)
+ gcry_sexp_release(public_key_sexp);
+ if (signature_sexp)
+ gcry_sexp_release(signature_sexp);
+ if (data_sexp)
+ gcry_sexp_release(data_sexp);
+
+ return k;
+}
+
+static int dnssec_ecdsa_verify(
+ const char *hash_algorithm,
+ int algorithm,
+ const void *hash, size_t hash_size,
+ DnsResourceRecord *rrsig,
+ DnsResourceRecord *dnskey) {
+
+ const char *curve;
+ size_t key_size;
+ uint8_t *q;
+
+ assert(hash);
+ assert(hash_size);
+ assert(rrsig);
+ assert(dnskey);
+
+ if (algorithm == DNSSEC_ALGORITHM_ECDSAP256SHA256) {
+ key_size = 32;
+ curve = "NIST P-256";
+ } else if (algorithm == DNSSEC_ALGORITHM_ECDSAP384SHA384) {
+ key_size = 48;
+ curve = "NIST P-384";
+ } else
+ return -EOPNOTSUPP;
+
+ if (dnskey->dnskey.key_size != key_size * 2)
+ return -EINVAL;
+
+ if (rrsig->rrsig.signature_size != key_size * 2)
+ return -EINVAL;
+
+ q = alloca(key_size*2 + 1);
+ q[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
+ memcpy(q+1, dnskey->dnskey.key, key_size*2);
+
+ return dnssec_ecdsa_verify_raw(
+ hash_algorithm,
+ curve,
+ rrsig->rrsig.signature, key_size,
+ (uint8_t*) rrsig->rrsig.signature + key_size, key_size,
+ hash, hash_size,
+ q, key_size*2+1);
+}
+
static void md_add_uint8(gcry_md_hd_t md, uint8_t v) {
gcry_md_write(md, &v, sizeof(v));
}
@@ -275,6 +456,31 @@ static int dnssec_rrsig_expired(DnsResourceRecord *rrsig, usec_t realtime) {
return realtime < inception || realtime > expiration;
}
+static int algorithm_to_gcrypt_md(uint8_t algorithm) {
+
+ /* Translates a DNSSEC signature algorithm into a gcrypt digest identifier */
+
+ switch (algorithm) {
+
+ case DNSSEC_ALGORITHM_RSASHA1:
+ case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
+ return GCRY_MD_SHA1;
+
+ case DNSSEC_ALGORITHM_RSASHA256:
+ case DNSSEC_ALGORITHM_ECDSAP256SHA256:
+ return GCRY_MD_SHA256;
+
+ case DNSSEC_ALGORITHM_ECDSAP384SHA384:
+ return GCRY_MD_SHA384;
+
+ case DNSSEC_ALGORITHM_RSASHA512:
+ return GCRY_MD_SHA512;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
int dnssec_verify_rrset(
DnsAnswer *a,
DnsResourceKey *key,
@@ -284,12 +490,12 @@ int dnssec_verify_rrset(
DnssecResult *result) {
uint8_t wire_format_name[DNS_WIRE_FOMAT_HOSTNAME_MAX];
- size_t exponent_size, modulus_size, hash_size;
- void *exponent, *modulus, *hash;
+ size_t hash_size;
+ void *hash;
DnsResourceRecord **list, *rr;
gcry_md_hd_t md = NULL;
+ int r, md_algorithm;
size_t k, n = 0;
- int r;
assert(key);
assert(rrsig);
@@ -302,10 +508,13 @@ int dnssec_verify_rrset(
* using the signature "rrsig" and the key "dnskey". It's
* assumed the RRSIG and DNSKEY match. */
- if (!dnssec_algorithm_supported(rrsig->rrsig.algorithm)) {
+ md_algorithm = algorithm_to_gcrypt_md(rrsig->rrsig.algorithm);
+ if (md_algorithm == -EOPNOTSUPP) {
*result = DNSSEC_UNSUPPORTED_ALGORITHM;
return 0;
}
+ if (md_algorithm < 0)
+ return md_algorithm;
if (a->n_rrs > VERIFY_RRS_MAX)
return -E2BIG;
@@ -342,31 +551,13 @@ int dnssec_verify_rrset(
/* Bring the RRs into canonical order */
qsort_safe(list, n, sizeof(DnsResourceRecord*), rr_compare);
- initialize_libgcrypt();
-
/* OK, the RRs are now in canonical order. Let's calculate the digest */
- switch (rrsig->rrsig.algorithm) {
-
- case DNSSEC_ALGORITHM_RSASHA1:
- case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
- gcry_md_open(&md, GCRY_MD_SHA1, 0);
- hash_size = 20;
- break;
-
- case DNSSEC_ALGORITHM_RSASHA256:
- gcry_md_open(&md, GCRY_MD_SHA256, 0);
- hash_size = 32;
- break;
-
- case DNSSEC_ALGORITHM_RSASHA512:
- gcry_md_open(&md, GCRY_MD_SHA512, 0);
- hash_size = 64;
- break;
+ initialize_libgcrypt();
- default:
- assert_not_reached("Unknown digest");
- }
+ hash_size = gcry_md_get_algo_dlen(md_algorithm);
+ assert(hash_size > 0);
+ gcry_md_open(&md, md_algorithm, 0);
if (!md)
return -EIO;
@@ -417,53 +608,30 @@ int dnssec_verify_rrset(
goto finish;
}
- if (*(uint8_t*) dnskey->dnskey.key == 0) {
- /* exponent is > 255 bytes long */
-
- exponent = (uint8_t*) dnskey->dnskey.key + 3;
- exponent_size =
- ((size_t) (((uint8_t*) dnskey->dnskey.key)[0]) << 8) |
- ((size_t) ((uint8_t*) dnskey->dnskey.key)[1]);
-
- if (exponent_size < 256) {
- r = -EINVAL;
- goto finish;
- }
-
- if (3 + exponent_size >= dnskey->dnskey.key_size) {
- r = -EINVAL;
- goto finish;
- }
-
- modulus = (uint8_t*) dnskey->dnskey.key + 3 + exponent_size;
- modulus_size = dnskey->dnskey.key_size - 3 - exponent_size;
-
- } else {
- /* exponent is <= 255 bytes long */
-
- exponent = (uint8_t*) dnskey->dnskey.key + 1;
- exponent_size = (size_t) ((uint8_t*) dnskey->dnskey.key)[0];
-
- if (exponent_size <= 0) {
- r = -EINVAL;
- goto finish;
- }
+ switch (rrsig->rrsig.algorithm) {
- if (1 + exponent_size >= dnskey->dnskey.key_size) {
- r = -EINVAL;
- goto finish;
- }
+ case DNSSEC_ALGORITHM_RSASHA1:
+ case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
+ case DNSSEC_ALGORITHM_RSASHA256:
+ case DNSSEC_ALGORITHM_RSASHA512:
+ r = dnssec_rsa_verify(
+ gcry_md_algo_name(md_algorithm),
+ hash, hash_size,
+ rrsig,
+ dnskey);
+ break;
- modulus = (uint8_t*) dnskey->dnskey.key + 1 + exponent_size;
- modulus_size = dnskey->dnskey.key_size - 1 - exponent_size;
+ case DNSSEC_ALGORITHM_ECDSAP256SHA256:
+ case DNSSEC_ALGORITHM_ECDSAP384SHA384:
+ r = dnssec_ecdsa_verify(
+ gcry_md_algo_name(md_algorithm),
+ rrsig->rrsig.algorithm,
+ hash, hash_size,
+ rrsig,
+ dnskey);
+ break;
}
- r = dnssec_rsa_verify(
- gcry_md_algo_name(gcry_md_get_algo(md)),
- rrsig->rrsig.signature, rrsig->rrsig.signature_size,
- hash, hash_size,
- exponent, exponent_size,
- modulus, modulus_size);
if (r < 0)
goto finish;
@@ -533,6 +701,30 @@ int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig)
return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig->key), DNS_RESOURCE_KEY_NAME(key));
}
+static int dnssec_fix_rrset_ttl(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord *rrsig, usec_t realtime) {
+ DnsResourceRecord *rr;
+ int r;
+
+ assert(key);
+ assert(rrsig);
+
+ DNS_ANSWER_FOREACH(rr, a) {
+ r = dns_resource_key_equal(key, rr->key);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ continue;
+
+ /* Pick the TTL as the minimum of the RR's TTL, the
+ * RR's original TTL according to the RRSIG and the
+ * RRSIG's own TTL, see RFC 4035, Section 5.3.3 */
+ rr->ttl = MIN3(rr->ttl, rrsig->rrsig.original_ttl, rrsig->ttl);
+ rr->expiry = rrsig->rrsig.expiration * USEC_PER_SEC;
+ }
+
+ return 0;
+}
+
int dnssec_verify_rrset_search(
DnsAnswer *a,
DnsResourceKey *key,
@@ -599,7 +791,11 @@ int dnssec_verify_rrset_search(
case DNSSEC_VALIDATED:
/* Yay, the RR has been validated,
- * return immediately. */
+ * return immediately, but fix up the expiry */
+ r = dnssec_fix_rrset_ttl(a, key, rrsig, realtime);
+ if (r < 0)
+ return r;
+
*result = DNSSEC_VALIDATED;
return 0;
@@ -730,9 +926,9 @@ int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) {
return (int) c;
}
-static int digest_to_gcrypt(uint8_t algorithm) {
+static int digest_to_gcrypt_md(uint8_t algorithm) {
- /* Translates a DNSSEC digest algorithm into a gcrypt digest iedntifier */
+ /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
switch (algorithm) {
@@ -742,6 +938,9 @@ static int digest_to_gcrypt(uint8_t algorithm) {
case DNSSEC_DIGEST_SHA256:
return GCRY_MD_SHA256;
+ case DNSSEC_DIGEST_SHA384:
+ return GCRY_MD_SHA384;
+
default:
return -EOPNOTSUPP;
}
@@ -751,9 +950,8 @@ int dnssec_verify_dnskey(DnsResourceRecord *dnskey, DnsResourceRecord *ds) {
char owner_name[DNSSEC_CANONICAL_HOSTNAME_MAX];
gcry_md_hd_t md = NULL;
size_t hash_size;
- int algorithm;
+ int md_algorithm, r;
void *result;
- int r;
assert(dnskey);
assert(ds);
@@ -776,11 +974,11 @@ int dnssec_verify_dnskey(DnsResourceRecord *dnskey, DnsResourceRecord *ds) {
initialize_libgcrypt();
- algorithm = digest_to_gcrypt(ds->ds.digest_type);
- if (algorithm < 0)
- return algorithm;
+ md_algorithm = digest_to_gcrypt_md(ds->ds.digest_type);
+ if (md_algorithm < 0)
+ return md_algorithm;
- hash_size = gcry_md_get_algo_dlen(algorithm);
+ hash_size = gcry_md_get_algo_dlen(md_algorithm);
assert(hash_size > 0);
if (ds->ds.digest_size != hash_size)
@@ -790,7 +988,7 @@ int dnssec_verify_dnskey(DnsResourceRecord *dnskey, DnsResourceRecord *ds) {
if (r < 0)
return r;
- gcry_md_open(&md, algorithm, 0);
+ gcry_md_open(&md, md_algorithm, 0);
if (!md)
return -EIO;
@@ -866,7 +1064,7 @@ int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
if (nsec3->key->type != DNS_TYPE_NSEC3)
return -EINVAL;
- algorithm = digest_to_gcrypt(nsec3->nsec3.algorithm);
+ algorithm = digest_to_gcrypt_md(nsec3->nsec3.algorithm);
if (algorithm < 0)
return algorithm;
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index 04d442bf03..d479de7125 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -339,6 +339,7 @@ DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
rr->n_ref = 1;
rr->key = dns_resource_key_ref(key);
+ rr->expiry = USEC_INFINITY;
return rr;
}
diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h
index f2997883a8..fccc4dba6a 100644
--- a/src/resolve/resolved-dns-rr.h
+++ b/src/resolve/resolved-dns-rr.h
@@ -53,6 +53,8 @@ enum {
DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1,
DNSSEC_ALGORITHM_RSASHA256 = 8, /* RFC 5702 */
DNSSEC_ALGORITHM_RSASHA512 = 10, /* RFC 5702 */
+ DNSSEC_ALGORITHM_ECDSAP256SHA256 = 13, /* RFC 6605 */
+ DNSSEC_ALGORITHM_ECDSAP384SHA384 = 14, /* RFC 6605 */
DNSSEC_ALGORITHM_INDIRECT = 252,
DNSSEC_ALGORITHM_PRIVATEDNS,
DNSSEC_ALGORITHM_PRIVATEOID,
@@ -64,6 +66,7 @@ enum {
enum {
DNSSEC_DIGEST_SHA1 = 1,
DNSSEC_DIGEST_SHA256 = 2,
+ DNSSEC_DIGEST_SHA384 = 4,
_DNSSEC_DIGEST_MAX_DEFINED
};
@@ -97,6 +100,7 @@ struct DnsResourceRecord {
DnsResourceKey *key;
char *to_string;
uint32_t ttl;
+ usec_t expiry; /* RRSIG signature expiry */
bool unparseable:1;
bool wire_format_canonical:1;
void *wire_format;
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 3ca4a5ab74..fb95554db3 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -48,14 +48,10 @@ static void dns_transaction_close_connection(DnsTransaction *t) {
t->dns_udp_fd = safe_close(t->dns_udp_fd);
}
-static void dns_transaction_stop(DnsTransaction *t) {
+static void dns_transaction_stop_timeout(DnsTransaction *t) {
assert(t);
t->timeout_event_source = sd_event_source_unref(t->timeout_event_source);
- t->stream = dns_stream_free(t->stream);
-
- /* Note that we do not drop the UDP socket here, as we want to
- * reuse it to repeat the interaction. */
}
DnsTransaction* dns_transaction_free(DnsTransaction *t) {
@@ -67,7 +63,7 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) {
return NULL;
dns_transaction_close_connection(t);
- dns_transaction_stop(t);
+ dns_transaction_stop_timeout(t);
dns_packet_unref(t->sent);
dns_transaction_reset_answer(t);
@@ -264,7 +260,7 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
t->state = state;
dns_transaction_close_connection(t);
- dns_transaction_stop(t);
+ dns_transaction_stop_timeout(t);
/* Notify all queries that are interested, but make sure the
* transaction isn't freed while we are still looking at it */
@@ -725,7 +721,8 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
if (r > 0) {
/* There are DNSSEC transactions pending now. Update the state accordingly. */
t->state = DNS_TRANSACTION_VALIDATING;
- dns_transaction_stop(t);
+ dns_transaction_close_connection(t);
+ dns_transaction_stop_timeout(t);
return;
}
}
@@ -869,7 +866,7 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) {
assert(t);
- dns_transaction_stop(t);
+ dns_transaction_stop_timeout(t);
if (t->n_attempts >= TRANSACTION_ATTEMPTS_MAX(t->scope->protocol)) {
dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED);
diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c
index 0273b9e3c9..68404ca9e5 100644
--- a/src/shared/dns-domain.c
+++ b/src/shared/dns-domain.c
@@ -98,8 +98,13 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
((unsigned) (n[1] - '0') * 10) +
((unsigned) (n[2] - '0'));
- /* Don't allow CC characters or anything that doesn't fit in 8bit */
- if (k < ' ' || k > 255 || k == 127)
+ /* Don't allow anything that doesn't
+ * fit in 8bit. Note that we do allow
+ * control characters, as some servers
+ * (e.g. cloudflare) are happy to
+ * generate labels with them
+ * inside. */
+ if (k > 255)
return -EINVAL;
if (d)
@@ -245,7 +250,7 @@ int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {
*(q++) = *p;
sz -= 1;
- } else if ((uint8_t) *p >= (uint8_t) ' ' && *p != 127) {
+ } else {
/* Everything else */
@@ -259,8 +264,7 @@ int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {
sz -= 4;
- } else
- return -EINVAL;
+ }
p++;
l--;
diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c
index 1b0cb153f7..6c3c49908f 100644
--- a/src/test/test-dns-domain.c
+++ b/src/test/test-dns-domain.c
@@ -168,7 +168,7 @@ static void test_dns_label_escape_one(const char *what, size_t l, const char *ex
static void test_dns_label_escape(void) {
test_dns_label_escape_one("", 0, NULL, -EINVAL);
test_dns_label_escape_one("hallo", 5, "hallo", 5);
- test_dns_label_escape_one("hallo", 6, NULL, -EINVAL);
+ test_dns_label_escape_one("hallo", 6, "hallo\\000", 9);
test_dns_label_escape_one("hallo hallo.foobar,waldi", 24, "hallo\\032hallo\\.foobar\\044waldi", 31);
}
@@ -190,7 +190,7 @@ static void test_dns_name_normalize(void) {
test_dns_name_normalize_one("f", "f", 0);
test_dns_name_normalize_one("f.waldi", "f.waldi", 0);
test_dns_name_normalize_one("f \\032.waldi", "f\\032\\032.waldi", 0);
- test_dns_name_normalize_one("\\000", NULL, -EINVAL);
+ test_dns_name_normalize_one("\\000", "\\000", 0);
test_dns_name_normalize_one("..", NULL, -EINVAL);
test_dns_name_normalize_one(".foobar", NULL, -EINVAL);
test_dns_name_normalize_one("foobar.", "foobar", 0);
@@ -216,7 +216,7 @@ static void test_dns_name_equal(void) {
test_dns_name_equal_one("abc.def", "CBA.def", false);
test_dns_name_equal_one("", "xxx", false);
test_dns_name_equal_one("ab", "a", false);
- test_dns_name_equal_one("\\000", "xxxx", -EINVAL);
+ test_dns_name_equal_one("\\000", "\\000", true);
test_dns_name_equal_one(".", "", true);
test_dns_name_equal_one(".", ".", true);
test_dns_name_equal_one("..", "..", -EINVAL);