summaryrefslogtreecommitdiff
path: root/src/resolve/resolved-dns-cache.c
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2022-07-04 18:09:58 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2022-07-09 05:20:10 +0900
commit325513bc776c739a814996cc5c483235ca92be86 (patch)
tree197914963a0fd97d99ed99314fc615c0a482beeb /src/resolve/resolved-dns-cache.c
parent055acd4d8b385fd9ff29e49e0c46856a9e705433 (diff)
downloadsystemd-325513bc776c739a814996cc5c483235ca92be86.tar.gz
resolve: mdns: calculate required packet size to store questions and authorities
Otherwise, if we have many cached entries or pending transactions with TYPE_ANY, then dns_transaction_make_packet_mdns() fails with -EMSGSIZE. This also fixes use-after-free. Fixes #23894.
Diffstat (limited to 'src/resolve/resolved-dns-cache.c')
-rw-r--r--src/resolve/resolved-dns-cache.c32
1 files changed, 23 insertions, 9 deletions
diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c
index 0856976d3e..f793a659ee 100644
--- a/src/resolve/resolved-dns-cache.c
+++ b/src/resolve/resolved-dns-cache.c
@@ -1242,16 +1242,14 @@ int dns_cache_check_conflicts(DnsCache *cache, DnsResourceRecord *rr, int owner_
return 1;
}
-int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) {
+int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p, usec_t ts, unsigned max_rr) {
unsigned ancount = 0;
DnsCacheItem *i;
- usec_t t;
int r;
assert(cache);
assert(p);
-
- t = now(CLOCK_BOOTTIME);
+ assert(p->protocol == DNS_PROTOCOL_MDNS);
HASHMAP_FOREACH(i, cache->by_key)
LIST_FOREACH(by_key, j, i) {
@@ -1263,14 +1261,17 @@ int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) {
/* RFC6762 7.1: Don't append records with less than half the TTL remaining
* as known answers. */
- if (usec_sub_unsigned(j->until, t) < j->rr->ttl * USEC_PER_SEC / 2)
+ if (usec_sub_unsigned(j->until, ts) < j->rr->ttl * USEC_PER_SEC / 2)
continue;
r = dns_packet_append_rr(p, j->rr, 0, NULL, NULL);
- if (r == -EMSGSIZE && p->protocol == DNS_PROTOCOL_MDNS) {
- /* For mDNS, if we're unable to stuff all known answers into the given packet,
- * allocate a new one, push the RR into that one and link it to the current one.
- */
+ if (r == -EMSGSIZE) {
+ if (max_rr == 0)
+ /* If max_rr == 0, do not allocate more packets. */
+ goto finalize;
+
+ /* If we're unable to stuff all known answers into the given packet, allocate
+ * a new one, push the RR into that one and link it to the current one. */
DNS_PACKET_HEADER(p)->ancount = htobe16(ancount);
ancount = 0;
@@ -1288,8 +1289,21 @@ int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) {
return r;
ancount++;
+ if (max_rr > 0 && ancount >= max_rr) {
+ DNS_PACKET_HEADER(p)->ancount = htobe16(ancount);
+ ancount = 0;
+
+ r = dns_packet_new_query(&p->more, p->protocol, 0, true);
+ if (r < 0)
+ return r;
+
+ p = p->more;
+
+ max_rr = UINT_MAX;
+ }
}
+finalize:
DNS_PACKET_HEADER(p)->ancount = htobe16(ancount);
return 0;