summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile.am14
-rw-r--r--man/resolved.conf.xml6
-rw-r--r--man/systemd-resolve.xml19
-rw-r--r--src/basic/hexdecoct.c61
-rw-r--r--src/basic/hexdecoct.h5
-rw-r--r--src/resolve/dns-type.c46
-rw-r--r--src/resolve/dns-type.h11
-rw-r--r--src/resolve/resolve-tool.c43
-rw-r--r--src/resolve/resolved-dns-packet.c49
-rw-r--r--src/resolve/resolved-dns-rr.c184
-rw-r--r--src/resolve/resolved-dns-rr.h11
-rw-r--r--src/resolve/resolved-dns-server.c13
-rw-r--r--src/resolve/resolved-dns-server.h4
-rw-r--r--src/resolve/resolved-manager.c2
-rw-r--r--src/resolve/resolved-resolv-conf.c2
-rw-r--r--src/resolve/resolved-resolv-conf.h2
-rw-r--r--src/resolve/resolved.c2
-rw-r--r--src/resolve/test-resolve-tables.c27
-rw-r--r--src/shared/test-tables.h15
-rw-r--r--src/test/test-util.c21
21 files changed, 435 insertions, 103 deletions
diff --git a/.gitignore b/.gitignore
index b9db9784ad..586b3796b1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -251,6 +251,7 @@
/test-rbtree
/test-replace-var
/test-resolve
+/test-resolve-tables
/test-ring
/test-rlimit-util
/test-sched-prio
diff --git a/Makefile.am b/Makefile.am
index 34b1f1941b..27b727294e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1499,6 +1499,7 @@ tests += \
test-af-list \
test-arphrd-list \
test-dns-domain \
+ test-resolve-tables \
test-install-root \
test-rlimit-util \
test-signal-util
@@ -1663,6 +1664,17 @@ test_dns_domain_LDADD = \
libsystemd-network.la \
libshared.la
+test_resolve_tables_SOURCES = \
+ src/resolve/test-resolve-tables.c \
+ src/shared/test-tables.h \
+ src/resolve/dns-type.c \
+ src/resolve/dns-type.h \
+ src/resolve/dns_type-from-name.h \
+ src/resolve/dns_type-to-name.h
+
+test_resolve_tables_LDADD = \
+ libshared.la
+
if ENABLE_EFI
manual_tests += \
test-boot-timestamp
@@ -5286,6 +5298,8 @@ lib_LTLIBRARIES += \
systemd_resolve_SOURCES = \
src/resolve/resolve-tool.c \
+ src/resolve/resolved-dns-dnssec.c \
+ src/resolve/resolved-dns-dnssec.h \
src/resolve/resolved-dns-packet.c \
src/resolve/resolved-dns-packet.h \
src/resolve/resolved-dns-rr.c \
diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml
index f9e4d548e7..920ce9e89b 100644
--- a/man/resolved.conf.xml
+++ b/man/resolved.conf.xml
@@ -131,8 +131,8 @@
<listitem><para>Takes a boolean argument or
<literal>allow-downgrade</literal>. If true all DNS lookups are
DNSSEC-validated locally (excluding LLMNR and Multicast
- DNS). If a response for a lookup request is detected invalid
- this is returned as lookup failure to applications. Note that
+ DNS). If the response to a lookup request is detected to be invalid
+ a lookup failure is returned to applications. Note that
this mode requires a DNS server that supports DNSSEC. If the
DNS server does not properly support DNSSEC all validations
will fail. If set to <literal>allow-downgrade</literal> DNSSEC
@@ -153,7 +153,7 @@
is built into the resolver, additional trust anchors may be
defined with
<citerefentry><refentrytitle>dnssec-trust-anchors.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
- Trust anchors may change in regular intervals, and old trust
+ Trust anchors may change at regular intervals, and old trust
anchors may be revoked. In such a case DNSSEC validation is
not possible until new trust anchors are configured locally or
the resolver software package is updated with the new root
diff --git a/man/systemd-resolve.xml b/man/systemd-resolve.xml
index c5ad6a0e3e..546054a403 100644
--- a/man/systemd-resolve.xml
+++ b/man/systemd-resolve.xml
@@ -64,14 +64,14 @@
<cmdsynopsis>
<command>systemd-resolve</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
- <command>--type=<replaceable>TYPE</replaceable></command>
+ <command> --type=<replaceable>TYPE</replaceable></command>
<arg choice="plain" rep="repeat"><replaceable>RRDOMAIN</replaceable></arg>
</cmdsynopsis>
<cmdsynopsis>
<command>systemd-resolve</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
- <command>--service</command>
+ <command> --service</command>
<arg choice="plain"><arg choice="opt"><arg choice="opt"><replaceable>NAME</replaceable></arg>
<replaceable>TYPE</replaceable></arg> <replaceable>DOMAIN</replaceable></arg>
</cmdsynopsis>
@@ -79,13 +79,13 @@
<cmdsynopsis>
<command>systemd-resolve</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
- <command>--statistics</command>
+ <command> --statistics</command>
</cmdsynopsis>
<cmdsynopsis>
<command>systemd-resolve</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
- <command>--reset-statistics</command>
+ <command> --reset-statistics</command>
</cmdsynopsis>
</refsynopsisdiv>
@@ -101,7 +101,8 @@
done, and a hostname is retrieved for the specified addresses.</para>
<para>The <option>--type=</option> switch may be used to specify a DNS resource record type (A, AAAA, SOA, MX, ...) in
- order to request a specific DNS resource record, instead of the address or reverse address lookups.</para>
+ order to request a specific DNS resource record, instead of the address or reverse address lookups.
+ The special value <literal>help</literal> may be used to list known values.</para>
<para>The <option>--service</option> switch may be used to resolve <ulink
url="https://tools.ietf.org/html/rfc2782">SRV</ulink> and <ulink
@@ -157,7 +158,9 @@
same time. The setting <literal>llmnr</literal> is identical to specifying this switch once with
<literal>llmnr-ipv4</literal> and once via <literal>llmnr-ipv6</literal>. Note that this option does not force
the service to resolve the operation with the specified protocol, as that might require a suitable network
- interface and configuration.</para></listitem>
+ interface and configuration.
+ The special value <literal>help</literal> may be used to list known values.
+ </para></listitem>
</varlistentry>
<varlistentry>
@@ -168,7 +171,9 @@
<listitem><para>Specifies the DNS resource record type (e.g. A, AAAA, MX, …) and class (e.g. IN, ANY, …) to
look up. If these options are used a DNS resource record set matching the specified class and type is
- requested. The class defaults to IN if only a type is specified.</para></listitem>
+ requested. The class defaults to IN if only a type is specified.
+ The special value <literal>help</literal> may be used to list known values.
+ </para></listitem>
</varlistentry>
<varlistentry>
diff --git a/src/basic/hexdecoct.c b/src/basic/hexdecoct.c
index 1e907de228..f30e028f45 100644
--- a/src/basic/hexdecoct.c
+++ b/src/basic/hexdecoct.c
@@ -514,14 +514,14 @@ int unbase64char(char c) {
return -EINVAL;
}
-char *base64mem(const void *p, size_t l) {
+ssize_t base64mem(const void *p, size_t l, char **out) {
char *r, *z;
const uint8_t *x;
/* three input bytes makes four output bytes, padding is added so we must round up */
z = r = malloc(4 * (l + 2) / 3 + 1);
if (!r)
- return NULL;
+ return -ENOMEM;
for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
/* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
@@ -549,9 +549,64 @@ char *base64mem(const void *p, size_t l) {
}
*z = 0;
- return r;
+ *out = r;
+ return z - r;
+}
+
+static int base64_append_width(char **prefix, int plen,
+ const char *sep, int indent,
+ const void *p, size_t l,
+ int width) {
+
+ _cleanup_free_ char *x = NULL;
+ char *t, *s;
+ ssize_t slen, len, avail;
+ int line, lines;
+
+ len = base64mem(p, l, &x);
+ if (len <= 0)
+ return len;
+
+ lines = (len + width - 1) / width;
+
+ slen = sep ? strlen(sep) : 0;
+ t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);
+ if (!t)
+ return -ENOMEM;
+
+ memcpy(t + plen, sep, slen);
+
+ for (line = 0, s = t + plen + slen, avail = len; line < lines; line++) {
+ int act = MIN(width, avail);
+
+ if (line > 0 || sep) {
+ memset(s, ' ', indent);
+ s += indent;
+ }
+
+ memcpy(s, x + width * line, act);
+ s += act;
+ *(s++) = line < lines - 1 ? '\n' : '\0';
+ avail -= act;
+ }
+ assert(avail == 0);
+
+ *prefix = t;
+ return 0;
}
+int base64_append(char **prefix, int plen,
+ const void *p, size_t l,
+ int indent, int width) {
+ if (plen > width / 2 || plen + indent > width)
+ /* leave indent on the left, keep last column free */
+ return base64_append_width(prefix, plen, "\n", indent, p, l, width - indent - 1);
+ else
+ /* leave plen on the left, keep last column free */
+ return base64_append_width(prefix, plen, NULL, plen, p, l, width - plen - 1);
+};
+
+
int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
_cleanup_free_ uint8_t *r = NULL;
int a, b, c, d;
diff --git a/src/basic/hexdecoct.h b/src/basic/hexdecoct.h
index d9eb54a8a1..243c5e921e 100644
--- a/src/basic/hexdecoct.h
+++ b/src/basic/hexdecoct.h
@@ -49,7 +49,10 @@ int unbase64char(char c) _const_;
char *base32hexmem(const void *p, size_t l, bool padding);
int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len);
-char *base64mem(const void *p, size_t l);
+ssize_t base64mem(const void *p, size_t l, char **out);
+int base64_append(char **prefix, int plen,
+ const void *p, size_t l,
+ int margin, int width);
int unbase64mem(const char *p, size_t l, void **mem, size_t *len);
void hexdump(FILE *f, const void *p, size_t s);
diff --git a/src/resolve/dns-type.c b/src/resolve/dns-type.c
index 56720646ca..fc2f1826fd 100644
--- a/src/resolve/dns-type.c
+++ b/src/resolve/dns-type.c
@@ -22,6 +22,7 @@
#include <sys/socket.h>
#include "dns-type.h"
+#include "parse-util.h"
#include "string-util.h"
typedef const struct {
@@ -41,10 +42,19 @@ int dns_type_from_string(const char *s) {
assert(s);
sc = lookup_dns_type(s, strlen(s));
- if (!sc)
- return _DNS_TYPE_INVALID;
+ if (sc)
+ return sc->id;
- return sc->id;
+ s = startswith_no_case(s, "TYPE");
+ if (s) {
+ unsigned x;
+
+ if (safe_atou(s, &x) >= 0 &&
+ x <= UINT16_MAX)
+ return (int) x;
+ }
+
+ return _DNS_TYPE_INVALID;
}
bool dns_type_is_pseudo(uint16_t type) {
@@ -228,3 +238,33 @@ int dns_class_from_string(const char *s) {
return _DNS_CLASS_INVALID;
}
+
+const char* tlsa_cert_usage_to_string(uint8_t cert_usage) {
+ switch(cert_usage) {
+ case 0: return "CA constraint";
+ case 1: return "Service certificate constraint";
+ case 2: return "Trust anchor assertion";
+ case 3: return "Domain-issued certificate";
+ case 4 ... 254: return "Unassigned";
+ case 255: return "Private use";
+ }
+}
+
+const char* tlsa_selector_to_string(uint8_t selector) {
+ switch(selector) {
+ case 0: return "Full Certificate";
+ case 1: return "SubjectPublicKeyInfo";
+ case 2 ... 254: return "Unassigned";
+ case 255: return "Private use";
+ }
+}
+
+const char* tlsa_matching_type_to_string(uint8_t selector) {
+ switch(selector) {
+ case 0: return "No hash used";
+ case 1: return "SHA-256";
+ case 2: return "SHA-512";
+ case 3 ... 254: return "Unassigned";
+ case 255: return "Private use";
+ }
+}
diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h
index 60ff160383..d025544bab 100644
--- a/src/resolve/dns-type.h
+++ b/src/resolve/dns-type.h
@@ -87,6 +87,7 @@ enum {
DNS_TYPE_TALINK,
DNS_TYPE_CDS,
DNS_TYPE_CDNSKEY,
+ DNS_TYPE_OPENPGPKEY,
DNS_TYPE_SPF = 0x63,
DNS_TYPE_NID,
@@ -138,8 +139,18 @@ int dns_type_to_af(uint16_t t);
bool dns_class_is_pseudo(uint16_t class);
bool dns_class_is_valid_rr(uint16_t class);
+/* TYPE?? follows http://tools.ietf.org/html/rfc3597#section-5 */
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);
int dns_class_from_string(const char *name);
+
+/* https://tools.ietf.org/html/draft-ietf-dane-protocol-23#section-7.2 */
+const char *tlsa_cert_usage_to_string(uint8_t cert_usage);
+
+/* https://tools.ietf.org/html/draft-ietf-dane-protocol-23#section-7.3 */
+const char *tlsa_selector_to_string(uint8_t selector);
+
+/* https://tools.ietf.org/html/draft-ietf-dane-protocol-23#section-7.4 */
+const char *tlsa_matching_type_to_string(uint8_t selector);
diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c
index fdaeb8d926..9bee953839 100644
--- a/src/resolve/resolve-tool.c
+++ b/src/resolve/resolve-tool.c
@@ -900,6 +900,12 @@ static int reset_statistics(sd_bus *bus) {
return 0;
}
+static void help_protocol_types(void) {
+ if (arg_legend)
+ puts("Known protocol types:");
+ puts("dns\nllmnr\nllmnr-ipv4\nllmnr-ipv6");
+}
+
static void help_dns_types(void) {
int i;
const char *t;
@@ -930,22 +936,22 @@ static void help(void) {
printf("%s [OPTIONS...] NAME...\n"
"%s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\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 Look via protocol\n"
- " -t --type=TYPE Query RR with DNS type\n"
- " -c --class=CLASS Query RR with DNS class\n"
- " --service Resolve service (SRV)\n"
- " --service-address=BOOL Do [not] resolve address for services\n"
- " --service-txt=BOOL Do [not] resolve TXT records for services\n"
- " --cname=BOOL Do [not] follow CNAME redirects\n"
- " --search=BOOL Do [not] use search domains\n"
- " --legend=BOOL Do [not] print column headers and meta information\n"
- " --statistics Show resolver statistics\n"
- " --reset-statistics Reset resolver statistics\n"
+ " -h --help Show this help\n"
+ " --version Show package version\n"
+ " -4 Resolve IPv4 addresses\n"
+ " -6 Resolve IPv6 addresses\n"
+ " -i --interface=INTERFACE Look on interface\n"
+ " -p --protocol=PROTOCOL|help Look via protocol\n"
+ " -t --type=TYPE|help Query RR with DNS type\n"
+ " -c --class=CLASS|help Query RR with DNS class\n"
+ " --service Resolve service (SRV)\n"
+ " --service-address=BOOL Do [not] resolve address for services\n"
+ " --service-txt=BOOL Do [not] resolve TXT records for services\n"
+ " --cname=BOOL Do [not] follow CNAME redirects\n"
+ " --search=BOOL Do [not] use search domains\n"
+ " --legend=BOOL Do [not] print column headers and meta information\n"
+ " --statistics Show resolver statistics\n"
+ " --reset-statistics Reset resolver statistics\n"
, program_invocation_short_name, program_invocation_short_name);
}
@@ -1061,7 +1067,10 @@ static int parse_argv(int argc, char *argv[]) {
break;
case 'p':
- if (streq(optarg, "dns"))
+ if (streq(optarg, "help")) {
+ help_protocol_types();
+ return 0;
+ } else if (streq(optarg, "dns"))
arg_flags |= SD_RESOLVED_DNS;
else if (streq(optarg, "llmnr"))
arg_flags |= SD_RESOLVED_LLMNR;
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index 032e719595..5cbe20832f 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -1058,11 +1058,28 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
break;
+ case DNS_TYPE_TLSA:
+ r = dns_packet_append_uint8(p, rr->tlsa.cert_usage, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_uint8(p, rr->tlsa.selector, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_uint8(p, rr->tlsa.matching_type, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_blob(p, rr->tlsa.data, rr->tlsa.data_size, NULL);
+ break;
+
case DNS_TYPE_OPT:
+ case DNS_TYPE_OPENPGPKEY:
case _DNS_TYPE_INVALID: /* unparseable */
default:
- r = dns_packet_append_blob(p, rr->generic.data, rr->generic.size, NULL);
+ r = dns_packet_append_blob(p, rr->generic.data, rr->generic.data_size, NULL);
break;
}
if (r < 0)
@@ -1976,10 +1993,36 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
break;
}
+ case DNS_TYPE_TLSA:
+ r = dns_packet_read_uint8(p, &rr->tlsa.cert_usage, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_read_uint8(p, &rr->tlsa.selector, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_read_uint8(p, &rr->tlsa.matching_type, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_read_memdup(p, rdlength - 3,
+ &rr->tlsa.data, &rr->tlsa.data_size,
+ NULL);
+ if (rr->tlsa.data_size <= 0) {
+ /* the accepted size depends on the algorithm, but for now
+ just ensure that the value is greater than zero */
+ r = -EBADMSG;
+ goto fail;
+ }
+
+ break;
+
case DNS_TYPE_OPT: /* we only care about the header of OPT for now. */
+ case DNS_TYPE_OPENPGPKEY:
default:
unparseable:
- r = dns_packet_read_memdup(p, rdlength, &rr->generic.data, &rr->generic.size, NULL);
+ r = dns_packet_read_memdup(p, rdlength, &rr->generic.data, &rr->generic.data_size, NULL);
if (r < 0)
goto fail;
break;
@@ -2021,7 +2064,7 @@ static bool opt_is_good(DnsResourceRecord *rr, bool *rfc6975) {
return false;
p = rr->opt.data;
- l = rr->opt.size;
+ l = rr->opt.data_size;
while (l > 0) {
uint16_t option_code, option_length;
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index 7273ef3825..783ec7516c 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -25,11 +25,13 @@
#include "dns-domain.h"
#include "dns-type.h"
#include "hexdecoct.h"
+#include "resolved-dns-dnssec.h"
#include "resolved-dns-packet.h"
#include "resolved-dns-rr.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
+#include "terminal-util.h"
DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
DnsResourceKey *k;
@@ -486,6 +488,11 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
case DNS_TYPE_AAAA:
break;
+ case DNS_TYPE_TLSA:
+ free(rr->tlsa.data);
+ break;
+
+ case DNS_TYPE_OPENPGPKEY:
default:
free(rr->generic.data);
}
@@ -564,6 +571,10 @@ int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const u
return 0;
}
+#define FIELD_EQUAL(a, b, field) \
+ ((a).field ## _size == (b).field ## _size && \
+ memcmp((a).field, (b).field, (a).field ## _size) == 0)
+
int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
int r;
@@ -645,36 +656,30 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor
return a->ds.key_tag == b->ds.key_tag &&
a->ds.algorithm == b->ds.algorithm &&
a->ds.digest_type == b->ds.digest_type &&
- a->ds.digest_size == b->ds.digest_size &&
- memcmp(a->ds.digest, b->ds.digest, a->ds.digest_size) == 0;
+ FIELD_EQUAL(a->ds, b->ds, digest);
case DNS_TYPE_SSHFP:
return a->sshfp.algorithm == b->sshfp.algorithm &&
a->sshfp.fptype == b->sshfp.fptype &&
- a->sshfp.fingerprint_size == b->sshfp.fingerprint_size &&
- memcmp(a->sshfp.fingerprint, b->sshfp.fingerprint, a->sshfp.fingerprint_size) == 0;
+ FIELD_EQUAL(a->sshfp, b->sshfp, fingerprint);
case DNS_TYPE_DNSKEY:
return a->dnskey.flags == b->dnskey.flags &&
a->dnskey.protocol == b->dnskey.protocol &&
a->dnskey.algorithm == b->dnskey.algorithm &&
- a->dnskey.key_size == b->dnskey.key_size &&
- memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
+ FIELD_EQUAL(a->dnskey, b->dnskey, key);
case DNS_TYPE_RRSIG:
/* do the fast comparisons first */
- if (a->rrsig.type_covered != b->rrsig.type_covered ||
- a->rrsig.algorithm != b->rrsig.algorithm ||
- a->rrsig.labels != b->rrsig.labels ||
- a->rrsig.original_ttl != b->rrsig.original_ttl ||
- a->rrsig.expiration != b->rrsig.expiration ||
- a->rrsig.inception != b->rrsig.inception ||
- a->rrsig.key_tag != b->rrsig.key_tag ||
- a->rrsig.signature_size != b->rrsig.signature_size ||
- memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0)
- return false;
-
- return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
+ return a->rrsig.type_covered == b->rrsig.type_covered &&
+ a->rrsig.algorithm == b->rrsig.algorithm &&
+ a->rrsig.labels == b->rrsig.labels &&
+ a->rrsig.original_ttl == b->rrsig.original_ttl &&
+ a->rrsig.expiration == b->rrsig.expiration &&
+ a->rrsig.inception == b->rrsig.inception &&
+ a->rrsig.key_tag == b->rrsig.key_tag &&
+ FIELD_EQUAL(a->rrsig, b->rrsig, signature) &&
+ dns_name_equal(a->rrsig.signer, b->rrsig.signer);
case DNS_TYPE_NSEC:
return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) &&
@@ -682,16 +687,20 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor
case DNS_TYPE_NSEC3:
return a->nsec3.algorithm == b->nsec3.algorithm &&
- a->nsec3.flags == b->nsec3.flags &&
- a->nsec3.iterations == b->nsec3.iterations &&
- a->nsec3.salt_size == b->nsec3.salt_size &&
- memcmp(a->nsec3.salt, b->nsec3.salt, a->nsec3.salt_size) == 0 &&
- memcmp(a->nsec3.next_hashed_name, b->nsec3.next_hashed_name, a->nsec3.next_hashed_name_size) == 0 &&
- bitmap_equal(a->nsec3.types, b->nsec3.types);
+ a->nsec3.flags == b->nsec3.flags &&
+ a->nsec3.iterations == b->nsec3.iterations &&
+ FIELD_EQUAL(a->nsec3, b->nsec3, salt) &&
+ FIELD_EQUAL(a->nsec3, b->nsec3, next_hashed_name) &&
+ bitmap_equal(a->nsec3.types, b->nsec3.types);
+
+ case DNS_TYPE_TLSA:
+ return a->tlsa.cert_usage == b->tlsa.cert_usage &&
+ a->tlsa.selector == b->tlsa.selector &&
+ a->tlsa.matching_type == b->tlsa.matching_type &&
+ FIELD_EQUAL(a->tlsa, b->tlsa, data);
default:
- return a->generic.size == b->generic.size &&
- memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
+ return FIELD_EQUAL(a->generic, b->generic, data);
}
}
@@ -958,23 +967,47 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
case DNS_TYPE_DNSKEY: {
_cleanup_free_ char *alg = NULL;
+ char *ss;
+ int n, n1;
+ uint16_t key_tag;
+
+ key_tag = dnssec_keytag(rr, true);
r = dnssec_algorithm_to_string_alloc(rr->dnskey.algorithm, &alg);
if (r < 0)
return NULL;
- t = base64mem(rr->dnskey.key, rr->dnskey.key_size);
- if (!t)
- return NULL;
-
- r = asprintf(&s, "%s %u %u %s %s",
+ r = asprintf(&s, "%s %n%u %u %s %n",
k,
+ &n1,
rr->dnskey.flags,
rr->dnskey.protocol,
alg,
- t);
+ &n);
+ if (r < 0)
+ return NULL;
+
+ r = base64_append(&s, n,
+ rr->dnskey.key, rr->dnskey.key_size,
+ 8, columns());
if (r < 0)
return NULL;
+
+ r = asprintf(&ss, "%s\n"
+ "%*s-- Flags:%s%s%s\n"
+ "%*s-- Key tag: %u",
+ s,
+ n1, "",
+ rr->dnskey.flags & DNSKEY_FLAG_SEP ? " SEP" : "",
+ rr->dnskey.flags & DNSKEY_FLAG_REVOKE ? " REVOKE" : "",
+ rr->dnskey.flags & DNSKEY_FLAG_ZONE_KEY ? " ZONE_KEY" : "",
+ n1, "",
+ key_tag);
+ if (r < 0)
+ return NULL;
+ free(s);
+ s = ss;
+
break;
}
@@ -982,6 +1015,7 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
_cleanup_free_ char *alg = NULL;
char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1];
const char *type;
+ int n;
type = dns_type_to_string(rr->rrsig.type_covered);
@@ -989,10 +1023,6 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
if (r < 0)
return NULL;
- t = base64mem(rr->rrsig.signature, rr->rrsig.signature_size);
- if (!t)
- return NULL;
-
r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration);
if (r < 0)
return NULL;
@@ -1004,7 +1034,7 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
/* TYPE?? follows
* http://tools.ietf.org/html/rfc3597#section-5 */
- r = asprintf(&s, "%s %s%.*u %s %u %u %s %s %u %s %s",
+ r = asprintf(&s, "%s %s%.*u %s %u %u %s %s %u %s %n",
k,
type ?: "TYPE",
type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
@@ -1015,9 +1045,16 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
inception,
rr->rrsig.key_tag,
rr->rrsig.signer,
- t);
+ &n);
if (r < 0)
return NULL;
+
+ r = base64_append(&s, n,
+ rr->rrsig.signature, rr->rrsig.signature_size,
+ 8, columns());
+ if (r < 0)
+ return NULL;
+
break;
}
@@ -1065,13 +1102,70 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
break;
}
+ case DNS_TYPE_TLSA: {
+ const char *cert_usage, *selector, *matching_type;
+ char *ss;
+ int n;
+
+ cert_usage = tlsa_cert_usage_to_string(rr->tlsa.cert_usage);
+ selector = tlsa_selector_to_string(rr->tlsa.selector);
+ matching_type = tlsa_matching_type_to_string(rr->tlsa.matching_type);
+
+ r = asprintf(&s, "%s %u %u %u %n",
+ k,
+ rr->tlsa.cert_usage,
+ rr->tlsa.selector,
+ rr->tlsa.matching_type,
+ &n);
+ if (r < 0)
+ return NULL;
+
+ r = base64_append(&s, n,
+ rr->tlsa.data, rr->tlsa.data_size,
+ 8, columns());
+ if (r < 0)
+ return NULL;
+
+ r = asprintf(&ss, "%s\n"
+ "%*s-- Cert. usage: %s\n"
+ "%*s-- Selector: %s\n"
+ "%*s-- Matching type: %s",
+ s,
+ n - 6, "", cert_usage,
+ n - 6, "", selector,
+ n - 6, "", matching_type);
+ if (r < 0)
+ return NULL;
+ free(s);
+ s = ss;
+
+ break;
+ }
+
+ case DNS_TYPE_OPENPGPKEY: {
+ int n;
+
+ r = asprintf(&s, "%s %n",
+ k,
+ &n);
+ if (r < 0)
+ return NULL;
+
+ r = base64_append(&s, n,
+ rr->generic.data, rr->generic.data_size,
+ 8, columns());
+ if (r < 0)
+ return NULL;
+ break;
+ }
+
default:
- t = hexmem(rr->generic.data, rr->generic.size);
+ t = hexmem(rr->generic.data, rr->generic.data_size);
if (!t)
return NULL;
/* Format as documented in RFC 3597, Section 5 */
- r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.size, t);
+ r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.data_size, t);
if (r < 0)
return NULL;
break;
@@ -1331,8 +1425,16 @@ static void dns_resource_record_hash_func(const void *i, struct siphash *state)
/* FIXME: We leave the bitmaps out */
break;
+ case DNS_TYPE_TLSA:
+ siphash24_compress(&rr->tlsa.cert_usage, sizeof(rr->tlsa.cert_usage), state);
+ siphash24_compress(&rr->tlsa.selector, sizeof(rr->tlsa.selector), state);
+ siphash24_compress(&rr->tlsa.matching_type, sizeof(rr->tlsa.matching_type), state);
+ siphash24_compress(&rr->tlsa.data, rr->tlsa.data_size, state);
+ break;
+
+ case DNS_TYPE_OPENPGPKEY:
default:
- siphash24_compress(rr->generic.data, rr->generic.size, state);
+ siphash24_compress(rr->generic.data, rr->generic.data_size, state);
break;
}
}
diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h
index d9c31e81c5..37c4487332 100644
--- a/src/resolve/resolved-dns-rr.h
+++ b/src/resolve/resolved-dns-rr.h
@@ -129,7 +129,7 @@ struct DnsResourceRecord {
union {
struct {
void *data;
- size_t size;
+ size_t data_size;
} generic, opt;
struct {
@@ -242,6 +242,15 @@ struct DnsResourceRecord {
size_t next_hashed_name_size;
Bitmap *types;
} nsec3;
+
+ /* https://tools.ietf.org/html/draft-ietf-dane-protocol-23 */
+ struct {
+ uint8_t cert_usage;
+ uint8_t selector;
+ uint8_t matching_type;
+ void *data;
+ size_t data_size;
+ } tlsa;
};
};
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c
index e1d2025863..43ec92f4f0 100644
--- a/src/resolve/resolved-dns-server.c
+++ b/src/resolve/resolved-dns-server.c
@@ -657,7 +657,9 @@ DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
return s;
if (s)
- log_info("Switching to system DNS server %s.", dns_server_string(s));
+ log_info("Switching to %s DNS server %s.",
+ dns_server_type_to_string(s->type),
+ dns_server_string(s));
dns_server_unref(m->current_dns_server);
m->current_dns_server = dns_server_ref(s);
@@ -675,7 +677,7 @@ DnsServer *manager_get_dns_server(Manager *m) {
/* Try to read updates resolv.conf */
manager_read_resolv_conf(m);
- /* If no DNS server was chose so far, pick the first one */
+ /* If no DNS server was chosen so far, pick the first one */
if (!m->current_dns_server)
manager_set_dns_server(m, m->dns_servers);
@@ -723,6 +725,13 @@ void manager_next_dns_server(Manager *m) {
manager_set_dns_server(m, m->dns_servers);
}
+static const char* const dns_server_type_table[_DNS_SERVER_TYPE_MAX] = {
+ [DNS_SERVER_SYSTEM] = "system",
+ [DNS_SERVER_FALLBACK] = "fallback",
+ [DNS_SERVER_LINK] = "link",
+};
+DEFINE_STRING_TABLE_LOOKUP(dns_server_type, DnsServerType);
+
static const char* const dns_server_feature_level_table[_DNS_SERVER_FEATURE_LEVEL_MAX] = {
[DNS_SERVER_FEATURE_LEVEL_TCP] = "TCP",
[DNS_SERVER_FEATURE_LEVEL_UDP] = "UDP",
diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h
index 2a3c921678..7a885655a4 100644
--- a/src/resolve/resolved-dns-server.h
+++ b/src/resolve/resolved-dns-server.h
@@ -30,6 +30,10 @@ typedef enum DnsServerType {
DNS_SERVER_FALLBACK,
DNS_SERVER_LINK,
} DnsServerType;
+#define _DNS_SERVER_TYPE_MAX (DNS_SERVER_LINK + 1)
+
+const char* dns_server_type_to_string(DnsServerType i) _const_;
+DnsServerType dns_server_type_from_string(const char *s) _pure_;
typedef enum DnsServerFeatureLevel {
DNS_SERVER_FEATURE_LEVEL_TCP,
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 4306403834..fbd188c2ac 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -288,7 +288,7 @@ static int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *
r = manager_write_resolv_conf(m);
if (r < 0)
- log_warning_errno(r, "Could not update resolv.conf: %m");
+ log_warning_errno(r, "Could not update "PRIVATE_RESOLV_CONF": %m");
return 0;
}
diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c
index 7567f4c369..c5ce9c4f01 100644
--- a/src/resolve/resolved-resolv-conf.c
+++ b/src/resolve/resolved-resolv-conf.c
@@ -226,8 +226,6 @@ static int write_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *doma
int manager_write_resolv_conf(Manager *m) {
- #define PRIVATE_RESOLV_CONF "/run/systemd/resolve/resolv.conf"
-
_cleanup_ordered_set_free_ OrderedSet *dns = NULL, *domains = NULL;
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
diff --git a/src/resolve/resolved-resolv-conf.h b/src/resolve/resolved-resolv-conf.h
index a3355e994b..7081563965 100644
--- a/src/resolve/resolved-resolv-conf.h
+++ b/src/resolve/resolved-resolv-conf.h
@@ -23,5 +23,7 @@
#include "resolved-manager.h"
+#define PRIVATE_RESOLV_CONF "/run/systemd/resolve/resolv.conf"
+
int manager_read_resolv_conf(Manager *m);
int manager_write_resolv_conf(Manager *m);
diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c
index 472bb32764..eee52da882 100644
--- a/src/resolve/resolved.c
+++ b/src/resolve/resolved.c
@@ -91,7 +91,7 @@ int main(int argc, char *argv[]) {
* symlink */
r = manager_write_resolv_conf(m);
if (r < 0)
- log_warning_errno(r, "Could not create resolv.conf: %m");
+ log_warning_errno(r, "Could not create "PRIVATE_RESOLV_CONF": %m");
sd_notify(false,
"READY=1\n"
diff --git a/src/resolve/test-resolve-tables.c b/src/resolve/test-resolve-tables.c
new file mode 100644
index 0000000000..63660afc87
--- /dev/null
+++ b/src/resolve/test-resolve-tables.c
@@ -0,0 +1,27 @@
+/***
+ This file is part of systemd
+
+ Copyright 2013 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "dns-type.h"
+#include "test-tables.h"
+
+int main(int argc, char **argv) {
+ test_table_sparse(dns_type, DNS_TYPE);
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/shared/test-tables.h b/src/shared/test-tables.h
index 74f1716fe0..228e510104 100644
--- a/src/shared/test-tables.h
+++ b/src/shared/test-tables.h
@@ -28,18 +28,25 @@ static inline void _test_table(const char *name,
reverse_t reverse,
int size,
bool sparse) {
- int i;
+ int i, boring = 0;
for (i = -1; i < size + 1; i++) {
const char* val = lookup(i);
int rev;
- if (val)
+ if (val) {
rev = reverse(val);
- else
+ boring = 0;
+ } else {
rev = reverse("--no-such--value----");
+ boring += i >= 0;
+ }
+
+ if (boring < 1 || i == size)
+ printf("%s: %d → %s → %d\n", name, i, val, rev);
+ else if (boring == 1)
+ printf("%*s ...\n", (int) strlen(name), "");
- printf("%s: %d → %s → %d\n", name, i, val, rev);
assert_se(!(i >= 0 && i < size ?
sparse ? rev != i && rev != -1 : val == NULL || rev != i :
val != NULL || rev != -1));
diff --git a/src/test/test-util.c b/src/test/test-util.c
index f6ed55878c..e199497818 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -545,38 +545,31 @@ static void test_unbase32hexmem(void) {
static void test_base64mem(void) {
char *b64;
- b64 = base64mem("", strlen(""));
- assert_se(b64);
+ assert_se(base64mem("", strlen(""), &b64) == 0);
assert_se(streq(b64, ""));
free(b64);
- b64 = base64mem("f", strlen("f"));
- assert_se(b64);
+ assert_se(base64mem("f", strlen("f"), &b64) == 4);
assert_se(streq(b64, "Zg=="));
free(b64);
- b64 = base64mem("fo", strlen("fo"));
- assert_se(b64);
+ assert_se(base64mem("fo", strlen("fo"), &b64) == 4);
assert_se(streq(b64, "Zm8="));
free(b64);
- b64 = base64mem("foo", strlen("foo"));
- assert_se(b64);
+ assert_se(base64mem("foo", strlen("foo"), &b64) == 4);
assert_se(streq(b64, "Zm9v"));
free(b64);
- b64 = base64mem("foob", strlen("foob"));
- assert_se(b64);
+ assert_se(base64mem("foob", strlen("foob"), &b64) == 8);
assert_se(streq(b64, "Zm9vYg=="));
free(b64);
- b64 = base64mem("fooba", strlen("fooba"));
- assert_se(b64);
+ assert_se(base64mem("fooba", strlen("fooba"), &b64) == 8);
assert_se(streq(b64, "Zm9vYmE="));
free(b64);
- b64 = base64mem("foobar", strlen("foobar"));
- assert_se(b64);
+ assert_se(base64mem("foobar", strlen("foobar"), &b64) == 8);
assert_se(streq(b64, "Zm9vYmFy"));
free(b64);
}