@@ -42,14 +42,18 @@ enum DnsCacheItemType {
4242};
4343
4444struct 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+
457523int 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 );
0 commit comments