mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-02-27 13:57:26 +03:00
Merge pull request #2589 from keszybz/resolve-tool-2
Better support of OPENPGPKEY, CAA, TLSA packets and tests
This commit is contained in:
commit
91ba5ac7d0
1
.gitignore
vendored
1
.gitignore
vendored
@ -184,6 +184,7 @@
|
||||
/test-dhcp-server
|
||||
/test-dhcp6-client
|
||||
/test-dns-domain
|
||||
/test-dns-packet
|
||||
/test-dnssec
|
||||
/test-efi-disk.img
|
||||
/test-ellipsize
|
||||
|
106
Makefile.am
106
Makefile.am
@ -1499,6 +1499,7 @@ tests += \
|
||||
test-af-list \
|
||||
test-arphrd-list \
|
||||
test-dns-domain \
|
||||
test-dns-packet \
|
||||
test-resolve-tables \
|
||||
test-install-root \
|
||||
test-rlimit-util \
|
||||
@ -1664,16 +1665,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 += \
|
||||
@ -4279,7 +4270,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)
|
||||
@ -5178,6 +5171,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 \
|
||||
@ -5197,14 +5204,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 \
|
||||
@ -5223,14 +5223,12 @@ 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
|
||||
|
||||
nodist_systemd_resolved_SOURCES = \
|
||||
src/resolve/dns_type-from-name.h \
|
||||
@ -5290,18 +5288,9 @@ 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
|
||||
|
||||
nodist_systemd_resolve_SOURCES = \
|
||||
src/resolve/dns_type-from-name.h \
|
||||
@ -5320,20 +5309,43 @@ 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_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
-DRESOLVE_TEST_DIR=\"$(abs_top_srcdir)/src/resolve/test-data\"
|
||||
|
||||
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 \
|
||||
src/resolve/test-data/_443._tcp.fedoraproject.org.pkts \
|
||||
src/resolve/test-data/kyhwana.org.pkts \
|
||||
src/resolve/test-data/fake-caa.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
|
||||
|
@ -76,6 +76,13 @@
|
||||
<replaceable>TYPE</replaceable></arg> <replaceable>DOMAIN</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
|
||||
<cmdsynopsis>
|
||||
<command>systemd-resolve</command>
|
||||
<arg choice="opt" rep="repeat">OPTIONS</arg>
|
||||
<command> --openpgp</command>
|
||||
<arg choice="plain"><replaceable>USER@DOMAIN</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
|
||||
<cmdsynopsis>
|
||||
<command>systemd-resolve</command>
|
||||
<arg choice="opt" rep="repeat">OPTIONS</arg>
|
||||
@ -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).</para>
|
||||
|
||||
<para>The <option>--openpgp</option> switch may be use to query PGP keys stored as the
|
||||
<ulink url="https://tools.ietf.org/html/draft-wouters-dane-openpgp-02">OPENPGPKEY</ulink> resource records.
|
||||
When this option is specified one or more e-mail address must be specified.</para>
|
||||
|
||||
<para>The <option>--statistics</option> switch may be used to show resolver statistics, including information about
|
||||
the number of successful and failed DNSSEC validations.</para>
|
||||
|
||||
@ -197,6 +208,14 @@
|
||||
<option>--service</option> the TXT service metadata record is resolved as well.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--openpgp</option></term>
|
||||
|
||||
<listitem><para>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.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--cname=</option><replaceable>BOOL</replaceable></term>
|
||||
|
||||
|
@ -413,6 +413,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);
|
||||
|
||||
|
@ -48,6 +48,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);
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "alloc-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "macro.h"
|
||||
#include "util.h"
|
||||
|
||||
char octchar(int x) {
|
||||
return '0' + (x & 7);
|
||||
@ -572,7 +573,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);
|
||||
|
@ -102,6 +102,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)))
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#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));
|
||||
@ -206,20 +207,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) {
|
||||
@ -259,7 +246,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);
|
||||
@ -295,7 +282,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);
|
||||
@ -314,7 +301,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);
|
||||
@ -341,7 +328,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);
|
||||
@ -380,7 +367,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);
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include "fd-util.h"
|
||||
#include "fsprg.h"
|
||||
#include "gcrypt-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "journal-authenticate.h"
|
||||
#include "journal-def.h"
|
||||
@ -424,25 +425,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)
|
||||
|
@ -1123,8 +1123,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)
|
||||
@ -1389,7 +1389,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);
|
||||
|
@ -54,12 +54,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;
|
||||
|
@ -71,8 +71,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;
|
||||
|
@ -110,14 +110,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;
|
||||
}
|
||||
|
@ -1131,8 +1131,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 */
|
||||
|
@ -2631,8 +2631,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;
|
||||
}
|
||||
|
@ -350,7 +350,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;
|
||||
@ -787,7 +787,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);
|
||||
@ -998,7 +998,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
|
||||
|
@ -217,9 +217,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;
|
||||
|
@ -2623,12 +2623,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);
|
||||
|
@ -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)
|
||||
|
@ -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.");
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
||||
|
BIN
src/resolve/test-data/_443._tcp.fedoraproject.org.pkts
Normal file
BIN
src/resolve/test-data/_443._tcp.fedoraproject.org.pkts
Normal file
Binary file not shown.
BIN
src/resolve/test-data/_openpgpkey.fedoraproject.org.pkts
Normal file
BIN
src/resolve/test-data/_openpgpkey.fedoraproject.org.pkts
Normal file
Binary file not shown.
BIN
src/resolve/test-data/fake-caa.pkts
Normal file
BIN
src/resolve/test-data/fake-caa.pkts
Normal file
Binary file not shown.
BIN
src/resolve/test-data/fedoraproject.org.pkts
Normal file
BIN
src/resolve/test-data/fedoraproject.org.pkts
Normal file
Binary file not shown.
BIN
src/resolve/test-data/gandi.net.pkts
Normal file
BIN
src/resolve/test-data/gandi.net.pkts
Normal file
Binary file not shown.
BIN
src/resolve/test-data/google.com.pkts
Normal file
BIN
src/resolve/test-data/google.com.pkts
Normal file
Binary file not shown.
BIN
src/resolve/test-data/kyhwana.org.pkts
Normal file
BIN
src/resolve/test-data/kyhwana.org.pkts
Normal file
Binary file not shown.
BIN
src/resolve/test-data/root.pkts
Normal file
BIN
src/resolve/test-data/root.pkts
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/resolve/test-data/teamits.com.pkts
Normal file
BIN
src/resolve/test-data/teamits.com.pkts
Normal file
Binary file not shown.
BIN
src/resolve/test-data/zbyszek@fedoraproject.org.pkts
Normal file
BIN
src/resolve/test-data/zbyszek@fedoraproject.org.pkts
Normal file
Binary file not shown.
115
src/resolve/test-dns-packet.c
Normal file
115
src/resolve/test-dns-packet.c
Normal file
@ -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;
|
||||
}
|
69
src/shared/gcrypt-util.c
Normal file
69
src/shared/gcrypt-util.c
Normal file
@ -0,0 +1,69 @@
|
||||
/*-*- 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 <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
25
src/shared/gcrypt-util.h
Normal file
25
src/shared/gcrypt-util.h
Normal file
@ -0,0 +1,25 @@
|
||||
/*-*- 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 <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
void initialize_libgcrypt(bool secmem);
|
||||
int string_hashsum(const char *s, size_t len, int md_algorithm, char **out);
|
Loading…
x
Reference in New Issue
Block a user