1
0
mirror of https://github.com/systemd/systemd synced 2026-04-26 17:04:50 +02:00

Compare commits

...

9 Commits

Author SHA1 Message Date
Zbigniew Jędrzejewski-Szmek
cd0cade1ad
Merge pull request #23289 from yuwata/resolve-answer-add-rrsig
resolve: place RRSIG after the corresponding entries
2022-05-12 16:15:12 +02:00
Stefan Seering
026d48ba93 fix typo 2022-05-12 21:13:03 +09:00
Yu Watanabe
b692ad36b9 sd-device-enumerator: fix inverted return value of match_initialized()
Fixes a bug introduced by d8b50e5df7e01983279e70c6d970fb60d053df97.

Fixes https://github.com/systemd/systemd/pull/22662#issuecomment-1124163773.
Fixes RHBZ#2083374 (https://bugzilla.redhat.com/show_bug.cgi?id=2083374).
2022-05-12 09:31:23 +02:00
Yu Watanabe
d1b8e56a62 resolve: fix false maybe-uninitialized warning 2022-05-07 15:14:41 +09:00
Yu Watanabe
388c92ce09 resolve: move the RRSIG after the all corresponding entries
Fixes #22002.
2022-05-07 15:14:41 +09:00
Yu Watanabe
71aee23dba resolve: manage DnsAnswerItem with OrderedSet
Previously, we manage DnsAnswerItem by an array and Set,
The array was used for the order of the items, and the set is used to
dedup items.
Let's use OrderedSet, then we can simplify the logic.

This fixes dns_answer_remove_by_key() and dns_answer_remove_by_rr()
which makes the set in a broken state.
2022-05-07 15:14:41 +09:00
Yu Watanabe
0bb7324c11 ordered-set: introduce ordered_set_reserve() 2022-05-07 15:14:41 +09:00
Yu Watanabe
4ce30e4de0 resolve: first increment the reference counter
When `exist->rr` and `rr` point to the same object, then it may be freed by
the `dns_resource_record_unref()`.
2022-05-07 15:14:41 +09:00
Yu Watanabe
6edf21dba7 resolve: use dns_answer_isempty() at one more place 2022-05-07 15:14:41 +09:00
9 changed files with 239 additions and 348 deletions

View File

@ -195,7 +195,7 @@ encrypt and decrypt/authenticate credentials. Example:
```sh
systemd-creds encrypt plaintext.txt ciphertext.cred
shred -u plaintext-txt
shred -u plaintext.txt
systemd-run -P --wait -p LoadCredentialEncrypted=foobar:$(pwd)/ciphertext.cred systemd-creds cat foobar
```

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

@ -537,12 +537,12 @@ static int match_initialized(sd_device_enumerator *enumerator, sd_device *device
return true;
if (sd_device_get_devnum(device, NULL) >= 0)
return true;
return false;
if (sd_device_get_ifindex(device, NULL) >= 0)
return true;
return false;
return false;
return true;
}
return (enumerator->match_initialized == MATCH_INITIALIZED_NO) == (r == 0);

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