From 75f32f047cc380bdb648faf3ee277f7dc3cdd007 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 1 Feb 2016 21:57:41 -0500 Subject: Add memcpy_safe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ISO/IEC 9899:1999 §7.21.1/2 says: Where an argument declared as size_t n specifies the length of the array for a function, n can have the value zero on a call to that function. Unless explicitly stated otherwise in the description of a particular function in this subclause, pointer arguments on such a call shall still have valid values, as described in 7.1.4. In base64_append_width memcpy was called as memcpy(x, NULL, 0). GCC 4.9 started making use of this and assumes This worked fine under -O0, but does something strange under -O3. This patch fixes a bug in base64_append_width(), fixes a possible bug in journal_file_append_entry_internal(), and makes use of the new function to simplify the code in other places. --- src/basic/hexdecoct.c | 3 ++- src/basic/util.h | 10 ++++++++++ src/journal/journal-file.c | 6 +++--- src/libsystemd-network/dhcp-option.c | 7 +------ src/libsystemd-network/dhcp6-option.c | 3 +-- src/libsystemd-network/test-dhcp-option.c | 11 +++-------- src/libsystemd/sd-bus/bus-control.c | 3 +-- src/libsystemd/sd-bus/bus-message.c | 3 +-- src/libsystemd/sd-bus/bus-socket.c | 6 +++--- src/libsystemd/sd-resolve/sd-resolve.c | 5 ++--- src/nspawn/nspawn.c | 10 ++++------ src/resolve/resolved-dns-packet.c | 3 +-- 12 files changed, 32 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/basic/hexdecoct.c b/src/basic/hexdecoct.c index f30e028f45..cbd97a1b69 100644 --- a/src/basic/hexdecoct.c +++ b/src/basic/hexdecoct.c @@ -27,6 +27,7 @@ #include "alloc-util.h" #include "hexdecoct.h" #include "macro.h" +#include "util.h" char octchar(int x) { return '0' + (x & 7); @@ -574,7 +575,7 @@ static int base64_append_width(char **prefix, int plen, if (!t) return -ENOMEM; - memcpy(t + plen, sep, slen); + memcpy_safe(t + plen, sep, slen); for (line = 0, s = t + plen + slen, avail = len; line < lines; line++) { int act = MIN(width, avail); diff --git a/src/basic/util.h b/src/basic/util.h index 76a06822b7..b7bad76212 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -104,6 +104,16 @@ static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_ qsort(base, nmemb, size, compar); } +/** + * Normal memcpy requires src to be nonnull. We do nothing if n is 0. + */ +static inline void memcpy_safe(void *dst, const void *src, size_t n) { + if (n == 0) + return; + assert(src); + memcpy(dst, src, n); +} + int on_ac_power(void); #define memzero(x,l) (memset((x), 0, (l))) diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index 2973176c8d..da8039712f 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -1110,8 +1110,8 @@ static int journal_file_append_data( } #endif - if (compression == 0 && size > 0) - memcpy(o->data.payload, data, size); + if (compression == 0) + memcpy_safe(o->data.payload, data, size); r = journal_file_link_data(f, o, p, hash); if (r < 0) @@ -1373,7 +1373,7 @@ static int journal_file_append_entry_internal( return r; o->entry.seqnum = htole64(journal_file_entry_seqnum(f, seqnum)); - memcpy(o->entry.items, items, n_items * sizeof(EntryItem)); + memcpy_safe(o->entry.items, items, n_items * sizeof(EntryItem)); o->entry.realtime = htole64(ts->realtime); o->entry.monotonic = htole64(ts->monotonic); o->entry.xor_hash = htole64(xor_hash); diff --git a/src/libsystemd-network/dhcp-option.c b/src/libsystemd-network/dhcp-option.c index 9f0d96e57d..3ceb70f07e 100644 --- a/src/libsystemd-network/dhcp-option.c +++ b/src/libsystemd-network/dhcp-option.c @@ -56,12 +56,7 @@ static int option_append(uint8_t options[], size_t size, size_t *offset, options[*offset] = code; options[*offset + 1] = optlen; - if (optlen) { - assert(optval); - - memcpy(&options[*offset + 2], optval, optlen); - } - + memcpy_safe(&options[*offset + 2], optval, optlen); *offset += optlen + 2; break; diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index 6050851858..e858e14d97 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -73,8 +73,7 @@ int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code, if (r < 0) return r; - if (optval) - memcpy(*buf, optval, optlen); + memcpy_safe(*buf, optval, optlen); *buf += optlen; *buflen -= optlen; diff --git a/src/libsystemd-network/test-dhcp-option.c b/src/libsystemd-network/test-dhcp-option.c index 7b80a5bd90..45f4e0b5f5 100644 --- a/src/libsystemd-network/test-dhcp-option.c +++ b/src/libsystemd-network/test-dhcp-option.c @@ -112,14 +112,9 @@ static DHCPMessage *create_message(uint8_t *options, uint16_t optlen, message = malloc0(len); assert_se(message); - if (options && optlen) - memcpy(&message->options, options, optlen); - - if (file && filelen <= 128) - memcpy(&message->file, file, filelen); - - if (sname && snamelen <= 64) - memcpy(&message->sname, sname, snamelen); + memcpy_safe(&message->options, options, optlen); + memcpy_safe(&message->file, file, filelen); + memcpy_safe(&message->sname, sname, snamelen); return message; } diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c index ff628cfe72..00de2a95da 100644 --- a/src/libsystemd/sd-bus/bus-control.c +++ b/src/libsystemd/sd-bus/bus-control.c @@ -1133,8 +1133,7 @@ static int add_name_change_match(sd_bus *bus, item->name_change.old_id.id = old_owner_id; item->name_change.new_id.id = new_owner_id; - if (name) - memcpy(item->name_change.name, name, l); + memcpy_safe(item->name_change.name, name, l); /* If the old name is unset or empty, then * this can match against added names */ diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index e939359338..6fd0001359 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -2633,8 +2633,7 @@ _public_ int sd_bus_message_append_array( if (r < 0) return r; - if (size > 0) - memcpy(p, ptr, size); + memcpy_safe(p, ptr, size); return 0; } diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index 1df571ac92..4f99719231 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -352,7 +352,7 @@ static int bus_socket_auth_write(sd_bus *b, const char *t) { if (!p) return -ENOMEM; - memcpy(p, b->auth_iovec[0].iov_base, b->auth_iovec[0].iov_len); + memcpy_safe(p, b->auth_iovec[0].iov_base, b->auth_iovec[0].iov_len); memcpy(p + b->auth_iovec[0].iov_len, t, l); b->auth_iovec[0].iov_base = p; @@ -789,7 +789,7 @@ int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) { n = m->n_iovec * sizeof(struct iovec); iov = alloca(n); - memcpy(iov, m->iovec, n); + memcpy_safe(iov, m->iovec, n); j = 0; iovec_advance(iov, &j, *idx); @@ -1000,7 +1000,7 @@ int bus_socket_read_message(sd_bus *bus) { return -ENOMEM; } - memcpy(f + bus->n_fds, CMSG_DATA(cmsg), n * sizeof(int)); + memcpy_safe(f + bus->n_fds, CMSG_DATA(cmsg), n * sizeof(int)); bus->fds = f; bus->n_fds += n; } else diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c index d6e6f396d4..c3489cb02f 100644 --- a/src/libsystemd/sd-resolve/sd-resolve.c +++ b/src/libsystemd/sd-resolve/sd-resolve.c @@ -219,9 +219,8 @@ static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *leng memcpy((uint8_t*) p, &s, sizeof(AddrInfoSerialization)); memcpy((uint8_t*) p + sizeof(AddrInfoSerialization), ai->ai_addr, ai->ai_addrlen); - - if (ai->ai_canonname) - memcpy((char*) p + sizeof(AddrInfoSerialization) + ai->ai_addrlen, ai->ai_canonname, cnl); + memcpy_safe((char*) p + sizeof(AddrInfoSerialization) + ai->ai_addrlen, + ai->ai_canonname, cnl); *length += l; return (uint8_t*) p + l; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 9dd4c051b2..1c010b3b84 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -2580,12 +2580,10 @@ static int inner_child( /* Automatically search for the init system */ - m = 1 + strv_length(arg_parameters); - a = newa(char*, m + 1); - if (strv_isempty(arg_parameters)) - a[1] = NULL; - else - memcpy(a + 1, arg_parameters, m * sizeof(char*)); + m = strv_length(arg_parameters); + a = newa(char*, m + 2); + memcpy_safe(a + 1, arg_parameters, m * sizeof(char*)); + a[1 + m] = NULL; a[0] = (char*) "/usr/lib/systemd/systemd"; execve(a[0], a, env_use); diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 5cbe20832f..abb9725b73 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -433,8 +433,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; } -- cgit v1.2.3-54-g00ecf From 91e023d896dd5ca49dd440276f2241570acffd96 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 28 Jan 2016 18:24:27 -0500 Subject: Move initialize_libgcrypt to separate file It's annoying to have the exact same function in three places. It's stored in src/shared, but it's not added to the library to avoid the dependency on libgcrypt. --- Makefile.am | 8 ++++++-- src/journal/fsprg.c | 25 ++++++------------------ src/journal/journal-authenticate.c | 15 ++------------ src/resolve/resolved-dns-dnssec.c | 20 ++++--------------- src/shared/gcrypt-util.c | 40 ++++++++++++++++++++++++++++++++++++++ src/shared/gcrypt-util.h | 24 +++++++++++++++++++++++ 6 files changed, 82 insertions(+), 50 deletions(-) create mode 100644 src/shared/gcrypt-util.c create mode 100644 src/shared/gcrypt-util.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index db95b109ce..d2cf9360ed 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4274,7 +4274,9 @@ libsystemd_journal_internal_la_SOURCES += \ src/journal/journal-authenticate.c \ src/journal/journal-authenticate.h \ src/journal/fsprg.c \ - src/journal/fsprg.h + src/journal/fsprg.h \ + src/shared/gcrypt-util.c \ + src/shared/gcrypt-util.h libsystemd_journal_internal_la_LIBADD += \ $(GCRYPT_LIBS) @@ -5216,7 +5218,9 @@ systemd_resolved_SOURCES = \ src/resolve/resolved-etc-hosts.h \ src/resolve/resolved-etc-hosts.c \ src/resolve/dns-type.c \ - src/resolve/dns-type.h + src/resolve/dns-type.h \ + src/shared/gcrypt-util.c \ + src/shared/gcrypt-util.h nodist_systemd_resolved_SOURCES = \ src/resolve/dns_type-from-name.h \ diff --git a/src/journal/fsprg.c b/src/journal/fsprg.c index a9f564c249..12ae7449f9 100644 --- a/src/journal/fsprg.c +++ b/src/journal/fsprg.c @@ -32,6 +32,7 @@ #include #include "fsprg.h" +#include "gcrypt-util.h" #define ISVALID_SECPAR(secpar) (((secpar) % 16 == 0) && ((secpar) >= 16) && ((secpar) <= 16384)) #define VALIDATE_SECPAR(secpar) assert(ISVALID_SECPAR(secpar)); @@ -208,20 +209,6 @@ static void CRT_compose(gcry_mpi_t *x, const gcry_mpi_t xp, const gcry_mpi_t xq, gcry_mpi_release(u); } -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); - - /* Turn off "secmem". Clients which whish to make use of this - * feature should initialize the library manually */ - gcry_control(GCRYCTL_DISABLE_SECMEM); - gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); -} - /******************************************************************************/ size_t FSPRG_mskinbytes(unsigned _secpar) { @@ -261,7 +248,7 @@ void FSPRG_GenMK(void *msk, void *mpk, const void *seed, size_t seedlen, unsigne VALIDATE_SECPAR(_secpar); secpar = _secpar; - initialize_libgcrypt(); + initialize_libgcrypt(false); if (!seed) { gcry_randomize(iseed, FSPRG_RECOMMENDED_SEEDLEN, GCRY_STRONG_RANDOM); @@ -297,7 +284,7 @@ void FSPRG_GenState0(void *state, const void *mpk, const void *seed, size_t seed gcry_mpi_t n, x; uint16_t secpar; - initialize_libgcrypt(); + initialize_libgcrypt(false); secpar = read_secpar(mpk + 0); n = mpi_import(mpk + 2, secpar / 8); @@ -316,7 +303,7 @@ void FSPRG_Evolve(void *state) { uint16_t secpar; uint64_t epoch; - initialize_libgcrypt(); + initialize_libgcrypt(false); secpar = read_secpar(state + 0); n = mpi_import(state + 2 + 0 * secpar / 8, secpar / 8); @@ -343,7 +330,7 @@ void FSPRG_Seek(void *state, uint64_t epoch, const void *msk, const void *seed, gcry_mpi_t p, q, n, x, xp, xq, kp, kq, xm; uint16_t secpar; - initialize_libgcrypt(); + initialize_libgcrypt(false); secpar = read_secpar(msk + 0); p = mpi_import(msk + 2 + 0 * (secpar / 2) / 8, (secpar / 2) / 8); @@ -382,7 +369,7 @@ void FSPRG_Seek(void *state, uint64_t epoch, const void *msk, const void *seed, void FSPRG_GetKey(const void *state, void *key, size_t keylen, uint32_t idx) { uint16_t secpar; - initialize_libgcrypt(); + initialize_libgcrypt(false); secpar = read_secpar(state + 0); det_randomize(key, keylen, state + 2, 2 * secpar / 8 + 8, idx); diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c index aeec83da1e..45d7f4b340 100644 --- a/src/journal/journal-authenticate.c +++ b/src/journal/journal-authenticate.c @@ -24,6 +24,7 @@ #include "fd-util.h" #include "fsprg.h" +#include "gcrypt-util.h" #include "hexdecoct.h" #include "journal-authenticate.h" #include "journal-def.h" @@ -426,25 +427,13 @@ finish: return r; } -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_INITIALIZATION_FINISHED, 0); -} - int journal_file_hmac_setup(JournalFile *f) { gcry_error_t e; if (!f->seal) return 0; - initialize_libgcrypt(); + initialize_libgcrypt(true); e = gcry_md_open(&f->hmac, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); if (e != 0) diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c index 21cf161494..f799379efd 100644 --- a/src/resolve/resolved-dns-dnssec.c +++ b/src/resolve/resolved-dns-dnssec.c @@ -25,6 +25,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" @@ -128,19 +129,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; @@ -739,7 +727,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); @@ -1072,7 +1060,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) @@ -1191,7 +1179,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/shared/gcrypt-util.c b/src/shared/gcrypt-util.c new file mode 100644 index 0000000000..3bbc161ef2 --- /dev/null +++ b/src/shared/gcrypt-util.c @@ -0,0 +1,40 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + 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 . +***/ + +#include + +#include "hexdecoct.h" +#include "gcrypt-util.h" + +void initialize_libgcrypt(bool secmem) { + const char *p; + if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) + return; + + p = gcry_check_version("1.4.5"); + assert(p); + + /* Turn off "secmem". Clients which whish to make use of this + * feature should initialize the library manually */ + if (!secmem) + gcry_control(GCRYCTL_DISABLE_SECMEM); + gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); +} diff --git a/src/shared/gcrypt-util.h b/src/shared/gcrypt-util.h new file mode 100644 index 0000000000..42ce3fd121 --- /dev/null +++ b/src/shared/gcrypt-util.h @@ -0,0 +1,24 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + 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 . +***/ + +#include + +void initialize_libgcrypt(bool secmem); -- cgit v1.2.3-54-g00ecf From 4ac2ca1bdb8ff0e862927c3e1162c3686449c50a Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 28 Jan 2016 18:24:27 -0500 Subject: systemd-resolve: allow easy querying of openpgp keys $ systemd-resolve --openpgp zbyszek@fedoraproject.org d08ee310438ca124a6149ea5cc21b6313b390dce485576eff96f8722._openpgpkey.fedoraproject.org. IN OPENPGPKEY mQINBFBHPMsBEACeInGYJCb+7TurKfb6wGyTottCDtiSJB310i37/6ZYoeIay/5soJjlM yfMFQ9T2XNT/0LM6gTa0MpC1st9LnzYTMsT6tzRly1D1UbVI6xw0g0vE5y2Cjk3xUwAyn ... --- Makefile.am | 4 ++- man/systemd-resolve.xml | 19 +++++++++++++ src/resolve/resolve-tool.c | 69 ++++++++++++++++++++++++++++++++++++++++------ src/shared/gcrypt-util.c | 29 +++++++++++++++++++ src/shared/gcrypt-util.h | 1 + 5 files changed, 113 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/Makefile.am b/Makefile.am index d2cf9360ed..e63015476c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5291,7 +5291,9 @@ systemd_resolve_SOURCES = \ src/resolve/resolved-dns-question.c \ src/resolve/resolved-dns-question.h \ src/resolve/dns-type.c \ - src/resolve/dns-type.h + src/resolve/dns-type.h \ + src/shared/gcrypt-util.c \ + src/shared/gcrypt-util.h nodist_systemd_resolve_SOURCES = \ src/resolve/dns_type-from-name.h \ diff --git a/man/systemd-resolve.xml b/man/systemd-resolve.xml index f1e663c5bb..0defa2d7fb 100644 --- a/man/systemd-resolve.xml +++ b/man/systemd-resolve.xml @@ -76,6 +76,13 @@ TYPE DOMAIN + + systemd-resolve + OPTIONS + --openpgp + USER@DOMAIN + + systemd-resolve OPTIONS @@ -114,6 +121,10 @@ is assumed to be a domain name, that is already prefixed with an SRV type, and an SRV lookup is done (no TXT). + The switch may be use to query PGP keys stored as the + OPENPGPKEY resource records. + When this option is specified one or more e-mail address must be specified. + The switch may be used to show resolver statistics, including information about the number of succesful and failed DNSSEC validations. @@ -197,6 +208,14 @@ the TXT service metadata record is resolved as well. + + + + Enables OPENPGPKEY resource record resolution (see above). Specified e-mail + addresses are converted to the corresponding DNS domain name, and any OPENPGPKEY keys are + printed. + + BOOL diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index 9bee953839..6d1bc6d0f9 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -19,6 +19,7 @@ along with systemd; If not, see . ***/ +#include #include #include @@ -30,6 +31,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" @@ -48,6 +50,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; @@ -547,15 +550,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); @@ -765,6 +763,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; @@ -947,6 +975,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" @@ -963,6 +992,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, @@ -980,6 +1010,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 }, @@ -1089,6 +1120,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) @@ -1248,6 +1283,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/shared/gcrypt-util.c b/src/shared/gcrypt-util.c index 3bbc161ef2..b887243849 100644 --- a/src/shared/gcrypt-util.c +++ b/src/shared/gcrypt-util.c @@ -38,3 +38,32 @@ void initialize_libgcrypt(bool secmem) { gcry_control(GCRYCTL_DISABLE_SECMEM); gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); } + +int string_hashsum(const char *s, size_t len, int md_algorithm, char **out) { + gcry_md_hd_t md = NULL; + size_t hash_size; + void *hash; + char *enc; + + initialize_libgcrypt(false); + + hash_size = gcry_md_get_algo_dlen(md_algorithm); + assert(hash_size > 0); + + gcry_md_open(&md, md_algorithm, 0); + if (!md) + return -EIO; + + gcry_md_write(md, s, len); + + hash = gcry_md_read(md, 0); + if (!hash) + return -EIO; + + enc = hexmem(hash, hash_size); + if (!enc) + return -ENOMEM; + + *out = enc; + return 0; +} diff --git a/src/shared/gcrypt-util.h b/src/shared/gcrypt-util.h index 42ce3fd121..c7652c22d1 100644 --- a/src/shared/gcrypt-util.h +++ b/src/shared/gcrypt-util.h @@ -22,3 +22,4 @@ #include void initialize_libgcrypt(bool secmem); +int string_hashsum(const char *s, size_t len, int md_algorithm, char **out); -- cgit v1.2.3-54-g00ecf From e18a3c7314ddfabd3d6eabad4a32d6e571e2ec42 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 30 Jan 2016 16:42:16 -0500 Subject: resolved: add cleanup function to rewind packets This makes the behaviour more consistent. Before we would not rewind after some errors, but this seems to have been an unintentional omission. --- src/resolve/resolved-dns-packet.c | 422 ++++++++++++++++---------------------- 1 file changed, 178 insertions(+), 244 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index abb9725b73..6a9a1f732d 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -30,6 +30,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; @@ -1231,80 +1244,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( @@ -1313,7 +1313,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; @@ -1321,19 +1322,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 */ @@ -1344,12 +1344,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; @@ -1358,7 +1356,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; @@ -1368,13 +1366,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; @@ -1382,16 +1378,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; @@ -1402,13 +1394,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) { @@ -1418,32 +1407,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; @@ -1468,7 +1456,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 ++; @@ -1480,70 +1468,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 */ @@ -1555,10 +1534,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; @@ -1566,12 +1543,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) { @@ -1583,7 +1558,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; @@ -1591,27 +1567,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. */ @@ -1620,12 +1591,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; @@ -1634,13 +1603,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; @@ -1654,7 +1623,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; @@ -1710,27 +1679,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; @@ -1738,7 +1707,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; @@ -1749,49 +1718,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 { @@ -1804,122 +1767,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; @@ -1934,11 +1889,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 @@ -1951,41 +1904,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 */ @@ -1995,25 +1946,24 @@ 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; @@ -2022,16 +1972,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; @@ -2039,12 +1986,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) { @@ -2092,23 +2037,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; @@ -2116,21 +2059,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; } } @@ -2140,10 +2079,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; @@ -2151,7 +2088,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) @@ -2214,7 +2151,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 @@ -2235,11 +2172,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) { -- cgit v1.2.3-54-g00ecf From 6d99904f5a263cc119ac79718d83d7136dde349d Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 31 Jan 2016 00:10:42 -0500 Subject: test-dns-packet: add framework to read and dump packets Packets are stored in a simple format: ... Packets for some example domains are dumped, to test rr code for various record types. Currently: A AAAA CAA DNSKEY LOC MX NS NSEC OPENPGPKEY SOA SPF TXT The hashing code is executed, but results are not checked. Also build other tests in src/resolve only with --enable-resolve. --- .gitignore | 1 + Makefile.am | 91 ++++++++++--------- src/resolve/resolved-dns-rr.c | 2 +- src/resolve/resolved-dns-rr.h | 2 + .../test-data/_openpgpkey.fedoraproject.org.pkts | Bin 0 -> 986 bytes src/resolve/test-data/fedoraproject.org.pkts | Bin 0 -> 1483 bytes src/resolve/test-data/gandi.net.pkts | Bin 0 -> 1010 bytes src/resolve/test-data/google.com.pkts | Bin 0 -> 747 bytes src/resolve/test-data/root.pkts | Bin 0 -> 1061 bytes ...sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts | Bin 0 -> 330 bytes src/resolve/test-data/teamits.com.pkts | Bin 0 -> 1021 bytes .../test-data/zbyszek@fedoraproject.org.pkts | Bin 0 -> 2533 bytes src/resolve/test-dns-packet.c | 100 +++++++++++++++++++++ 13 files changed, 149 insertions(+), 47 deletions(-) create mode 100644 src/resolve/test-data/_openpgpkey.fedoraproject.org.pkts create mode 100644 src/resolve/test-data/fedoraproject.org.pkts create mode 100644 src/resolve/test-data/gandi.net.pkts create mode 100644 src/resolve/test-data/google.com.pkts create mode 100644 src/resolve/test-data/root.pkts create mode 100644 src/resolve/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts create mode 100644 src/resolve/test-data/teamits.com.pkts create mode 100644 src/resolve/test-data/zbyszek@fedoraproject.org.pkts create mode 100644 src/resolve/test-dns-packet.c (limited to 'src') diff --git a/.gitignore b/.gitignore index 586b3796b1..81b97c4add 100644 --- a/.gitignore +++ b/.gitignore @@ -184,6 +184,7 @@ /test-dhcp-server /test-dhcp6-client /test-dns-domain +/test-dns-packet /test-dnssec /test-efi-disk.img /test-ellipsize diff --git a/Makefile.am b/Makefile.am index e63015476c..4e6a27a77d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1501,6 +1501,7 @@ tests += \ test-af-list \ test-arphrd-list \ test-dns-domain \ + test-dns-packet \ test-resolve-tables \ test-install-root \ test-rlimit-util \ @@ -1666,16 +1667,6 @@ 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 += \ @@ -5166,6 +5157,20 @@ EXTRA_DIST += \ # ------------------------------------------------------------------------------ if ENABLE_RESOLVED +basic_dns_sources = \ + 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 \ + src/resolve/resolved-dns-rr.h \ + src/resolve/resolved-dns-answer.c \ + src/resolve/resolved-dns-answer.h \ + src/resolve/resolved-dns-question.c \ + src/resolve/resolved-dns-question.h \ + src/resolve/dns-type.c \ + src/resolve/dns-type.h + systemd_resolved_SOURCES = \ src/resolve/resolved.c \ src/resolve/resolved-manager.c \ @@ -5185,14 +5190,7 @@ systemd_resolved_SOURCES = \ src/resolve/resolved-mdns.h \ src/resolve/resolved-mdns.c \ src/resolve/resolved-def.h \ - src/resolve/resolved-dns-rr.h \ - src/resolve/resolved-dns-rr.c \ - src/resolve/resolved-dns-question.h \ - src/resolve/resolved-dns-question.c \ - src/resolve/resolved-dns-answer.h \ - src/resolve/resolved-dns-answer.c \ - src/resolve/resolved-dns-packet.h \ - src/resolve/resolved-dns-packet.c \ + $(basic_dns_sources) \ src/resolve/resolved-dns-query.h \ src/resolve/resolved-dns-query.c \ src/resolve/resolved-dns-synthesize.h \ @@ -5211,14 +5209,10 @@ systemd_resolved_SOURCES = \ src/resolve/resolved-dns-zone.c \ src/resolve/resolved-dns-stream.h \ src/resolve/resolved-dns-stream.c \ - src/resolve/resolved-dns-dnssec.h \ - src/resolve/resolved-dns-dnssec.c \ src/resolve/resolved-dns-trust-anchor.h \ src/resolve/resolved-dns-trust-anchor.c \ src/resolve/resolved-etc-hosts.h \ src/resolve/resolved-etc-hosts.c \ - src/resolve/dns-type.c \ - src/resolve/dns-type.h \ src/shared/gcrypt-util.c \ src/shared/gcrypt-util.h @@ -5280,18 +5274,7 @@ 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 \ - src/resolve/resolved-dns-rr.h \ - src/resolve/resolved-dns-answer.c \ - src/resolve/resolved-dns-answer.h \ - src/resolve/resolved-dns-question.c \ - src/resolve/resolved-dns-question.h \ - src/resolve/dns-type.c \ - src/resolve/dns-type.h \ + $(basic_dns_sources) \ src/shared/gcrypt-util.c \ src/shared/gcrypt-util.h @@ -5312,20 +5295,36 @@ tests += \ manual_tests += \ test-dnssec-complex +test_resolve_tables_SOURCES = \ + src/resolve/test-resolve-tables.c \ + src/resolve/dns_type-from-name.h \ + src/resolve/dns_type-to-name.h \ + $(basic_dns_sources) \ + src/shared/test-tables.h + +test_resolve_tables_LDADD = \ + libshared.la + +test_dns_packet_SOURCES = \ + src/resolve/test-dns-packet.c \ + $(basic_dns_sources) + +test_dns_packet_LDADD = \ + libshared.la + +EXTRA_DIST += \ + src/resolve/test-data/_openpgpkey.fedoraproject.org.pkts \ + src/resolve/test-data/fedoraproject.org.pkts \ + src/resolve/test-data/gandi.net.pkts \ + src/resolve/test-data/google.com.pkts \ + src/resolve/test-data/root.pkts \ + src/resolve/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts \ + src/resolve/test-data/teamits.com.pkts \ + src/resolve/test-data/zbyszek@fedoraproject.org.pkts + test_dnssec_SOURCES = \ src/resolve/test-dnssec.c \ - src/resolve/resolved-dns-packet.c \ - src/resolve/resolved-dns-packet.h \ - src/resolve/resolved-dns-rr.c \ - src/resolve/resolved-dns-rr.h \ - src/resolve/resolved-dns-answer.c \ - src/resolve/resolved-dns-answer.h \ - src/resolve/resolved-dns-question.c \ - src/resolve/resolved-dns-question.h \ - src/resolve/resolved-dns-dnssec.c \ - src/resolve/resolved-dns-dnssec.h \ - src/resolve/dns-type.c \ - src/resolve/dns-type.h + $(basic_dns_sources) test_dnssec_LDADD = \ libshared.la diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 783ec7516c..2803ec017e 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -1302,7 +1302,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); diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index 37c4487332..01c7091645 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -325,6 +325,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/test-data/_openpgpkey.fedoraproject.org.pkts b/src/resolve/test-data/_openpgpkey.fedoraproject.org.pkts new file mode 100644 index 0000000000..15de02e997 Binary files /dev/null and b/src/resolve/test-data/_openpgpkey.fedoraproject.org.pkts differ diff --git a/src/resolve/test-data/fedoraproject.org.pkts b/src/resolve/test-data/fedoraproject.org.pkts new file mode 100644 index 0000000000..17874844d9 Binary files /dev/null and b/src/resolve/test-data/fedoraproject.org.pkts differ diff --git a/src/resolve/test-data/gandi.net.pkts b/src/resolve/test-data/gandi.net.pkts new file mode 100644 index 0000000000..5ef51e0c8e Binary files /dev/null and b/src/resolve/test-data/gandi.net.pkts differ diff --git a/src/resolve/test-data/google.com.pkts b/src/resolve/test-data/google.com.pkts new file mode 100644 index 0000000000..f98c4cd855 Binary files /dev/null and b/src/resolve/test-data/google.com.pkts differ diff --git a/src/resolve/test-data/root.pkts b/src/resolve/test-data/root.pkts new file mode 100644 index 0000000000..54ba668c75 Binary files /dev/null and b/src/resolve/test-data/root.pkts differ 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 new file mode 100644 index 0000000000..a854249532 Binary files /dev/null and b/src/resolve/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts differ diff --git a/src/resolve/test-data/teamits.com.pkts b/src/resolve/test-data/teamits.com.pkts new file mode 100644 index 0000000000..11deb39677 Binary files /dev/null and b/src/resolve/test-data/teamits.com.pkts differ diff --git a/src/resolve/test-data/zbyszek@fedoraproject.org.pkts b/src/resolve/test-data/zbyszek@fedoraproject.org.pkts new file mode 100644 index 0000000000..f0a6f982df Binary files /dev/null and b/src/resolve/test-data/zbyszek@fedoraproject.org.pkts differ diff --git a/src/resolve/test-dns-packet.c b/src/resolve/test-dns-packet.c new file mode 100644 index 0000000000..d8a5d9bbef --- /dev/null +++ b/src/resolve/test-dns-packet.c @@ -0,0 +1,100 @@ +/*** + 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 . +***/ + +#include + +#include "alloc-util.h" +#include "fileio.h" +#include "macro.h" +#include "log.h" +#include "resolved-dns-packet.h" +#include "resolved-dns-rr.h" +#include "string-util.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; + + log_parse_environment(); + + for (i = 1; i < argc; i++) { + test_packet_from_file(argv[i], false); + puts(""); + test_packet_from_file(argv[i], true); + if (i + 1 < argc) + puts(""); + } + + return EXIT_SUCCESS; +} -- cgit v1.2.3-54-g00ecf From fff85dbe15475c35fed2af66fabef3bdfb94f389 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 11 Feb 2016 09:18:32 -0500 Subject: test-dns-packet: allow running without arguments --- Makefile.am | 4 ++++ src/resolve/test-dns-packet.c | 27 +++++++++++++++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 4e6a27a77d..754772156c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5309,6 +5309,10 @@ test_dns_packet_SOURCES = \ src/resolve/test-dns-packet.c \ $(basic_dns_sources) +test_dns_packet_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DRESOLVE_TEST_DIR=\"$(abs_top_srcdir)/src/resolve/test-data\" + test_dns_packet_LDADD = \ libshared.la diff --git a/src/resolve/test-dns-packet.c b/src/resolve/test-dns-packet.c index d8a5d9bbef..1abbd3fa2e 100644 --- a/src/resolve/test-dns-packet.c +++ b/src/resolve/test-dns-packet.c @@ -18,14 +18,17 @@ ***/ #include +#include #include "alloc-util.h" #include "fileio.h" -#include "macro.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) @@ -84,15 +87,27 @@ static void test_packet_from_file(const char* filename, bool canonical) { } int main(int argc, char **argv) { - int i; + int i, N; + _cleanup_globfree_ glob_t g = {}; + _cleanup_strv_free_ char **globs = NULL; + char **fnames; log_parse_environment(); - for (i = 1; i < argc; i++) { - test_packet_from_file(argv[i], false); + 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(argv[i], true); - if (i + 1 < argc) + test_packet_from_file(fnames[i], true); + if (i + 1 < N) puts(""); } -- cgit v1.2.3-54-g00ecf From fa45182ed6b833017dde5a7cee27cdf25985790a Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 31 Jan 2016 16:23:00 -0500 Subject: Fix hashing of TLSA packets Also add example files with TLSA and SSHFP records. --- Makefile.am | 4 +++- src/resolve/resolved-dns-rr.c | 2 +- src/resolve/test-data/_443._tcp.fedoraproject.org.pkts | Bin 0 -> 169 bytes src/resolve/test-data/kyhwana.org.pkts | Bin 0 -> 1803 bytes 4 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 src/resolve/test-data/_443._tcp.fedoraproject.org.pkts create mode 100644 src/resolve/test-data/kyhwana.org.pkts (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 754772156c..8ab04e74ba 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5324,7 +5324,9 @@ EXTRA_DIST += \ src/resolve/test-data/root.pkts \ src/resolve/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts \ src/resolve/test-data/teamits.com.pkts \ - src/resolve/test-data/zbyszek@fedoraproject.org.pkts + src/resolve/test-data/zbyszek@fedoraproject.org.pkts \ + src/resolve/test-data/_443._tcp.fedoraproject.org.pkts \ + src/resolve/test-data/kyhwana.org.pkts test_dnssec_SOURCES = \ src/resolve/test-dnssec.c \ diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 2803ec017e..422bbe4bc4 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -1429,7 +1429,7 @@ 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_OPENPGPKEY: diff --git a/src/resolve/test-data/_443._tcp.fedoraproject.org.pkts b/src/resolve/test-data/_443._tcp.fedoraproject.org.pkts new file mode 100644 index 0000000000..a383c6286d Binary files /dev/null and b/src/resolve/test-data/_443._tcp.fedoraproject.org.pkts differ diff --git a/src/resolve/test-data/kyhwana.org.pkts b/src/resolve/test-data/kyhwana.org.pkts new file mode 100644 index 0000000000..e28a725c9a Binary files /dev/null and b/src/resolve/test-data/kyhwana.org.pkts differ -- cgit v1.2.3-54-g00ecf From 95052df3760523e1f3bb9705c918d85aae7fb431 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 31 Jan 2016 16:21:00 -0500 Subject: resolve: parse CAA records --- src/basic/escape.c | 28 ++++++++++++++++++++++++++++ src/basic/escape.h | 1 + src/resolve/resolved-dns-packet.c | 27 +++++++++++++++++++++++++++ src/resolve/resolved-dns-rr.c | 36 ++++++++++++++++++++++++++++++++++++ src/resolve/resolved-dns-rr.h | 8 ++++++++ 5 files changed, 100 insertions(+) (limited to 'src') diff --git a/src/basic/escape.c b/src/basic/escape.c index f276c36c56..d59aa9f42f 100644 --- a/src/basic/escape.c +++ b/src/basic/escape.c @@ -415,6 +415,34 @@ char *xescape(const char *s, const char *bad) { return r; } +char *octescape(const char *s, size_t len) { + char *r, *t; + const char *f; + + /* Escapes all chars in bad, in addition to \ and " chars, + * in \nnn style escaping. */ + + r = new(char, len * 4 + 1); + if (!r) + return NULL; + + for (f = s, t = r; f < s + len; f++) { + + if (*f < ' ' || *f >= 127 || *f == '\\' || *f == '"') { + *(t++) = '\\'; + *(t++) = '0' + (*f >> 6); + *(t++) = '0' + ((*f >> 3) & 8); + *(t++) = '0' + (*f & 8); + } else + *(t++) = *f; + } + + *t = 0; + + return r; + +} + static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) { assert(bad); diff --git a/src/basic/escape.h b/src/basic/escape.h index ac8f5f3910..bc25646a3d 100644 --- a/src/basic/escape.h +++ b/src/basic/escape.h @@ -50,6 +50,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit); char *xescape(const char *s, const char *bad); +char *octescape(const char *s, size_t len); char *shell_escape(const char *s, const char *bad); char *shell_maybe_quote(const char *s); diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 6a9a1f732d..4c4d16d109 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -1086,6 +1086,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 */ @@ -1967,6 +1979,21 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl 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; + case DNS_TYPE_OPT: /* we only care about the header of OPT for now. */ case DNS_TYPE_OPENPGPKEY: default: diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 422bbe4bc4..35c0de1a6d 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -24,6 +24,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" @@ -492,6 +493,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); @@ -699,6 +705,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); } @@ -1142,6 +1154,24 @@ 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\"", + k, + rr->caa.flags, + rr->caa.tag, + value); + if (r < 0) + return NULL; + + break; + } + case DNS_TYPE_OPENPGPKEY: { int n; @@ -1432,6 +1462,12 @@ void dns_resource_record_hash_func(const void *i, struct siphash *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: default: siphash24_compress(rr->generic.data, rr->generic.data_size, state); diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index 01c7091645..b75676912b 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -251,6 +251,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; }; }; -- cgit v1.2.3-54-g00ecf From 718af59e9ac1a525b0a73b99a74bc376f1b4d49d Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 1 Feb 2016 21:35:44 -0500 Subject: resolve: always align flags to 8th column and print CAA flags Left-over unknown flags are printed numerically. Otherwise, it wouldn't be known what bits are remaining without knowning what the known bits are. A test case is added to verify the flag printing code: ============== src/resolve/test-data/fake-caa.pkts ============== google.com. IN CAA 0 issue "symantec.com" google.com. IN CAA 128 issue "symantec.com" -- Flags: critical google.com. IN CAA 129 issue "symantec.com" -- Flags: critical 1 google.com. IN CAA 22 issue "symantec.com" -- Flags: 22 --- Makefile.am | 3 ++- src/resolve/dns-type.h | 3 +++ src/resolve/resolved-dns-rr.c | 31 ++++++++++++++++--------------- src/resolve/test-data/fake-caa.pkts | Bin 0 -> 196 bytes 4 files changed, 21 insertions(+), 16 deletions(-) create mode 100644 src/resolve/test-data/fake-caa.pkts (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 8ab04e74ba..5d39967f2c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5326,7 +5326,8 @@ EXTRA_DIST += \ src/resolve/test-data/teamits.com.pkts \ src/resolve/test-data/zbyszek@fedoraproject.org.pkts \ src/resolve/test-data/_443._tcp.fedoraproject.org.pkts \ - src/resolve/test-data/kyhwana.org.pkts + src/resolve/test-data/kyhwana.org.pkts \ + src/resolve/test-data/fake-caa.pkts test_dnssec_SOURCES = \ src/resolve/test-dnssec.c \ diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h index d025544bab..ea51dfdb65 100644 --- a/src/resolve/dns-type.h +++ b/src/resolve/dns-type.h @@ -154,3 +154,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/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 35c0de1a6d..d54645fc7a 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -980,7 +980,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); @@ -989,9 +989,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, @@ -1006,14 +1005,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; @@ -1139,13 +1136,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); @@ -1161,11 +1158,15 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { if (!value) return NULL; - r = asprintf(&s, "%s %u %s \"%s\"", + r = asprintf(&s, "%s %u %s \"%s\"%s%s%s%.0u", k, rr->caa.flags, rr->caa.tag, - value); + 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; diff --git a/src/resolve/test-data/fake-caa.pkts b/src/resolve/test-data/fake-caa.pkts new file mode 100644 index 0000000000..1c3ecc5491 Binary files /dev/null and b/src/resolve/test-data/fake-caa.pkts differ -- cgit v1.2.3-54-g00ecf