Merge pull request #2469 from keszybz/resolved-2

Resolved 2
This commit is contained in:
Lennart Poettering 2016-01-30 15:04:56 +01:00
commit dcabda4155
21 changed files with 435 additions and 103 deletions

1
.gitignore vendored
View File

@ -251,6 +251,7 @@
/test-rbtree
/test-replace-var
/test-resolve
/test-resolve-tables
/test-ring
/test-rlimit-util
/test-sched-prio

View File

@ -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 \

View File

@ -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

View File

@ -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>

View File

@ -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;

View File

@ -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);

View File

@ -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";
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;
};
};

View File

@ -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",

View File

@ -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,

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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"

View File

@ -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;
}

View File

@ -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));

View File

@ -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);
}