diff options
Diffstat (limited to 'src/resolve')
22 files changed, 530 insertions, 302 deletions
diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h index a6c1630021..f18ac6eef3 100644 --- a/src/resolve/dns-type.h +++ b/src/resolve/dns-type.h @@ -152,3 +152,6 @@ const char *tlsa_selector_to_string(uint8_t selector); /* https://tools.ietf.org/html/draft-ietf-dane-protocol-23#section-7.4 */ const char *tlsa_matching_type_to_string(uint8_t selector); + +/* https://tools.ietf.org/html/rfc6844#section-5.1 */ +#define CAA_FLAG_CRITICAL (1u << 7) diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index 824cb267b5..9aade8e490 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -17,6 +17,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <gcrypt.h> #include <getopt.h> #include <net/if.h> @@ -28,6 +29,7 @@ #include "bus-util.h" #include "escape.h" #include "in-addr-util.h" +#include "gcrypt-util.h" #include "parse-util.h" #include "resolved-def.h" #include "resolved-dns-packet.h" @@ -46,6 +48,7 @@ static enum { MODE_RESOLVE_HOST, MODE_RESOLVE_RECORD, MODE_RESOLVE_SERVICE, + MODE_RESOLVE_OPENPGP, MODE_STATISTICS, MODE_RESET_STATISTICS, } arg_mode = MODE_RESOLVE_HOST; @@ -545,15 +548,10 @@ static int resolve_rfc4501(sd_bus *bus, const char *name) { } else n = p; - if (type == 0) - type = arg_type; - if (type == 0) - type = DNS_TYPE_A; - if (class == 0) - class = arg_class; - if (class == 0) - class = DNS_CLASS_IN; + class = arg_class ?: DNS_CLASS_IN; + if (type == 0) + type = arg_type ?: DNS_TYPE_A; return resolve_record(bus, n, class, type); @@ -763,6 +761,36 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons return 0; } +static int resolve_openpgp(sd_bus *bus, const char *address) { + const char *domain, *full; + int r; + _cleanup_free_ char *hashed = NULL; + + assert(bus); + assert(address); + + domain = strrchr(address, '@'); + if (!domain) { + log_error("Address does not contain '@': \"%s\"", address); + return -EINVAL; + } else if (domain == address || domain[1] == '\0') { + log_error("Address starts or ends with '@': \"%s\"", address); + return -EINVAL; + } + domain++; + + r = string_hashsum(address, domain - 1 - address, GCRY_MD_SHA224, &hashed); + if (r < 0) + return log_error_errno(r, "Hashing failed: %m"); + + full = strjoina(hashed, "._openpgpkey.", domain); + log_debug("Looking up \"%s\".", full); + + return resolve_record(bus, full, + arg_class ?: DNS_CLASS_IN, + arg_type ?: DNS_TYPE_OPENPGPKEY); +} + static int show_statistics(sd_bus *bus) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; @@ -945,6 +973,7 @@ static void help(void) { " --service Resolve service (SRV)\n" " --service-address=BOOL Do [not] resolve address for services\n" " --service-txt=BOOL Do [not] resolve TXT records for services\n" + " --openpgp Query OpenPGP public key\n" " --cname=BOOL Do [not] follow CNAME redirects\n" " --search=BOOL Do [not] use search domains\n" " --legend=BOOL Do [not] print column headers and meta information\n" @@ -961,6 +990,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_CNAME, ARG_SERVICE_ADDRESS, ARG_SERVICE_TXT, + ARG_OPENPGP, ARG_SEARCH, ARG_STATISTICS, ARG_RESET_STATISTICS, @@ -978,6 +1008,7 @@ static int parse_argv(int argc, char *argv[]) { { "service", no_argument, NULL, ARG_SERVICE }, { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS }, { "service-txt", required_argument, NULL, ARG_SERVICE_TXT }, + { "openpgp", no_argument, NULL, ARG_OPENPGP }, { "search", required_argument, NULL, ARG_SEARCH }, { "statistics", no_argument, NULL, ARG_STATISTICS, }, { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS }, @@ -1087,6 +1118,10 @@ static int parse_argv(int argc, char *argv[]) { arg_mode = MODE_RESOLVE_SERVICE; break; + case ARG_OPENPGP: + arg_mode = MODE_RESOLVE_OPENPGP; + break; + case ARG_CNAME: r = parse_boolean(optarg); if (r < 0) @@ -1246,6 +1281,24 @@ int main(int argc, char **argv) { break; + case MODE_RESOLVE_OPENPGP: + if (argc < optind + 1) { + log_error("E-mail address required."); + r = -EINVAL; + goto finish; + + } + + r = 0; + while (optind < argc) { + int k; + + k = resolve_openpgp(bus, argv[optind++]); + if (k < 0) + r = k; + } + break; + case MODE_STATISTICS: if (argc > optind) { log_error("Too many arguments."); diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index fc5e6beca0..6f08c43327 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -23,6 +23,7 @@ #include "dns-domain.h" #include "resolved-bus.h" #include "resolved-def.h" +#include "resolved-dns-synthesize.h" #include "resolved-link-bus.h" static int reply_query_state(DnsQuery *q) { @@ -233,6 +234,65 @@ static int check_ifindex_flags(int ifindex, uint64_t *flags, uint64_t ok, sd_bus return 0; } +static int parse_as_address(sd_bus_message *m, int ifindex, const char *hostname, int family, uint64_t flags) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_free_ char *canonical = NULL; + union in_addr_union parsed; + int r, ff; + + /* Check if the hostname is actually already an IP address formatted as string. In that case just parse it, + * let's not attempt to look it up. */ + + r = in_addr_from_string_auto(hostname, &ff, &parsed); + if (r < 0) /* not an address */ + return 0; + + if (family != AF_UNSPEC && ff != family) + return sd_bus_reply_method_errorf(m, BUS_ERROR_NO_SUCH_RR, "The specified address is not of the requested family."); + + r = sd_bus_message_new_method_return(m, &reply); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "(iiay)"); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'r', "iiay"); + if (r < 0) + return r; + + r = sd_bus_message_append(reply, "ii", ifindex, ff); + if (r < 0) + return r; + + r = sd_bus_message_append_array(reply, 'y', &parsed, FAMILY_ADDRESS_SIZE(ff)); + if (r < 0) + return r; + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + /* When an IP address is specified we just return it as canonical name, in order to avoid a DNS + * look-up. However, we reformat it to make sure it's in a truly canonical form (i.e. on IPv6 the inner + * omissions are always done the same way). */ + r = in_addr_to_string(ff, &parsed, &canonical); + if (r < 0) + return r; + + r = sd_bus_message_append(reply, "st", canonical, + SD_RESOLVED_FLAGS_MAKE(dns_synthesize_protocol(flags), ff, true)); + if (r < 0) + return r; + + return sd_bus_send(sd_bus_message_get_bus(m), reply, NULL); +} + static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL; Manager *m = userdata; @@ -254,15 +314,19 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); - r = dns_name_is_valid(hostname); + r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_SEARCH, error); if (r < 0) return r; - if (r == 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname); - r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_SEARCH, error); + r = parse_as_address(message, ifindex, hostname, family, flags); + if (r != 0) + return r; + + r = dns_name_is_valid(hostname); if (r < 0) return r; + if (r == 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname); r = dns_question_new_address(&question_utf8, family, hostname, false); if (r < 0) @@ -1198,7 +1262,7 @@ static int bus_property_get_dns_servers( return sd_bus_message_close_container(reply); } -static int bus_property_get_search_domains( +static int bus_property_get_domains( sd_bus *bus, const char *path, const char *interface, @@ -1396,8 +1460,8 @@ static int bus_method_set_link_dns_servers(sd_bus_message *message, void *userda return call_link_method(userdata, message, bus_link_method_set_dns_servers, error); } -static int bus_method_set_link_search_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) { - return call_link_method(userdata, message, bus_link_method_set_search_domains, error); +static int bus_method_set_link_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_set_domains, error); } static int bus_method_set_link_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) { @@ -1449,7 +1513,7 @@ static const sd_bus_vtable resolve_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), 0), SD_BUS_PROPERTY("DNS", "a(iiay)", bus_property_get_dns_servers, 0, 0), - SD_BUS_PROPERTY("SearchDomains", "a(isb)", bus_property_get_search_domains, 0, 0), + SD_BUS_PROPERTY("Domains", "a(isb)", bus_property_get_domains, 0, 0), SD_BUS_PROPERTY("TransactionStatistics", "(tt)", bus_property_get_transaction_statistics, 0, 0), SD_BUS_PROPERTY("CacheStatistics", "(ttt)", bus_property_get_cache_statistics, 0, 0), SD_BUS_PROPERTY("DNSSECStatistics", "(tttt)", bus_property_get_dnssec_statistics, 0, 0), @@ -1462,7 +1526,7 @@ static const sd_bus_vtable resolve_vtable[] = { SD_BUS_METHOD("ResetStatistics", NULL, NULL, bus_method_reset_statistics, 0), SD_BUS_METHOD("GetLink", "i", "o", bus_method_get_link, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, 0), - SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_search_domains, 0), + SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_domains, 0), SD_BUS_METHOD("SetLinkLLMNR", "is", NULL, bus_method_set_link_llmnr, 0), SD_BUS_METHOD("SetLinkMulticastDNS", "is", NULL, bus_method_set_link_mdns, 0), SD_BUS_METHOD("SetLinkDNSSEC", "is", NULL, bus_method_set_link_dnssec, 0), diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c index 7aea9cb653..7098265929 100644 --- a/src/resolve/resolved-dns-dnssec.c +++ b/src/resolve/resolved-dns-dnssec.c @@ -23,6 +23,7 @@ #include "alloc-util.h" #include "dns-domain.h" +#include "gcrypt-util.h" #include "hexdecoct.h" #include "resolved-dns-dnssec.h" #include "resolved-dns-packet.h" @@ -126,19 +127,6 @@ int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) { #ifdef HAVE_GCRYPT -static void initialize_libgcrypt(void) { - const char *p; - - if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) - return; - - p = gcry_check_version("1.4.5"); - assert(p); - - gcry_control(GCRYCTL_DISABLE_SECMEM); - gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); -} - static int rr_compare(const void *a, const void *b) { DnsResourceRecord **x = (DnsResourceRecord**) a, **y = (DnsResourceRecord**) b; size_t m; @@ -737,7 +725,7 @@ int dnssec_verify_rrset( qsort_safe(list, n, sizeof(DnsResourceRecord*), rr_compare); /* OK, the RRs are now in canonical order. Let's calculate the digest */ - initialize_libgcrypt(); + initialize_libgcrypt(false); hash_size = gcry_md_get_algo_dlen(md_algorithm); assert(hash_size > 0); @@ -1070,7 +1058,7 @@ int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds, if (dnssec_keytag(dnskey, mask_revoke) != ds->ds.key_tag) return 0; - initialize_libgcrypt(); + initialize_libgcrypt(false); md_algorithm = digest_to_gcrypt_md(ds->ds.digest_type); if (md_algorithm < 0) @@ -1189,7 +1177,7 @@ int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) { if (algorithm < 0) return algorithm; - initialize_libgcrypt(); + initialize_libgcrypt(false); hash_size = gcry_md_get_algo_dlen(algorithm); assert(hash_size > 0); diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index c940dd8929..c2fc1d8b05 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -28,6 +28,19 @@ #define EDNS0_OPT_DO (1<<15) +typedef struct DnsPacketRewinder { + DnsPacket *packet; + size_t saved_rindex; +} DnsPacketRewinder; + +static void rewind_dns_packet(DnsPacketRewinder *rewinder) { + if (rewinder->packet) + dns_packet_rewind(rewinder->packet, rewinder->saved_rindex); +} + +#define INIT_REWINDER(rewinder, p) do { rewinder.packet = p; rewinder.saved_rindex = p->rindex; } while(0) +#define CANCEL_REWINDER(rewinder) do { rewinder.packet = NULL; } while(0) + int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) { DnsPacket *p; size_t a; @@ -431,8 +444,7 @@ int dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_ ((uint8_t*) d)[0] = (uint8_t) size; - if (size > 0) - memcpy(((uint8_t*) d) + 1, s, size); + memcpy_safe(((uint8_t*) d) + 1, s, size); return 0; } @@ -1072,6 +1084,18 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star r = dns_packet_append_blob(p, rr->tlsa.data, rr->tlsa.data_size, NULL); break; + case DNS_TYPE_CAA: + r = dns_packet_append_uint8(p, rr->caa.flags, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_string(p, rr->caa.tag, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_blob(p, rr->caa.value, rr->caa.value_size, NULL); + break; + case DNS_TYPE_OPT: case DNS_TYPE_OPENPGPKEY: case _DNS_TYPE_INVALID: /* unparseable */ @@ -1230,80 +1254,67 @@ int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) { } int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) { - size_t saved_rindex; + _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder; const void *d; char *t; uint8_t c; int r; assert(p); - - saved_rindex = p->rindex; + INIT_REWINDER(rewinder, p); r = dns_packet_read_uint8(p, &c, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read(p, c, &d, NULL); if (r < 0) - goto fail; + return r; - if (memchr(d, 0, c)) { - r = -EBADMSG; - goto fail; - } + if (memchr(d, 0, c)) + return -EBADMSG; t = strndup(d, c); - if (!t) { - r = -ENOMEM; - goto fail; - } + if (!t) + return -ENOMEM; if (!utf8_is_valid(t)) { free(t); - r = -EBADMSG; - goto fail; + return -EBADMSG; } *ret = t; if (start) - *start = saved_rindex; + *start = rewinder.saved_rindex; + CANCEL_REWINDER(rewinder); return 0; - -fail: - dns_packet_rewind(p, saved_rindex); - return r; } int dns_packet_read_raw_string(DnsPacket *p, const void **ret, size_t *size, size_t *start) { - size_t saved_rindex; + _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder; uint8_t c; int r; assert(p); - - saved_rindex = p->rindex; + INIT_REWINDER(rewinder, p); r = dns_packet_read_uint8(p, &c, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read(p, c, ret, NULL); if (r < 0) - goto fail; + return r; if (size) *size = c; if (start) - *start = saved_rindex; + *start = rewinder.saved_rindex; + CANCEL_REWINDER(rewinder); return 0; - -fail: - dns_packet_rewind(p, saved_rindex); - return r; } int dns_packet_read_name( @@ -1312,7 +1323,8 @@ int dns_packet_read_name( bool allow_compression, size_t *start) { - size_t saved_rindex, after_rindex = 0, jump_barrier; + _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder; + size_t after_rindex = 0, jump_barrier; _cleanup_free_ char *ret = NULL; size_t n = 0, allocated = 0; bool first = true; @@ -1320,19 +1332,18 @@ int dns_packet_read_name( assert(p); assert(_ret); + INIT_REWINDER(rewinder, p); + jump_barrier = p->rindex; if (p->refuse_compression) allow_compression = false; - saved_rindex = p->rindex; - jump_barrier = p->rindex; - for (;;) { uint8_t c, d; r = dns_packet_read_uint8(p, &c, NULL); if (r < 0) - goto fail; + return r; if (c == 0) /* End of name */ @@ -1343,12 +1354,10 @@ int dns_packet_read_name( /* Literal label */ r = dns_packet_read(p, c, (const void**) &label, NULL); if (r < 0) - goto fail; + return r; - if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) + return -ENOMEM; if (first) first = false; @@ -1357,7 +1366,7 @@ int dns_packet_read_name( r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX); if (r < 0) - goto fail; + return r; n += r; continue; @@ -1367,13 +1376,11 @@ int dns_packet_read_name( /* Pointer */ r = dns_packet_read_uint8(p, &d, NULL); if (r < 0) - goto fail; + return r; ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d; - if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= jump_barrier) { - r = -EBADMSG; - goto fail; - } + if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= jump_barrier) + return -EBADMSG; if (after_rindex == 0) after_rindex = p->rindex; @@ -1381,16 +1388,12 @@ int dns_packet_read_name( /* Jumps are limited to a "prior occurrence" (RFC-1035 4.1.4) */ jump_barrier = ptr; p->rindex = ptr; - } else { - r = -EBADMSG; - goto fail; - } + } else + return -EBADMSG; } - if (!GREEDY_REALLOC(ret, allocated, n + 1)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(ret, allocated, n + 1)) + return -ENOMEM; ret[n] = 0; @@ -1401,13 +1404,10 @@ int dns_packet_read_name( ret = NULL; if (start) - *start = saved_rindex; + *start = rewinder.saved_rindex; + CANCEL_REWINDER(rewinder); return 0; - -fail: - dns_packet_rewind(p, saved_rindex); - return r; } static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *start) { @@ -1417,32 +1417,31 @@ static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *sta uint8_t bit = 0; unsigned i; bool found = false; - size_t saved_rindex; + _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder; int r; assert(p); assert(types); - - saved_rindex = p->rindex; + INIT_REWINDER(rewinder, p); r = bitmap_ensure_allocated(types); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &window, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &length, NULL); if (r < 0) - goto fail; + return r; if (length == 0 || length > 32) return -EBADMSG; r = dns_packet_read(p, length, (const void **)&bitmap, NULL); if (r < 0) - goto fail; + return r; for (i = 0; i < length; i++) { uint8_t bitmask = 1 << 7; @@ -1467,7 +1466,7 @@ static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *sta r = bitmap_set(*types, n); if (r < 0) - goto fail; + return r; } bit ++; @@ -1479,70 +1478,61 @@ static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *sta return -EBADMSG; if (start) - *start = saved_rindex; + *start = rewinder.saved_rindex; + CANCEL_REWINDER(rewinder); return 0; -fail: - dns_packet_rewind(p, saved_rindex); - return r; } static int dns_packet_read_type_windows(DnsPacket *p, Bitmap **types, size_t size, size_t *start) { - size_t saved_rindex; + _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder; int r; - saved_rindex = p->rindex; + INIT_REWINDER(rewinder, p); - while (p->rindex < saved_rindex + size) { + while (p->rindex < rewinder.saved_rindex + size) { r = dns_packet_read_type_window(p, types, NULL); if (r < 0) - goto fail; + return r; /* don't read past end of current RR */ - if (p->rindex > saved_rindex + size) { - r = -EBADMSG; - goto fail; - } + if (p->rindex > rewinder.saved_rindex + size) + return -EBADMSG; } - if (p->rindex != saved_rindex + size) { - r = -EBADMSG; - goto fail; - } + if (p->rindex != rewinder.saved_rindex + size) + return -EBADMSG; if (start) - *start = saved_rindex; + *start = rewinder.saved_rindex; + CANCEL_REWINDER(rewinder); return 0; -fail: - dns_packet_rewind(p, saved_rindex); - return r; } int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, bool *ret_cache_flush, size_t *start) { + _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder; _cleanup_free_ char *name = NULL; bool cache_flush = false; uint16_t class, type; DnsResourceKey *key; - size_t saved_rindex; int r; assert(p); assert(ret); - - saved_rindex = p->rindex; + INIT_REWINDER(rewinder, p); r = dns_packet_read_name(p, &name, true, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint16(p, &type, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint16(p, &class, NULL); if (r < 0) - goto fail; + return r; if (p->protocol == DNS_PROTOCOL_MDNS) { /* See RFC6762, Section 10.2 */ @@ -1554,10 +1544,8 @@ int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, bool *ret_cache_flus } key = dns_resource_key_new_consume(class, type, name); - if (!key) { - r = -ENOMEM; - goto fail; - } + if (!key) + return -ENOMEM; name = NULL; *ret = key; @@ -1565,12 +1553,10 @@ int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, bool *ret_cache_flus if (ret_cache_flush) *ret_cache_flush = cache_flush; if (start) - *start = saved_rindex; + *start = rewinder.saved_rindex; + CANCEL_REWINDER(rewinder); return 0; -fail: - dns_packet_rewind(p, saved_rindex); - return r; } static bool loc_size_ok(uint8_t size) { @@ -1582,7 +1568,8 @@ static bool loc_size_ok(uint8_t size) { int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_flush, size_t *start) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; - size_t saved_rindex, offset; + _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder; + size_t offset; uint16_t rdlength; bool cache_flush; int r; @@ -1590,27 +1577,22 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl assert(p); assert(ret); - saved_rindex = p->rindex; + INIT_REWINDER(rewinder, p); r = dns_packet_read_key(p, &key, &cache_flush, NULL); if (r < 0) - goto fail; + return r; - if (!dns_class_is_valid_rr(key->class)|| - !dns_type_is_valid_rr(key->type)) { - r = -EBADMSG; - goto fail; - } + if (!dns_class_is_valid_rr(key->class) || !dns_type_is_valid_rr(key->type)) + return -EBADMSG; rr = dns_resource_record_new(key); - if (!rr) { - r = -ENOMEM; - goto fail; - } + if (!rr) + return -ENOMEM; r = dns_packet_read_uint32(p, &rr->ttl, NULL); if (r < 0) - goto fail; + return r; /* RFC 2181, Section 8, suggests to * treat a TTL with the MSB set as a zero TTL. */ @@ -1619,12 +1601,10 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl r = dns_packet_read_uint16(p, &rdlength, NULL); if (r < 0) - goto fail; + return r; - if (p->rindex + rdlength > p->size) { - r = -EBADMSG; - goto fail; - } + if (p->rindex + rdlength > p->size) + return -EBADMSG; offset = p->rindex; @@ -1633,13 +1613,13 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl case DNS_TYPE_SRV: r = dns_packet_read_uint16(p, &rr->srv.priority, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint16(p, &rr->srv.weight, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint16(p, &rr->srv.port, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_name(p, &rr->srv.name, true, NULL); break; @@ -1653,7 +1633,7 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl case DNS_TYPE_HINFO: r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_string(p, &rr->hinfo.os, NULL); break; @@ -1709,27 +1689,27 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl case DNS_TYPE_SOA: r = dns_packet_read_name(p, &rr->soa.mname, true, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_name(p, &rr->soa.rname, true, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint32(p, &rr->soa.serial, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint32(p, &rr->soa.refresh, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint32(p, &rr->soa.retry, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint32(p, &rr->soa.expire, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint32(p, &rr->soa.minimum, NULL); break; @@ -1737,7 +1717,7 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl case DNS_TYPE_MX: r = dns_packet_read_uint16(p, &rr->mx.priority, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_name(p, &rr->mx.exchange, true, NULL); break; @@ -1748,49 +1728,43 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl r = dns_packet_read_uint8(p, &t, &pos); if (r < 0) - goto fail; + return r; if (t == 0) { rr->loc.version = t; r = dns_packet_read_uint8(p, &rr->loc.size, NULL); if (r < 0) - goto fail; + return r; - if (!loc_size_ok(rr->loc.size)) { - r = -EBADMSG; - goto fail; - } + if (!loc_size_ok(rr->loc.size)) + return -EBADMSG; r = dns_packet_read_uint8(p, &rr->loc.horiz_pre, NULL); if (r < 0) - goto fail; + return r; - if (!loc_size_ok(rr->loc.horiz_pre)) { - r = -EBADMSG; - goto fail; - } + if (!loc_size_ok(rr->loc.horiz_pre)) + return -EBADMSG; r = dns_packet_read_uint8(p, &rr->loc.vert_pre, NULL); if (r < 0) - goto fail; + return r; - if (!loc_size_ok(rr->loc.vert_pre)) { - r = -EBADMSG; - goto fail; - } + if (!loc_size_ok(rr->loc.vert_pre)) + return -EBADMSG; r = dns_packet_read_uint32(p, &rr->loc.latitude, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint32(p, &rr->loc.longitude, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint32(p, &rr->loc.altitude, NULL); if (r < 0) - goto fail; + return r; break; } else { @@ -1803,122 +1777,114 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl case DNS_TYPE_DS: r = dns_packet_read_uint16(p, &rr->ds.key_tag, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &rr->ds.algorithm, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &rr->ds.digest_type, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_memdup(p, rdlength - 4, &rr->ds.digest, &rr->ds.digest_size, NULL); if (r < 0) - goto fail; + return r; - if (rr->ds.digest_size <= 0) { + if (rr->ds.digest_size <= 0) /* the accepted size depends on the algorithm, but for now just ensure that the value is greater than zero */ - r = -EBADMSG; - goto fail; - } + return -EBADMSG; break; case DNS_TYPE_SSHFP: r = dns_packet_read_uint8(p, &rr->sshfp.algorithm, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &rr->sshfp.fptype, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_memdup(p, rdlength - 2, &rr->sshfp.fingerprint, &rr->sshfp.fingerprint_size, NULL); - if (rr->sshfp.fingerprint_size <= 0) { + if (rr->sshfp.fingerprint_size <= 0) /* the accepted size depends on the algorithm, but for now just ensure that the value is greater than zero */ - r = -EBADMSG; - goto fail; - } + return -EBADMSG; break; case DNS_TYPE_DNSKEY: r = dns_packet_read_uint16(p, &rr->dnskey.flags, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &rr->dnskey.protocol, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &rr->dnskey.algorithm, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_memdup(p, rdlength - 4, &rr->dnskey.key, &rr->dnskey.key_size, NULL); - if (rr->dnskey.key_size <= 0) { + if (rr->dnskey.key_size <= 0) /* the accepted size depends on the algorithm, but for now just ensure that the value is greater than zero */ - r = -EBADMSG; - goto fail; - } + return -EBADMSG; break; case DNS_TYPE_RRSIG: r = dns_packet_read_uint16(p, &rr->rrsig.type_covered, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &rr->rrsig.algorithm, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &rr->rrsig.labels, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint32(p, &rr->rrsig.original_ttl, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint32(p, &rr->rrsig.expiration, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint32(p, &rr->rrsig.inception, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint16(p, &rr->rrsig.key_tag, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_name(p, &rr->rrsig.signer, false, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_memdup(p, offset + rdlength - p->rindex, &rr->rrsig.signature, &rr->rrsig.signature_size, NULL); - if (rr->rrsig.signature_size <= 0) { + if (rr->rrsig.signature_size <= 0) /* the accepted size depends on the algorithm, but for now just ensure that the value is greater than zero */ - r = -EBADMSG; - goto fail; - } + return -EBADMSG; break; @@ -1933,11 +1899,9 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl r = dns_packet_read_name(p, &rr->nsec.next_domain_name, allow_compressed, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_type_windows(p, &rr->nsec.types, offset + rdlength - p->rindex, NULL); - if (r < 0) - goto fail; /* We accept empty NSEC bitmaps. The bit indicating the presence of the NSEC record itself * is redundant and in e.g., RFC4956 this fact is used to define a use for NSEC records @@ -1950,41 +1914,39 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl r = dns_packet_read_uint8(p, &rr->nsec3.algorithm, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &rr->nsec3.flags, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint16(p, &rr->nsec3.iterations, NULL); if (r < 0) - goto fail; + return r; /* this may be zero */ r = dns_packet_read_uint8(p, &size, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_memdup(p, size, &rr->nsec3.salt, &rr->nsec3.salt_size, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &size, NULL); if (r < 0) - goto fail; + return r; - if (size <= 0) { - r = -EBADMSG; - goto fail; - } + if (size <= 0) + return -EBADMSG; - r = dns_packet_read_memdup(p, size, &rr->nsec3.next_hashed_name, &rr->nsec3.next_hashed_name_size, NULL); + r = dns_packet_read_memdup(p, size, + &rr->nsec3.next_hashed_name, &rr->nsec3.next_hashed_name_size, + NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_type_windows(p, &rr->nsec3.types, offset + rdlength - p->rindex, NULL); - if (r < 0) - goto fail; /* empty non-terminals can have NSEC3 records, so empty bitmaps are allowed */ @@ -1994,25 +1956,39 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl case DNS_TYPE_TLSA: r = dns_packet_read_uint8(p, &rr->tlsa.cert_usage, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &rr->tlsa.selector, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &rr->tlsa.matching_type, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_memdup(p, rdlength - 3, &rr->tlsa.data, &rr->tlsa.data_size, NULL); - if (rr->tlsa.data_size <= 0) { + + if (rr->tlsa.data_size <= 0) /* the accepted size depends on the algorithm, but for now just ensure that the value is greater than zero */ - r = -EBADMSG; - goto fail; - } + return -EBADMSG; + + break; + + case DNS_TYPE_CAA: + r = dns_packet_read_uint8(p, &rr->caa.flags, NULL); + if (r < 0) + return r; + + r = dns_packet_read_string(p, &rr->caa.tag, NULL); + if (r < 0) + return r; + + r = dns_packet_read_memdup(p, + rdlength + offset - p->rindex, + &rr->caa.value, &rr->caa.value_size, NULL); break; @@ -2021,16 +1997,13 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl default: unparseable: r = dns_packet_read_memdup(p, rdlength, &rr->generic.data, &rr->generic.data_size, NULL); - if (r < 0) - goto fail; + break; } if (r < 0) - goto fail; - if (p->rindex != offset + rdlength) { - r = -EBADMSG; - goto fail; - } + return r; + if (p->rindex != offset + rdlength) + return -EBADMSG; *ret = rr; rr = NULL; @@ -2038,12 +2011,10 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl if (ret_cache_flush) *ret_cache_flush = cache_flush; if (start) - *start = saved_rindex; + *start = rewinder.saved_rindex; + CANCEL_REWINDER(rewinder); return 0; -fail: - dns_packet_rewind(p, saved_rindex); - return r; } static bool opt_is_good(DnsResourceRecord *rr, bool *rfc6975) { @@ -2091,23 +2062,21 @@ static bool opt_is_good(DnsResourceRecord *rr, bool *rfc6975) { int dns_packet_extract(DnsPacket *p) { _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL; _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; - size_t saved_rindex; + _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder = {}; unsigned n, i; int r; if (p->extracted) return 0; - saved_rindex = p->rindex; + INIT_REWINDER(rewinder, p); dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE); n = DNS_PACKET_QDCOUNT(p); if (n > 0) { question = dns_question_new(n); - if (!question) { - r = -ENOMEM; - goto finish; - } + if (!question) + return -ENOMEM; for (i = 0; i < n; i++) { _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; @@ -2115,21 +2084,17 @@ int dns_packet_extract(DnsPacket *p) { r = dns_packet_read_key(p, &key, &cache_flush, NULL); if (r < 0) - goto finish; + return r; - if (cache_flush) { - r = -EBADMSG; - goto finish; - } + if (cache_flush) + return -EBADMSG; - if (!dns_type_is_valid_query(key->type)) { - r = -EBADMSG; - goto finish; - } + if (!dns_type_is_valid_query(key->type)) + return -EBADMSG; r = dns_question_add(question, key); if (r < 0) - goto finish; + return r; } } @@ -2139,10 +2104,8 @@ int dns_packet_extract(DnsPacket *p) { bool bad_opt = false; answer = dns_answer_new(n); - if (!answer) { - r = -ENOMEM; - goto finish; - } + if (!answer) + return -ENOMEM; for (i = 0; i < n; i++) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; @@ -2150,7 +2113,7 @@ int dns_packet_extract(DnsPacket *p) { r = dns_packet_read_rr(p, &rr, &cache_flush, NULL); if (r < 0) - goto finish; + return r; /* Try to reduce memory usage a bit */ if (previous) @@ -2213,7 +2176,7 @@ int dns_packet_extract(DnsPacket *p) { (i < DNS_PACKET_ANCOUNT(p) ? DNS_ANSWER_CACHEABLE : 0) | (p->protocol == DNS_PROTOCOL_MDNS && !cache_flush ? DNS_ANSWER_SHARED_OWNER : 0)); if (r < 0) - goto finish; + return r; } /* Remember this RR, so that we potentically can merge it's ->key object with the next RR. Note @@ -2234,11 +2197,8 @@ int dns_packet_extract(DnsPacket *p) { p->extracted = true; - r = 0; - -finish: - p->rindex = saved_rindex; - return r; + /* no CANCEL, always rewind */ + return 0; } int dns_packet_is_reply_for(DnsPacket *p, const DnsResourceKey *key) { diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index 0bf34d270c..416335d0a2 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -262,11 +262,9 @@ static inline uint64_t SD_RESOLVED_FLAGS_MAKE(DnsProtocol protocol, int family, return f|(family == AF_INET6 ? SD_RESOLVED_LLMNR_IPV6 : SD_RESOLVED_LLMNR_IPV4); case DNS_PROTOCOL_MDNS: - return family == AF_INET6 ? SD_RESOLVED_MDNS_IPV6 : SD_RESOLVED_MDNS_IPV4; + return f|(family == AF_INET6 ? SD_RESOLVED_MDNS_IPV6 : SD_RESOLVED_MDNS_IPV4); default: - break; + return f; } - - return 0; } diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 40f8e28dfd..6397005a68 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -22,6 +22,7 @@ #include "alloc-util.h" #include "dns-domain.h" #include "dns-type.h" +#include "escape.h" #include "hexdecoct.h" #include "resolved-dns-dnssec.h" #include "resolved-dns-packet.h" @@ -490,6 +491,11 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) { free(rr->tlsa.data); break; + case DNS_TYPE_CAA: + free(rr->caa.tag); + free(rr->caa.value); + break; + case DNS_TYPE_OPENPGPKEY: default: free(rr->generic.data); @@ -697,6 +703,12 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor a->tlsa.matching_type == b->tlsa.matching_type && FIELD_EQUAL(a->tlsa, b->tlsa, data); + case DNS_TYPE_CAA: + return a->caa.flags == b->caa.flags && + streq(a->caa.tag, b->caa.tag) && + FIELD_EQUAL(a->caa, b->caa, value); + + case DNS_TYPE_OPENPGPKEY: default: return FIELD_EQUAL(a->generic, b->generic, data); } @@ -966,7 +978,7 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { case DNS_TYPE_DNSKEY: { _cleanup_free_ char *alg = NULL; char *ss; - int n, n1; + int n; uint16_t key_tag; key_tag = dnssec_keytag(rr, true); @@ -975,9 +987,8 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { if (r < 0) return NULL; - r = asprintf(&s, "%s %n%u %u %s %n", + r = asprintf(&s, "%s %u %u %s %n", k, - &n1, rr->dnskey.flags, rr->dnskey.protocol, alg, @@ -992,14 +1003,12 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { return NULL; r = asprintf(&ss, "%s\n" - "%*s-- Flags:%s%s%s\n" - "%*s-- Key tag: %u", + " -- Flags:%s%s%s\n" + " -- Key tag: %u", s, - n1, "", rr->dnskey.flags & DNSKEY_FLAG_SEP ? " SEP" : "", rr->dnskey.flags & DNSKEY_FLAG_REVOKE ? " REVOKE" : "", rr->dnskey.flags & DNSKEY_FLAG_ZONE_KEY ? " ZONE_KEY" : "", - n1, "", key_tag); if (r < 0) return NULL; @@ -1125,13 +1134,13 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { return NULL; r = asprintf(&ss, "%s\n" - "%*s-- Cert. usage: %s\n" - "%*s-- Selector: %s\n" - "%*s-- Matching type: %s", + " -- Cert. usage: %s\n" + " -- Selector: %s\n" + " -- Matching type: %s", s, - n - 6, "", cert_usage, - n - 6, "", selector, - n - 6, "", matching_type); + cert_usage, + selector, + matching_type); if (r < 0) return NULL; free(s); @@ -1140,6 +1149,28 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { break; } + case DNS_TYPE_CAA: { + _cleanup_free_ char *value; + + value = octescape(rr->caa.value, rr->caa.value_size); + if (!value) + return NULL; + + r = asprintf(&s, "%s %u %s \"%s\"%s%s%s%.0u", + k, + rr->caa.flags, + rr->caa.tag, + value, + rr->caa.flags ? "\n -- Flags:" : "", + rr->caa.flags & CAA_FLAG_CRITICAL ? " critical" : "", + rr->caa.flags & ~CAA_FLAG_CRITICAL ? " " : "", + rr->caa.flags & ~CAA_FLAG_CRITICAL); + if (r < 0) + return NULL; + + break; + } + case DNS_TYPE_OPENPGPKEY: { int n; @@ -1300,7 +1331,7 @@ int dns_resource_record_is_synthetic(DnsResourceRecord *rr) { return !r; } -static void dns_resource_record_hash_func(const void *i, struct siphash *state) { +void dns_resource_record_hash_func(const void *i, struct siphash *state) { const DnsResourceRecord *rr = i; assert(rr); @@ -1427,7 +1458,13 @@ static void dns_resource_record_hash_func(const void *i, struct siphash *state) siphash24_compress(&rr->tlsa.cert_usage, sizeof(rr->tlsa.cert_usage), state); siphash24_compress(&rr->tlsa.selector, sizeof(rr->tlsa.selector), state); siphash24_compress(&rr->tlsa.matching_type, sizeof(rr->tlsa.matching_type), state); - siphash24_compress(&rr->tlsa.data, rr->tlsa.data_size, state); + siphash24_compress(rr->tlsa.data, rr->tlsa.data_size, state); + break; + + case DNS_TYPE_CAA: + siphash24_compress(&rr->caa.flags, sizeof(rr->caa.flags), state); + string_hash_func(rr->caa.tag, state); + siphash24_compress(rr->caa.value, rr->caa.value_size, state); break; case DNS_TYPE_OPENPGPKEY: diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index 2e0dfbaba3..23749790b4 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -249,6 +249,14 @@ struct DnsResourceRecord { void *data; size_t data_size; } tlsa; + + /* https://tools.ietf.org/html/rfc6844 */ + struct { + uint8_t flags; + char *tag; + void *value; + size_t value_size; + } caa; }; }; @@ -323,6 +331,8 @@ int dns_resource_record_is_synthetic(DnsResourceRecord *rr); DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i); bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b); +void dns_resource_record_hash_func(const void *i, struct siphash *state); + extern const struct hash_ops dns_resource_key_hash_ops; extern const struct hash_ops dns_resource_record_hash_ops; diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c index df7516f4f4..7f21891819 100644 --- a/src/resolve/resolved-link-bus.c +++ b/src/resolve/resolved-link-bus.c @@ -239,7 +239,7 @@ clear: return r; } -int bus_link_method_set_search_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) { +int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) { Link *l = userdata; int r; @@ -457,10 +457,10 @@ const sd_bus_vtable link_vtable[] = { SD_BUS_PROPERTY("MulticastDNS", "s", property_get_resolve_support, offsetof(Link, mdns_support), 0), SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, offsetof(Link, dnssec_mode), 0), SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0), - SD_BUS_PROPERTY("DNSSECSupport", "b", property_get_dnssec_supported, 0, 0), + SD_BUS_PROPERTY("DNSSECSupported", "b", property_get_dnssec_supported, 0, 0), SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, 0), - SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_search_domains, 0), + SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_domains, 0), SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, 0), SD_BUS_METHOD("SetMulticastDNS", "s", NULL, bus_link_method_set_mdns, 0), SD_BUS_METHOD("SetDNSSEC", "s", NULL, bus_link_method_set_dnssec, 0), diff --git a/src/resolve/resolved-link-bus.h b/src/resolve/resolved-link-bus.h index 31e6cd2b45..646031b631 100644 --- a/src/resolve/resolved-link-bus.h +++ b/src/resolve/resolved-link-bus.h @@ -30,7 +30,7 @@ char *link_bus_path(Link *link); int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error); int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error); -int bus_link_method_set_search_domains(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error); diff --git a/src/resolve/test-data/_443._tcp.fedoraproject.org.pkts b/src/resolve/test-data/_443._tcp.fedoraproject.org.pkts Binary files differnew file mode 100644 index 0000000000..a383c6286d --- /dev/null +++ b/src/resolve/test-data/_443._tcp.fedoraproject.org.pkts diff --git a/src/resolve/test-data/_openpgpkey.fedoraproject.org.pkts b/src/resolve/test-data/_openpgpkey.fedoraproject.org.pkts Binary files differnew file mode 100644 index 0000000000..15de02e997 --- /dev/null +++ b/src/resolve/test-data/_openpgpkey.fedoraproject.org.pkts diff --git a/src/resolve/test-data/fake-caa.pkts b/src/resolve/test-data/fake-caa.pkts Binary files differnew file mode 100644 index 0000000000..1c3ecc5491 --- /dev/null +++ b/src/resolve/test-data/fake-caa.pkts diff --git a/src/resolve/test-data/fedoraproject.org.pkts b/src/resolve/test-data/fedoraproject.org.pkts Binary files differnew file mode 100644 index 0000000000..17874844d9 --- /dev/null +++ b/src/resolve/test-data/fedoraproject.org.pkts diff --git a/src/resolve/test-data/gandi.net.pkts b/src/resolve/test-data/gandi.net.pkts Binary files differnew file mode 100644 index 0000000000..5ef51e0c8e --- /dev/null +++ b/src/resolve/test-data/gandi.net.pkts diff --git a/src/resolve/test-data/google.com.pkts b/src/resolve/test-data/google.com.pkts Binary files differnew file mode 100644 index 0000000000..f98c4cd855 --- /dev/null +++ b/src/resolve/test-data/google.com.pkts diff --git a/src/resolve/test-data/kyhwana.org.pkts b/src/resolve/test-data/kyhwana.org.pkts Binary files differnew file mode 100644 index 0000000000..e28a725c9a --- /dev/null +++ b/src/resolve/test-data/kyhwana.org.pkts diff --git a/src/resolve/test-data/root.pkts b/src/resolve/test-data/root.pkts Binary files differnew file mode 100644 index 0000000000..54ba668c75 --- /dev/null +++ b/src/resolve/test-data/root.pkts diff --git a/src/resolve/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts b/src/resolve/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts Binary files differnew file mode 100644 index 0000000000..a854249532 --- /dev/null +++ b/src/resolve/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts diff --git a/src/resolve/test-data/teamits.com.pkts b/src/resolve/test-data/teamits.com.pkts Binary files differnew file mode 100644 index 0000000000..11deb39677 --- /dev/null +++ b/src/resolve/test-data/teamits.com.pkts diff --git a/src/resolve/test-data/zbyszek@fedoraproject.org.pkts b/src/resolve/test-data/zbyszek@fedoraproject.org.pkts Binary files differnew file mode 100644 index 0000000000..f0a6f982df --- /dev/null +++ b/src/resolve/test-data/zbyszek@fedoraproject.org.pkts diff --git a/src/resolve/test-dns-packet.c b/src/resolve/test-dns-packet.c new file mode 100644 index 0000000000..1abbd3fa2e --- /dev/null +++ b/src/resolve/test-dns-packet.c @@ -0,0 +1,115 @@ +/*** + This file is part of systemd + + Copyright 2016 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <net/if.h> +#include <glob.h> + +#include "alloc-util.h" +#include "fileio.h" +#include "glob-util.h" +#include "log.h" +#include "macro.h" +#include "resolved-dns-packet.h" +#include "resolved-dns-rr.h" +#include "string-util.h" +#include "strv.h" + +#define HASH_KEY SD_ID128_MAKE(d3,1e,48,90,4b,fa,4c,fe,af,9d,d5,a1,d7,2e,8a,b1) + +static uint64_t hash(DnsResourceRecord *rr) { + struct siphash state; + + siphash24_init(&state, HASH_KEY.bytes); + dns_resource_record_hash_func(rr, &state); + return siphash24_finalize(&state); +} + +static void test_packet_from_file(const char* filename, bool canonical) { + _cleanup_free_ char *data = NULL; + size_t data_size, packet_size, offset; + + assert_se(read_full_file(filename, &data, &data_size) >= 0); + assert_se(data); + assert_se(data_size > 8); + + log_info("============== %s %s==============", filename, canonical ? "canonical " : ""); + + for (offset = 0; offset < data_size; offset += 8 + packet_size) { + _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL, *p2 = NULL; + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL, *rr2 = NULL; + const char *s, *s2; + uint64_t hash1, hash2; + + packet_size = le64toh( *(uint64_t*)(data + offset) ); + assert_se(packet_size > 0); + assert_se(offset + 8 + packet_size <= data_size); + + assert_se(dns_packet_new(&p, DNS_PROTOCOL_DNS, 0) >= 0); + + assert_se(dns_packet_append_blob(p, data + offset + 8, packet_size, NULL) >= 0); + assert_se(dns_packet_read_rr(p, &rr, NULL, NULL) >= 0); + + s = dns_resource_record_to_string(rr); + assert_se(s); + puts(s); + + hash1 = hash(rr); + + assert_se(dns_resource_record_to_wire_format(rr, canonical) >= 0); + + assert_se(dns_packet_new(&p2, DNS_PROTOCOL_DNS, 0) >= 0); + assert_se(dns_packet_append_blob(p2, rr->wire_format, rr->wire_format_size, NULL) >= 0); + assert_se(dns_packet_read_rr(p2, &rr2, NULL, NULL) >= 0); + + s2 = dns_resource_record_to_string(rr); + assert_se(s2); + assert_se(streq(s, s2)); + + hash2 = hash(rr); + assert_se(hash1 == hash2); + } +} + +int main(int argc, char **argv) { + int i, N; + _cleanup_globfree_ glob_t g = {}; + _cleanup_strv_free_ char **globs = NULL; + char **fnames; + + log_parse_environment(); + + if (argc >= 2) { + N = argc - 1; + fnames = argv + 1; + } else { + assert_se(glob(RESOLVE_TEST_DIR "/*.pkts", GLOB_NOSORT, NULL, &g) == 0); + N = g.gl_pathc; + fnames = g.gl_pathv; + } + + for (i = 0; i < N; i++) { + test_packet_from_file(fnames[i], false); + puts(""); + test_packet_from_file(fnames[i], true); + if (i + 1 < N) + puts(""); + } + + return EXIT_SUCCESS; +} |