1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2024-12-23 17:34:00 +03:00

Merge pull request #23289 from yuwata/resolve-answer-add-rrsig

resolve: place RRSIG after the corresponding entries
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2022-05-12 16:15:12 +02:00 committed by GitHub
commit cd0cade1ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 235 additions and 344 deletions

View File

@ -74,6 +74,10 @@ static inline char** ordered_set_get_strv(OrderedSet *s) {
return _hashmap_get_strv(HASHMAP_BASE((OrderedHashmap*) s));
}
static inline int ordered_set_reserve(OrderedSet *s, unsigned entries_add) {
return ordered_hashmap_reserve((OrderedHashmap*) s, entries_add);
}
int ordered_set_consume(OrderedSet *s, void *p);
int _ordered_set_put_strdup(OrderedSet **s, const char *p HASHMAP_DEBUG_PARAMS);
#define ordered_set_put_strdup(s, p) _ordered_set_put_strdup(s, p HASHMAP_DEBUG_SRC_ARGS)

View File

@ -9,6 +9,19 @@
#include "resolved-dns-dnssec.h"
#include "string-util.h"
static DnsAnswerItem *dns_answer_item_free(DnsAnswerItem *item) {
if (!item)
return NULL;
dns_resource_record_unref(item->rr);
dns_resource_record_unref(item->rrsig);
return mfree(item);
}
DEFINE_PRIVATE_TRIVIAL_REF_UNREF_FUNC(DnsAnswerItem, dns_answer_item, dns_answer_item_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsAnswerItem*, dns_answer_item_unref);
static void dns_answer_item_hash_func(const DnsAnswerItem *a, struct siphash *state) {
assert(a);
assert(state);
@ -31,54 +44,62 @@ static int dns_answer_item_compare_func(const DnsAnswerItem *a, const DnsAnswerI
return dns_resource_record_compare_func(a->rr, b->rr);
}
DEFINE_PRIVATE_HASH_OPS(dns_answer_item_hash_ops, DnsAnswerItem, dns_answer_item_hash_func, dns_answer_item_compare_func);
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
dns_answer_item_hash_ops,
DnsAnswerItem,
dns_answer_item_hash_func,
dns_answer_item_compare_func,
dns_answer_item_unref);
DnsAnswer *dns_answer_new(size_t n) {
_cleanup_set_free_ Set *s = NULL;
DnsAnswer *a;
static int dns_answer_reserve_internal(DnsAnswer *a, size_t n) {
size_t m;
if (n > UINT16_MAX) /* We can only place 64K RRs in an answer at max */
assert(a);
assert(a->items);
m = ordered_set_size(a->items);
assert(m <= UINT16_MAX); /* We can only place 64K RRs in an answer at max */
if (n > UINT16_MAX - m)
n = UINT16_MAX;
s = set_new(&dns_answer_item_hash_ops);
if (!s)
return NULL;
else
n += m;
/* Higher multipliers give slightly higher efficiency through hash collisions, but the gains
* quickly drop off after 2. */
if (set_reserve(s, n * 2) < 0)
return NULL;
a = malloc0(offsetof(DnsAnswer, items) + sizeof(DnsAnswerItem) * n);
if (!a)
return NULL;
a->n_ref = 1;
a->n_allocated = n;
a->set_items = TAKE_PTR(s);
return a;
return ordered_set_reserve(a->items, n * 2);
}
static void dns_answer_flush(DnsAnswer *a) {
DnsAnswerItem *item;
DnsAnswer *dns_answer_new(size_t n) {
_cleanup_ordered_set_free_ OrderedSet *s = NULL;
DnsAnswer *a;
if (n > UINT16_MAX)
n = UINT16_MAX;
s = ordered_set_new(&dns_answer_item_hash_ops);
if (!s)
return NULL;
a = new(DnsAnswer, 1);
if (!a)
return;
return NULL;
a->set_items = set_free(a->set_items);
*a = (DnsAnswer) {
.n_ref = 1,
.items = TAKE_PTR(s),
};
DNS_ANSWER_FOREACH_ITEM(item, a) {
dns_resource_record_unref(item->rr);
dns_resource_record_unref(item->rrsig);
}
if (dns_answer_reserve_internal(a, n) < 0)
return NULL;
a->n_rrs = 0;
return a;
}
static DnsAnswer *dns_answer_free(DnsAnswer *a) {
assert(a);
dns_answer_flush(a);
ordered_set_free(a->items);
return mfree(a);
}
@ -91,6 +112,7 @@ static int dns_answer_add_raw(
DnsAnswerFlags flags,
DnsResourceRecord *rrsig) {
_cleanup_(dns_answer_item_unrefp) DnsAnswerItem *item = NULL;
int r;
assert(rr);
@ -98,25 +120,26 @@ static int dns_answer_add_raw(
if (!a)
return -ENOSPC;
if (a->n_rrs >= a->n_allocated)
if (dns_answer_size(a) >= UINT16_MAX)
return -ENOSPC;
a->items[a->n_rrs] = (DnsAnswerItem) {
.rr = rr,
item = new(DnsAnswerItem, 1);
if (!item)
return -ENOMEM;
*item = (DnsAnswerItem) {
.n_ref = 1,
.rr = dns_resource_record_ref(rr),
.ifindex = ifindex,
.flags = flags,
.rrsig = dns_resource_record_ref(rrsig),
};
r = set_put(a->set_items, &a->items[a->n_rrs]);
r = ordered_set_put(a->items, item);
if (r < 0)
return r;
if (r == 0)
return -EEXIST;
dns_resource_record_ref(rr);
a->n_rrs++;
TAKE_PTR(item);
return 1;
}
@ -159,7 +182,7 @@ int dns_answer_add(
.ifindex = ifindex,
};
exist = set_get(a->set_items, &tmp);
exist = ordered_set_get(a->items, &tmp);
if (exist) {
/* There's already an RR of the same RRset in place! Let's see if the TTLs more or less
* match. We don't really care if they match precisely, but we do care whether one is 0 and
@ -169,8 +192,9 @@ int dns_answer_add(
/* Entry already exists, keep the entry with the higher TTL. */
if (rr->ttl > exist->rr->ttl) {
dns_resource_record_ref(rr);
dns_resource_record_unref(exist->rr);
exist->rr = dns_resource_record_ref(rr); /* lgtm [cpp/inconsistent-null-check] */
exist->rr = rr;
/* Update RRSIG and RR at the same time */
if (rrsig) {
@ -181,6 +205,12 @@ int dns_answer_add(
}
exist->flags |= flags;
if (rr->key->type == DNS_TYPE_RRSIG) {
/* If the rr is RRSIG, then move the rr to the end. */
assert_se(ordered_set_remove(a->items, exist) == exist);
assert_se(ordered_set_put(a->items, exist) == 1);
}
return 0;
}
@ -436,7 +466,7 @@ int dns_answer_merge(DnsAnswer *a, DnsAnswer *b, DnsAnswer **ret) {
return 0;
}
k = dns_answer_new(a->n_rrs + b->n_rrs);
k = dns_answer_new(dns_answer_size(a) + dns_answer_size(b));
if (!k)
return -ENOMEM;
@ -470,9 +500,8 @@ int dns_answer_extend(DnsAnswer **a, DnsAnswer *b) {
}
int dns_answer_remove_by_key(DnsAnswer **a, const DnsResourceKey *key) {
bool found = false, other = false;
DnsResourceRecord *rr;
size_t i;
DnsAnswerItem *item;
bool found = false;
int r;
assert(a);
@ -480,162 +509,51 @@ int dns_answer_remove_by_key(DnsAnswer **a, const DnsResourceKey *key) {
/* Remove all entries matching the specified key from *a */
DNS_ANSWER_FOREACH(rr, *a) {
r = dns_resource_key_equal(rr->key, key);
DNS_ANSWER_FOREACH_ITEM(item, *a) {
r = dns_resource_key_equal(item->rr->key, key);
if (r < 0)
return r;
if (r > 0)
if (r > 0) {
dns_answer_item_unref(ordered_set_remove((*a)->items, item));
found = true;
else
other = true;
if (found && other)
break;
}
}
if (!found)
return 0;
if (!other) {
if (dns_answer_isempty(*a))
*a = dns_answer_unref(*a); /* Return NULL for the empty answer */
return 1;
}
if ((*a)->n_ref > 1) {
_cleanup_(dns_answer_unrefp) DnsAnswer *copy = NULL;
DnsAnswerItem *item;
copy = dns_answer_new((*a)->n_rrs);
if (!copy)
return -ENOMEM;
DNS_ANSWER_FOREACH_ITEM(item, *a) {
r = dns_resource_key_equal(item->rr->key, key);
if (r < 0)
return r;
if (r > 0)
continue;
r = dns_answer_add_raw(copy, item->rr, item->ifindex, item->flags, item->rrsig);
if (r < 0)
return r;
}
dns_answer_unref(*a);
*a = TAKE_PTR(copy);
return 1;
}
/* Only a single reference, edit in-place */
i = 0;
for (;;) {
if (i >= (*a)->n_rrs)
break;
r = dns_resource_key_equal((*a)->items[i].rr->key, key);
if (r < 0)
return r;
if (r > 0) {
/* Kill this entry */
dns_resource_record_unref((*a)->items[i].rr);
dns_resource_record_unref((*a)->items[i].rrsig);
memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1));
(*a)->n_rrs--;
continue;
} else
/* Keep this entry */
i++;
}
return 1;
}
int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rm) {
bool found = false, other = false;
DnsResourceRecord *rr;
size_t i;
int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rr) {
_unused_ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr_ref = dns_resource_record_ref(rr);
DnsAnswerItem *item;
bool found = false;
int r;
assert(a);
assert(rm);
assert(rr);
/* Remove all entries matching the specified RR from *a */
DNS_ANSWER_FOREACH(rr, *a) {
r = dns_resource_record_equal(rr, rm);
DNS_ANSWER_FOREACH_ITEM(item, *a) {
r = dns_resource_record_equal(item->rr, rr);
if (r < 0)
return r;
if (r > 0)
if (r > 0) {
dns_answer_item_unref(ordered_set_remove((*a)->items, item));
found = true;
else
other = true;
if (found && other)
break;
}
}
if (!found)
return 0;
if (!other) {
if (dns_answer_isempty(*a))
*a = dns_answer_unref(*a); /* Return NULL for the empty answer */
return 1;
}
if ((*a)->n_ref > 1) {
_cleanup_(dns_answer_unrefp) DnsAnswer *copy = NULL;
DnsAnswerItem *item;
copy = dns_answer_new((*a)->n_rrs);
if (!copy)
return -ENOMEM;
DNS_ANSWER_FOREACH_ITEM(item, *a) {
r = dns_resource_record_equal(item->rr, rm);
if (r < 0)
return r;
if (r > 0)
continue;
r = dns_answer_add_raw(copy, item->rr, item->ifindex, item->flags, item->rrsig);
if (r < 0)
return r;
}
dns_answer_unref(*a);
*a = TAKE_PTR(copy);
return 1;
}
/* Only a single reference, edit in-place */
i = 0;
for (;;) {
if (i >= (*a)->n_rrs)
break;
r = dns_resource_record_equal((*a)->items[i].rr, rm);
if (r < 0)
return r;
if (r > 0) {
/* Kill this entry */
dns_resource_record_unref((*a)->items[i].rr);
dns_resource_record_unref((*a)->items[i].rrsig);
memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1));
(*a)->n_rrs--;
continue;
} else
/* Keep this entry */
i++;
}
return 1;
}
@ -655,6 +573,8 @@ int dns_answer_remove_by_answer_keys(DnsAnswer **a, DnsAnswer *b) {
r = dns_answer_remove_by_key(a, item->rr->key);
if (r < 0)
return r;
if (!*a)
return 0; /* a is already empty. */
/* Let's remember this entry's RR key, to optimize the loop a bit: if we have an RRset with
* more than one item then we don't need to remove the key multiple times */
@ -688,12 +608,7 @@ int dns_answer_copy_by_key(
if (r == 0)
continue;
/* Make space for at least one entry */
r = dns_answer_reserve_or_clone(a, 1);
if (r < 0)
return r;
r = dns_answer_add(*a, item->rr, item->ifindex, item->flags|or_flags, rrsig ?: item->rrsig);
r = dns_answer_add_extend(a, item->rr, item->ifindex, item->flags|or_flags, rrsig ?: item->rrsig);
if (r < 0)
return r;
}
@ -707,6 +622,7 @@ int dns_answer_move_by_key(
const DnsResourceKey *key,
DnsAnswerFlags or_flags,
DnsResourceRecord *rrsig) {
int r;
assert(to);
@ -721,140 +637,91 @@ int dns_answer_move_by_key(
}
void dns_answer_order_by_scope(DnsAnswer *a, bool prefer_link_local) {
DnsAnswerItem *items;
size_t i, start, end;
_cleanup_free_ DnsAnswerItem **items = NULL;
DnsAnswerItem **p, *item;
size_t n;
if (!a)
n = dns_answer_size(a);
if (n <= 1)
return;
if (a->n_rrs <= 1)
return;
start = 0;
end = a->n_rrs-1;
/* RFC 4795, Section 2.6 suggests we should order entries
* depending on whether the sender is a link-local address. */
items = newa(DnsAnswerItem, a->n_rrs);
for (i = 0; i < a->n_rrs; i++) {
if (dns_resource_record_is_link_local_address(a->items[i].rr) != prefer_link_local)
/* Order address records that are not preferred to the end of the array */
items[end--] = a->items[i];
else
/* Order all other records to the beginning of the array */
items[start++] = a->items[i];
}
p = items = new(DnsAnswerItem*, n);
if (!items)
return (void) log_oom();
assert(start == end+1);
memcpy(a->items, items, sizeof(DnsAnswerItem) * a->n_rrs);
/* Order preferred address records and other records to the beginning of the array */
DNS_ANSWER_FOREACH_ITEM(item, a)
if (dns_resource_record_is_link_local_address(item->rr) == prefer_link_local)
*p++ = dns_answer_item_ref(item);
/* Order address records that are not preferred to the end of the array */
DNS_ANSWER_FOREACH_ITEM(item, a)
if (dns_resource_record_is_link_local_address(item->rr) != prefer_link_local)
*p++ = dns_answer_item_ref(item);
assert((size_t) (p - items) == n);
ordered_set_clear(a->items);
for (size_t i = 0; i < n; i++)
assert_se(ordered_set_put(a->items, items[i]) >= 0);
}
int dns_answer_reserve(DnsAnswer **a, size_t n_free) {
DnsAnswer *n;
assert(a);
if (n_free <= 0)
return 0;
if (*a) {
size_t ns;
int r;
if (!*a) {
DnsAnswer *n;
if ((*a)->n_ref > 1)
return -EBUSY;
ns = (*a)->n_rrs;
assert(ns <= UINT16_MAX); /* Maximum number of RRs we can stick into a DNS packet section */
if (n_free > UINT16_MAX - ns) /* overflow check */
ns = UINT16_MAX;
else
ns += n_free;
if ((*a)->n_allocated >= ns)
return 0;
/* Allocate more than we need, but not more than UINT16_MAX */
if (ns <= UINT16_MAX/2)
ns *= 2;
else
ns = UINT16_MAX;
/* This must be done before realloc() below. Otherwise, the original DnsAnswer object
* may be broken. */
r = set_reserve((*a)->set_items, ns);
if (r < 0)
return r;
n = realloc(*a, offsetof(DnsAnswer, items) + sizeof(DnsAnswerItem) * ns);
if (!n)
return -ENOMEM;
n->n_allocated = ns;
/* Previously all items are stored in the set, and the enough memory area is allocated
* in the above. So set_put() in the below cannot fail. */
set_clear(n->set_items);
for (size_t i = 0; i < n->n_rrs; i++)
assert_se(set_put(n->set_items, &n->items[i]) > 0);
} else {
n = dns_answer_new(n_free);
if (!n)
return -ENOMEM;
*a = n;
return 0;
}
*a = n;
return 0;
if ((*a)->n_ref > 1)
return -EBUSY;
return dns_answer_reserve_internal(*a, n_free);
}
int dns_answer_reserve_or_clone(DnsAnswer **a, size_t n_free) {
_cleanup_(dns_answer_unrefp) DnsAnswer *n = NULL;
size_t ns;
int r;
assert(a);
/* Tries to extend the DnsAnswer object. And if that's not possible, since we are not the sole owner,
* then allocate a new, appropriately sized one. Either way, after this call the object will only
* have a single reference, and has room for at least the specified number of RRs. */
r = dns_answer_reserve(a, n_free);
if (r != -EBUSY)
return r;
if (*a && (*a)->n_ref > 1) {
_cleanup_(dns_answer_unrefp) DnsAnswer *n = NULL;
size_t ns;
ns = dns_answer_size(*a);
assert(ns <= UINT16_MAX); /* Maximum number of RRs we can stick into a DNS packet section */
ns = (*a)->n_rrs;
assert(ns <= UINT16_MAX); /* Maximum number of RRs we can stick into a DNS packet section */
if (n_free > UINT16_MAX - ns) /* overflow check */
ns = UINT16_MAX;
else
ns += n_free;
if (n_free > UINT16_MAX - ns) /* overflow check */
ns = UINT16_MAX;
else if (n_free > 0) { /* Increase size and double the result, just in case — except if the
* increase is specified as 0, in which case we just allocate the
* exact amount as before, under the assumption this is just a request
* to copy the answer. */
ns += n_free;
n = dns_answer_new(ns);
if (!n)
return -ENOMEM;
if (ns <= UINT16_MAX/2) /* overflow check */
ns *= 2;
else
ns = UINT16_MAX;
}
n = dns_answer_new(ns);
if (!n)
return -ENOMEM;
r = dns_answer_add_raw_all(n, *a);
if (r < 0)
return r;
dns_answer_unref(*a);
assert_se(*a = TAKE_PTR(n));
} else if (n_free > 0) {
r = dns_answer_reserve(a, n_free);
if (r < 0)
return r;
}
r = dns_answer_add_raw_all(n, *a);
if (r < 0)
return r;
dns_answer_unref(*a);
*a = TAKE_PTR(n);
return 0;
}
@ -944,6 +811,8 @@ int dns_answer_has_dname_for_cname(DnsAnswer *a, DnsResourceRecord *cname) {
}
void dns_answer_randomize(DnsAnswer *a) {
_cleanup_free_ DnsAnswerItem **items = NULL;
DnsAnswerItem **p, *item;
size_t n;
/* Permutes the answer list randomly (Knuth shuffle) */
@ -952,6 +821,15 @@ void dns_answer_randomize(DnsAnswer *a) {
if (n <= 1)
return;
p = items = new(DnsAnswerItem*, n);
if (!items)
return (void) log_oom();
DNS_ANSWER_FOREACH_ITEM(item, a)
*p++ = dns_answer_item_ref(item);
assert((size_t) (p - items) == n);
for (size_t i = 0; i < n; i++) {
size_t k;
@ -959,8 +837,12 @@ void dns_answer_randomize(DnsAnswer *a) {
if (k == i)
continue;
SWAP_TWO(a->items[i], a->items[k]);
SWAP_TWO(items[i], items[k]);
}
ordered_set_clear(a->items);
for (size_t i = 0; i < n; i++)
assert_se(ordered_set_put(a->items, items[i]) >= 0);
}
uint32_t dns_answer_min_ttl(DnsAnswer *a) {

View File

@ -5,8 +5,8 @@ typedef struct DnsAnswer DnsAnswer;
typedef struct DnsAnswerItem DnsAnswerItem;
#include "macro.h"
#include "ordered-set.h"
#include "resolved-dns-rr.h"
#include "set.h"
/* A simple array of resource records. We keep track of the originating ifindex for each RR where that makes
* sense, so that we can qualify A and AAAA RRs referring to a local link with the right ifindex.
@ -29,6 +29,7 @@ typedef enum DnsAnswerFlags {
} DnsAnswerFlags;
struct DnsAnswerItem {
unsigned n_ref;
DnsResourceRecord *rr;
DnsResourceRecord *rrsig; /* Optionally, also store RRSIG RR that successfully validates this item */
int ifindex;
@ -37,9 +38,7 @@ struct DnsAnswerItem {
struct DnsAnswer {
unsigned n_ref;
Set *set_items; /* Used by dns_answer_add() for optimization. */
size_t n_rrs, n_allocated;
DnsAnswerItem items[0];
OrderedSet *items;
};
DnsAnswer *dns_answer_new(size_t n);
@ -76,7 +75,7 @@ int dns_answer_move_by_key(DnsAnswer **to, DnsAnswer **from, const DnsResourceKe
int dns_answer_has_dname_for_cname(DnsAnswer *a, DnsResourceRecord *cname);
static inline size_t dns_answer_size(DnsAnswer *a) {
return a ? a->n_rrs : 0;
return a ? ordered_set_size(a->items) : 0;
}
static inline bool dns_answer_isempty(DnsAnswer *a) {
@ -91,50 +90,40 @@ uint32_t dns_answer_min_ttl(DnsAnswer *a);
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsAnswer*, dns_answer_unref);
#define _DNS_ANSWER_FOREACH(q, kk, a) \
for (size_t UNIQ_T(i, q) = ({ \
(kk) = dns_answer_isempty(a) ? NULL : (a)->items[0].rr; \
0; \
}); \
UNIQ_T(i, q) < dns_answer_size(a); \
UNIQ_T(i, q)++, \
(kk) = UNIQ_T(i, q) < dns_answer_size(a) ? (a)->items[UNIQ_T(i, q)].rr : NULL)
typedef struct DnsAnswerIterator {
Iterator iterator;
DnsAnswer *answer;
DnsAnswerItem *item;
} DnsAnswerIterator;
#define DNS_ANSWER_FOREACH(kk, a) _DNS_ANSWER_FOREACH(UNIQ, kk, a)
#define _DNS_ANSWER_FOREACH(kk, a, i) \
for (DnsAnswerIterator i = { .iterator = ITERATOR_FIRST, .answer = (a) }; \
i.answer && \
ordered_set_iterate(i.answer->items, &i.iterator, (void**) &(i.item)) && \
(kk = i.item->rr, true); )
#define _DNS_ANSWER_FOREACH_IFINDEX(q, kk, ifi, a) \
for (size_t UNIQ_T(i, q) = ({ \
(kk) = dns_answer_isempty(a) ? NULL : (a)->items[0].rr; \
(ifi) = dns_answer_isempty(a) ? 0 : (a)->items[0].ifindex; \
0; \
}); \
UNIQ_T(i, q) < dns_answer_size(a); \
UNIQ_T(i, q)++, \
(kk) = UNIQ_T(i, q) < dns_answer_size(a) ? (a)->items[UNIQ_T(i, q)].rr : NULL, \
(ifi) = UNIQ_T(i, q) < dns_answer_size(a) ? (a)->items[UNIQ_T(i, q)].ifindex : 0)
#define DNS_ANSWER_FOREACH(rr, a) _DNS_ANSWER_FOREACH(rr, a, UNIQ_T(i, UNIQ))
#define DNS_ANSWER_FOREACH_IFINDEX(kk, ifindex, a) _DNS_ANSWER_FOREACH_IFINDEX(UNIQ, kk, ifindex, a)
#define _DNS_ANSWER_FOREACH_IFINDEX(kk, ifi, a, i) \
for (DnsAnswerIterator i = { .iterator = ITERATOR_FIRST, .answer = (a) }; \
i.answer && \
ordered_set_iterate(i.answer->items, &i.iterator, (void**) &(i.item)) && \
(kk = i.item->rr, ifi = i.item->ifindex, true); )
#define _DNS_ANSWER_FOREACH_FLAGS(q, kk, fl, a) \
for (size_t UNIQ_T(i, q) = ({ \
(kk) = dns_answer_isempty(a) ? NULL : (a)->items[0].rr; \
(fl) = dns_answer_isempty(a) ? 0 : (a)->items[0].flags; \
0; \
}); \
UNIQ_T(i, q) < dns_answer_size(a); \
UNIQ_T(i, q)++, \
(kk) = UNIQ_T(i, q) < dns_answer_size(a) ? (a)->items[UNIQ_T(i, q)].rr : NULL, \
(fl) = UNIQ_T(i, q) < dns_answer_size(a) ? (a)->items[UNIQ_T(i, q)].flags : 0)
#define DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, a) _DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, a, UNIQ_T(i, UNIQ))
#define DNS_ANSWER_FOREACH_FLAGS(kk, flags, a) _DNS_ANSWER_FOREACH_FLAGS(UNIQ, kk, flags, a)
#define _DNS_ANSWER_FOREACH_FLAGS(kk, fl, a, i) \
for (DnsAnswerIterator i = { .iterator = ITERATOR_FIRST, .answer = (a) }; \
i.answer && \
ordered_set_iterate(i.answer->items, &i.iterator, (void**) &(i.item)) && \
(kk = i.item->rr, fl = i.item->flags, true); )
#define _DNS_ANSWER_FOREACH_ITEM(q, item, a) \
for (size_t UNIQ_T(i, q) = ({ \
(item) = dns_answer_isempty(a) ? NULL : (a)->items; \
0; \
}); \
UNIQ_T(i, q) < dns_answer_size(a); \
UNIQ_T(i, q)++, \
(item) = (UNIQ_T(i, q) < dns_answer_size(a)) ? (a)->items + UNIQ_T(i, q) : NULL)
#define DNS_ANSWER_FOREACH_FLAGS(rr, flags, a) _DNS_ANSWER_FOREACH_FLAGS(rr, flags, a, UNIQ_T(i, UNIQ))
#define DNS_ANSWER_FOREACH_ITEM(item, a) _DNS_ANSWER_FOREACH_ITEM(UNIQ, item, a)
#define _DNS_ANSWER_FOREACH_ITEM(item, a, i) \
for (DnsAnswerIterator i = { .iterator = ITERATOR_FIRST, .answer = (a) }; \
i.answer && \
ordered_set_iterate(i.answer->items, &i.iterator, (void**) &(i.item)) && \
(item = i.item, true); )
#define DNS_ANSWER_FOREACH_ITEM(item, a) _DNS_ANSWER_FOREACH_ITEM(item, a, UNIQ_T(i, UNIQ))

View File

@ -989,8 +989,9 @@ int dnssec_verify_rrset(
DnsResourceRecord **list, *rr;
const char *source, *name;
size_t n = 0, sig_size;
_cleanup_free_ char *sig_data = NULL;
size_t sig_size = 0; /* avoid false maybe-uninitialized warning */
size_t n = 0;
bool wildcard;
int r;
@ -1184,7 +1185,7 @@ int dnssec_verify_rrset_search(
/* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
if (!a || a->n_rrs <= 0)
if (dns_answer_isempty(a))
return -ENODATA;
/* Iterate through each RRSIG RR. */

View File

@ -3106,6 +3106,7 @@ static int dnssec_validate_records(
/* Returns negative on error, 0 if validation failed, 1 to restart validation, 2 when finished. */
DNS_ANSWER_FOREACH(rr, t->answer) {
_unused_ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr_ref = dns_resource_record_ref(rr);
DnsResourceRecord *rrsig = NULL;
DnssecResult result;

View File

@ -599,6 +599,7 @@ static int dns_trust_anchor_revoked_put(DnsTrustAnchor *d, DnsResourceRecord *rr
static int dns_trust_anchor_remove_revoked(DnsTrustAnchor *d, DnsResourceRecord *rr) {
_cleanup_(dns_answer_unrefp) DnsAnswer *new_answer = NULL;
DnsAnswer *old_answer;
DnsAnswerItem *item;
int r;
/* Remember that this is a revoked trust anchor RR */
@ -631,11 +632,12 @@ static int dns_trust_anchor_remove_revoked(DnsTrustAnchor *d, DnsResourceRecord
return 1;
}
r = hashmap_replace(d->positive_by_key, new_answer->items[0].rr->key, new_answer);
item = ordered_set_first(new_answer->items);
r = hashmap_replace(d->positive_by_key, item->rr->key, new_answer);
if (r < 0)
return r;
new_answer = NULL;
TAKE_PTR(new_answer);
dns_answer_unref(old_answer);
return 1;
}

View File

@ -107,7 +107,8 @@ static int proposed_rrs_cmp(DnsResourceRecord **x, unsigned x_size, DnsResourceR
static int mdns_packet_extract_matching_rrs(DnsPacket *p, DnsResourceKey *key, DnsResourceRecord ***ret_rrs) {
_cleanup_free_ DnsResourceRecord **list = NULL;
unsigned n = 0, size = 0;
size_t i, n = 0, size = 0;
DnsResourceRecord *rr;
int r;
assert(p);
@ -115,28 +116,39 @@ static int mdns_packet_extract_matching_rrs(DnsPacket *p, DnsResourceKey *key, D
assert(ret_rrs);
assert_return(DNS_PACKET_NSCOUNT(p) > 0, -EINVAL);
for (size_t i = DNS_PACKET_ANCOUNT(p); i < (DNS_PACKET_ANCOUNT(p) + DNS_PACKET_NSCOUNT(p)); i++) {
r = dns_resource_key_match_rr(key, p->answer->items[i].rr, NULL);
if (r < 0)
return r;
if (r > 0)
size++;
i = 0;
DNS_ANSWER_FOREACH(rr, p->answer) {
if (i >= DNS_PACKET_ANCOUNT(p) && i < DNS_PACKET_ANCOUNT(p) + DNS_PACKET_NSCOUNT(p)) {
r = dns_resource_key_match_rr(key, rr, NULL);
if (r < 0)
return r;
if (r > 0)
size++;
}
i++;
}
if (size == 0)
if (size == 0) {
*ret_rrs = NULL;
return 0;
}
list = new(DnsResourceRecord *, size);
if (!list)
return -ENOMEM;
for (size_t i = DNS_PACKET_ANCOUNT(p); i < (DNS_PACKET_ANCOUNT(p) + DNS_PACKET_NSCOUNT(p)); i++) {
r = dns_resource_key_match_rr(key, p->answer->items[i].rr, NULL);
if (r < 0)
return r;
if (r > 0)
list[n++] = p->answer->items[i].rr;
i = 0;
DNS_ANSWER_FOREACH(rr, p->answer) {
if (i >= DNS_PACKET_ANCOUNT(p) && i < DNS_PACKET_ANCOUNT(p) + DNS_PACKET_NSCOUNT(p)) {
r = dns_resource_key_match_rr(key, rr, NULL);
if (r < 0)
return r;
if (r > 0)
list[n++] = rr;
}
i++;
}
assert(n == size);
typesafe_qsort(list, size, mdns_rr_compare);