X Tutup
Skip to content

Commit d2579ee

Browse files
committed
resolved: rework mDNS cache-flush bit handling
This adds a new DnsAnswer item flag "DNS_ANSWER_SHARED_OWNER" which is set for mDNS RRs that lack the cache-flush bit. The cache-flush bit is removed from the DnsResourceRecord object in favour of this. This also splits out the code that removes previous entries when adding new positive ones into a new separate call dns_cache_remove_previous().
1 parent ea207b6 commit d2579ee

File tree

6 files changed

+129
-53
lines changed

6 files changed

+129
-53
lines changed

src/resolve-host/resolve-host.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ static int resolve_record(sd_bus *bus, const char *name) {
398398
if (r < 0)
399399
return log_oom();
400400

401-
r = dns_packet_read_rr(p, &rr, NULL);
401+
r = dns_packet_read_rr(p, &rr, NULL, NULL);
402402
if (r < 0) {
403403
log_error("Failed to parse RR.");
404404
return r;

src/resolve/resolved-dns-answer.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ typedef struct DnsAnswerItem DnsAnswerItem;
3535
* Note that we usually encode the the empty DnsAnswer object as a simple NULL. */
3636

3737
typedef enum DnsAnswerFlags {
38-
DNS_ANSWER_AUTHENTICATED = 1,
39-
DNS_ANSWER_CACHEABLE = 2,
38+
DNS_ANSWER_AUTHENTICATED = 1, /* Item has been authenticated */
39+
DNS_ANSWER_CACHEABLE = 2, /* Item is subject to caching */
40+
DNS_ANSWER_SHARED_OWNER = 4, /* For mDNS: RRset may be owner by multiple peers */
4041
} DnsAnswerFlags;
4142

4243
struct DnsAnswerItem {

src/resolve/resolved-dns-cache.c

Lines changed: 102 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,18 @@ enum DnsCacheItemType {
4242
};
4343

4444
struct DnsCacheItem {
45+
DnsCacheItemType type;
4546
DnsResourceKey *key;
4647
DnsResourceRecord *rr;
48+
4749
usec_t until;
48-
DnsCacheItemType type;
49-
unsigned prioq_idx;
50-
bool authenticated;
50+
bool authenticated:1;
51+
bool shared_owner:1;
52+
5153
int owner_family;
5254
union in_addr_union owner_address;
55+
56+
unsigned prioq_idx;
5357
LIST_FIELDS(DnsCacheItem, by_key);
5458
};
5559

@@ -175,7 +179,6 @@ void dns_cache_prune(DnsCache *c) {
175179
/* Remove all entries that are past their TTL */
176180

177181
for (;;) {
178-
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
179182
DnsCacheItem *i;
180183

181184
i = prioq_peek(c->by_expiry);
@@ -188,10 +191,19 @@ void dns_cache_prune(DnsCache *c) {
188191
if (i->until > t)
189192
break;
190193

191-
/* Take an extra reference to the key so that it
192-
* doesn't go away in the middle of the remove call */
193-
key = dns_resource_key_ref(i->key);
194-
dns_cache_remove(c, key);
194+
/* Depending whether this is an mDNS shared entry
195+
* either remove only this one RR or the whole
196+
* RRset */
197+
if (i->shared_owner)
198+
dns_cache_item_remove_and_free(c, i);
199+
else {
200+
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
201+
202+
/* Take an extra reference to the key so that it
203+
* doesn't go away in the middle of the remove call */
204+
key = dns_resource_key_ref(i->key);
205+
dns_cache_remove(c, key);
206+
}
195207
}
196208
}
197209

@@ -260,10 +272,20 @@ static DnsCacheItem* dns_cache_get(DnsCache *c, DnsResourceRecord *rr) {
260272
return NULL;
261273
}
262274

263-
static void dns_cache_item_update_positive(DnsCache *c, DnsCacheItem *i, DnsResourceRecord *rr, bool authenticated, usec_t timestamp) {
275+
static void dns_cache_item_update_positive(
276+
DnsCache *c,
277+
DnsCacheItem *i,
278+
DnsResourceRecord *rr,
279+
bool authenticated,
280+
bool shared_owner,
281+
usec_t timestamp,
282+
int owner_family,
283+
const union in_addr_union *owner_address) {
284+
264285
assert(c);
265286
assert(i);
266287
assert(rr);
288+
assert(owner_address);
267289

268290
i->type = DNS_CACHE_POSITIVE;
269291

@@ -280,8 +302,12 @@ static void dns_cache_item_update_positive(DnsCache *c, DnsCacheItem *i, DnsReso
280302
dns_resource_key_unref(i->key);
281303
i->key = dns_resource_key_ref(rr->key);
282304

283-
i->authenticated = authenticated;
284305
i->until = timestamp + MIN(rr->ttl * USEC_PER_SEC, CACHE_TTL_MAX_USEC);
306+
i->authenticated = authenticated;
307+
i->shared_owner = shared_owner;
308+
309+
i->owner_family = owner_family;
310+
i->owner_address = *owner_address;
285311

286312
prioq_reshuffle(c->by_expiry, i, &i->prioq_idx);
287313
}
@@ -290,6 +316,7 @@ static int dns_cache_put_positive(
290316
DnsCache *c,
291317
DnsResourceRecord *rr,
292318
bool authenticated,
319+
bool shared_owner,
293320
usec_t timestamp,
294321
int owner_family,
295322
const union in_addr_union *owner_address) {
@@ -327,10 +354,18 @@ static int dns_cache_put_positive(
327354
return 0;
328355
}
329356

330-
/* Entry exists already? Update TTL and timestamp */
357+
/* Entry exists already? Update TTL, timestamp and owner*/
331358
existing = dns_cache_get(c, rr);
332359
if (existing) {
333-
dns_cache_item_update_positive(c, existing, rr, authenticated, timestamp);
360+
dns_cache_item_update_positive(
361+
c,
362+
existing,
363+
rr,
364+
authenticated,
365+
shared_owner,
366+
timestamp,
367+
owner_family,
368+
owner_address);
334369
return 0;
335370
}
336371

@@ -349,10 +384,11 @@ static int dns_cache_put_positive(
349384
i->key = dns_resource_key_ref(rr->key);
350385
i->rr = dns_resource_record_ref(rr);
351386
i->until = timestamp + MIN(i->rr->ttl * USEC_PER_SEC, CACHE_TTL_MAX_USEC);
352-
i->prioq_idx = PRIOQ_IDX_NULL;
387+
i->authenticated = authenticated;
388+
i->shared_owner = shared_owner;
353389
i->owner_family = owner_family;
354390
i->owner_address = *owner_address;
355-
i->authenticated = authenticated;
391+
i->prioq_idx = PRIOQ_IDX_NULL;
356392

357393
r = dns_cache_link_item(c, i);
358394
if (r < 0)
@@ -363,7 +399,7 @@ static int dns_cache_put_positive(
363399
if (r < 0)
364400
return r;
365401

366-
log_debug("Added cache entry for %s", key_str);
402+
log_debug("Added positive cache entry for %s", key_str);
367403
}
368404

369405
i = NULL;
@@ -424,10 +460,10 @@ static int dns_cache_put_negative(
424460

425461
i->type = rcode == DNS_RCODE_SUCCESS ? DNS_CACHE_NODATA : DNS_CACHE_NXDOMAIN;
426462
i->until = timestamp + MIN(soa_ttl * USEC_PER_SEC, CACHE_TTL_MAX_USEC);
427-
i->prioq_idx = PRIOQ_IDX_NULL;
463+
i->authenticated = authenticated;
428464
i->owner_family = owner_family;
429465
i->owner_address = *owner_address;
430-
i->authenticated = authenticated;
466+
i->prioq_idx = PRIOQ_IDX_NULL;
431467

432468
if (i->type == DNS_CACHE_NXDOMAIN) {
433469
/* NXDOMAIN entries should apply equally to all types, so we use ANY as
@@ -454,6 +490,36 @@ static int dns_cache_put_negative(
454490
return 0;
455491
}
456492

493+
static void dns_cache_remove_previous(
494+
DnsCache *c,
495+
DnsResourceKey *key,
496+
DnsAnswer *answer) {
497+
498+
DnsResourceRecord *rr;
499+
DnsAnswerFlags flags;
500+
501+
assert(c);
502+
503+
/* First, if we were passed a key (i.e. on LLMNR/DNS, but
504+
* not on mDNS), delete all matching old RRs, so that we only
505+
* keep complete by_key in place. */
506+
if (key)
507+
dns_cache_remove(c, key);
508+
509+
/* Second, flush all entries matching the answer, unless this
510+
* is an RR that is explicitly marked to be "shared" between
511+
* peers (i.e. mDNS RRs without the flush-cache bit set). */
512+
DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
513+
if ((flags & DNS_ANSWER_CACHEABLE) == 0)
514+
continue;
515+
516+
if (flags & DNS_ANSWER_SHARED_OWNER)
517+
continue;
518+
519+
dns_cache_remove(c, rr->key);
520+
}
521+
}
522+
457523
int dns_cache_put(
458524
DnsCache *c,
459525
DnsResourceKey *key,
@@ -470,12 +536,9 @@ int dns_cache_put(
470536
int r;
471537

472538
assert(c);
539+
assert(owner_address);
473540

474-
if (key) {
475-
/* First, if we were passed a key, delete all matching old RRs,
476-
* so that we only keep complete by_key in place. */
477-
dns_cache_remove(c, key);
478-
}
541+
dns_cache_remove_previous(c, key, answer);
479542

480543
if (dns_answer_size(answer) <= 0) {
481544
if (log_get_max_level() >= LOG_DEBUG) {
@@ -491,18 +554,9 @@ int dns_cache_put(
491554
return 0;
492555
}
493556

494-
DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
495-
if ((flags & DNS_ANSWER_CACHEABLE) == 0)
496-
continue;
497-
498-
if (rr->key->cache_flush)
499-
dns_cache_remove(c, rr->key);
500-
}
501-
502557
/* We only care for positive replies and NXDOMAINs, on all
503558
* other replies we will simply flush the respective entries,
504559
* and that's it */
505-
506560
if (!IN_SET(rcode, DNS_RCODE_SUCCESS, DNS_RCODE_NXDOMAIN))
507561
return 0;
508562

@@ -517,17 +571,22 @@ int dns_cache_put(
517571
timestamp = now(clock_boottime_or_monotonic());
518572

519573
/* Second, add in positive entries for all contained RRs */
520-
521574
DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
522575
if ((flags & DNS_ANSWER_CACHEABLE) == 0)
523576
continue;
524577

525-
r = dns_cache_put_positive(c, rr, flags & DNS_ANSWER_AUTHENTICATED, timestamp, owner_family, owner_address);
578+
r = dns_cache_put_positive(
579+
c,
580+
rr,
581+
flags & DNS_ANSWER_AUTHENTICATED,
582+
flags & DNS_ANSWER_SHARED_OWNER,
583+
timestamp,
584+
owner_family, owner_address);
526585
if (r < 0)
527586
goto fail;
528587
}
529588

530-
if (!key)
589+
if (!key) /* mDNS doesn't know negative caching, really */
531590
return 0;
532591

533592
/* Third, add in negative entries if the key has no RR */
@@ -561,7 +620,14 @@ int dns_cache_put(
561620
if (authenticated && (flags & DNS_ANSWER_AUTHENTICATED) == 0)
562621
return 0;
563622

564-
r = dns_cache_put_negative(c, key, rcode, authenticated, timestamp, MIN(soa->soa.minimum, soa->ttl), owner_family, owner_address);
623+
r = dns_cache_put_negative(
624+
c,
625+
key,
626+
rcode,
627+
authenticated,
628+
timestamp,
629+
MIN(soa->soa.minimum, soa->ttl),
630+
owner_family, owner_address);
565631
if (r < 0)
566632
goto fail;
567633

@@ -822,7 +888,7 @@ int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) {
822888
if (!j->rr)
823889
continue;
824890

825-
if (!dns_key_is_shared(j->rr->key))
891+
if (!j->shared_owner)
826892
continue;
827893

828894
r = dns_packet_append_rr(p, j->rr, NULL, NULL);

src/resolve/resolved-dns-packet.c

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,9 +1455,9 @@ static int dns_packet_read_type_windows(DnsPacket *p, Bitmap **types, size_t siz
14551455
return r;
14561456
}
14571457

1458-
int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) {
1458+
int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, bool *ret_cache_flush, size_t *start) {
14591459
_cleanup_free_ char *name = NULL;
1460-
bool cache_flush = true;
1460+
bool cache_flush = false;
14611461
uint16_t class, type;
14621462
DnsResourceKey *key;
14631463
size_t saved_rindex;
@@ -1483,10 +1483,10 @@ int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) {
14831483
if (p->protocol == DNS_PROTOCOL_MDNS) {
14841484
/* See RFC6762, Section 10.2 */
14851485

1486-
if (type != DNS_TYPE_OPT && (class & MDNS_RR_CACHE_FLUSH))
1486+
if (type != DNS_TYPE_OPT && (class & MDNS_RR_CACHE_FLUSH)) {
14871487
class &= ~MDNS_RR_CACHE_FLUSH;
1488-
else
1489-
cache_flush = false;
1488+
cache_flush = true;
1489+
}
14901490
}
14911491

14921492
key = dns_resource_key_new_consume(class, type, name);
@@ -1495,11 +1495,11 @@ int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) {
14951495
goto fail;
14961496
}
14971497

1498-
key->cache_flush = cache_flush;
1499-
15001498
name = NULL;
15011499
*ret = key;
15021500

1501+
if (ret_cache_flush)
1502+
*ret_cache_flush = cache_flush;
15031503
if (start)
15041504
*start = saved_rindex;
15051505

@@ -1515,19 +1515,20 @@ static bool loc_size_ok(uint8_t size) {
15151515
return m <= 9 && e <= 9 && (m > 0 || e == 0);
15161516
}
15171517

1518-
int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
1518+
int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_flush, size_t *start) {
15191519
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
15201520
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
15211521
size_t saved_rindex, offset;
15221522
uint16_t rdlength;
1523+
bool cache_flush;
15231524
int r;
15241525

15251526
assert(p);
15261527
assert(ret);
15271528

15281529
saved_rindex = p->rindex;
15291530

1530-
r = dns_packet_read_key(p, &key, NULL);
1531+
r = dns_packet_read_key(p, &key, &cache_flush, NULL);
15311532
if (r < 0)
15321533
goto fail;
15331534

@@ -1939,6 +1940,8 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
19391940
*ret = rr;
19401941
rr = NULL;
19411942

1943+
if (ret_cache_flush)
1944+
*ret_cache_flush = cache_flush;
19421945
if (start)
19431946
*start = saved_rindex;
19441947

@@ -1971,11 +1974,17 @@ int dns_packet_extract(DnsPacket *p) {
19711974

19721975
for (i = 0; i < n; i++) {
19731976
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
1977+
bool cache_flush;
19741978

1975-
r = dns_packet_read_key(p, &key, NULL);
1979+
r = dns_packet_read_key(p, &key, &cache_flush, NULL);
19761980
if (r < 0)
19771981
goto finish;
19781982

1983+
if (cache_flush) {
1984+
r = -EBADMSG;
1985+
goto finish;
1986+
}
1987+
19791988
if (!dns_type_is_valid_query(key->type)) {
19801989
r = -EBADMSG;
19811990
goto finish;
@@ -2034,7 +2043,8 @@ int dns_packet_extract(DnsPacket *p) {
20342043
* sections. */
20352044

20362045
r = dns_answer_add(answer, rr, p->ifindex,
2037-
i < DNS_PACKET_ANCOUNT(p) ? DNS_ANSWER_CACHEABLE : 0);
2046+
(i < DNS_PACKET_ANCOUNT(p) ? DNS_ANSWER_CACHEABLE : 0) |
2047+
(p->protocol == DNS_PROTOCOL_MDNS && !cache_flush ? DNS_ANSWER_SHARED_OWNER : 0));
20382048
if (r < 0)
20392049
goto finish;
20402050
}

0 commit comments

Comments
 (0)
X Tutup