@@ -43,6 +43,8 @@ struct DnsCacheItem {
4343 usec_t until ;
4444 DnsCacheItemType type ;
4545 unsigned prioq_idx ;
46+ int owner_family ;
47+ union in_addr_union owner_address ;
4648 LIST_FIELDS (DnsCacheItem , by_key );
4749};
4850
@@ -256,13 +258,20 @@ static void dns_cache_item_update_positive(DnsCache *c, DnsCacheItem *i, DnsReso
256258 prioq_reshuffle (c -> by_expiry , i , & i -> prioq_idx );
257259}
258260
259- static int dns_cache_put_positive (DnsCache * c , DnsResourceRecord * rr , usec_t timestamp ) {
261+ static int dns_cache_put_positive (
262+ DnsCache * c ,
263+ DnsResourceRecord * rr ,
264+ usec_t timestamp ,
265+ int owner_family ,
266+ const union in_addr_union * owner_address ) {
267+
260268 _cleanup_ (dns_cache_item_freep ) DnsCacheItem * i = NULL ;
261269 DnsCacheItem * existing ;
262270 int r ;
263271
264272 assert (c );
265273 assert (rr );
274+ assert (owner_address );
266275
267276 /* New TTL is 0? Delete the entry... */
268277 if (rr -> ttl <= 0 ) {
@@ -298,6 +307,8 @@ static int dns_cache_put_positive(DnsCache *c, DnsResourceRecord *rr, usec_t tim
298307 i -> rr = dns_resource_record_ref (rr );
299308 i -> until = timestamp + MIN (i -> rr -> ttl * USEC_PER_SEC , CACHE_TTL_MAX_USEC );
300309 i -> prioq_idx = PRIOQ_IDX_NULL ;
310+ i -> owner_family = owner_family ;
311+ i -> owner_address = * owner_address ;
301312
302313 r = dns_cache_link_item (c , i );
303314 if (r < 0 )
@@ -307,12 +318,21 @@ static int dns_cache_put_positive(DnsCache *c, DnsResourceRecord *rr, usec_t tim
307318 return 0 ;
308319}
309320
310- static int dns_cache_put_negative (DnsCache * c , DnsResourceKey * key , int rcode , usec_t timestamp , uint32_t soa_ttl ) {
321+ static int dns_cache_put_negative (
322+ DnsCache * c ,
323+ DnsResourceKey * key ,
324+ int rcode ,
325+ usec_t timestamp ,
326+ uint32_t soa_ttl ,
327+ int owner_family ,
328+ const union in_addr_union * owner_address ) {
329+
311330 _cleanup_ (dns_cache_item_freep ) DnsCacheItem * i = NULL ;
312331 int r ;
313332
314333 assert (c );
315334 assert (key );
335+ assert (owner_address );
316336
317337 dns_cache_remove (c , key );
318338
@@ -340,6 +360,8 @@ static int dns_cache_put_negative(DnsCache *c, DnsResourceKey *key, int rcode, u
340360 i -> key = dns_resource_key_ref (key );
341361 i -> until = timestamp + MIN (soa_ttl * USEC_PER_SEC , CACHE_TTL_MAX_USEC );
342362 i -> prioq_idx = PRIOQ_IDX_NULL ;
363+ i -> owner_family = owner_family ;
364+ i -> owner_address = * owner_address ;
343365
344366 r = dns_cache_link_item (c , i );
345367 if (r < 0 )
@@ -349,7 +371,16 @@ static int dns_cache_put_negative(DnsCache *c, DnsResourceKey *key, int rcode, u
349371 return 0 ;
350372}
351373
352- int dns_cache_put (DnsCache * c , DnsQuestion * q , int rcode , DnsAnswer * answer , unsigned max_rrs , usec_t timestamp ) {
374+ int dns_cache_put (
375+ DnsCache * c ,
376+ DnsQuestion * q ,
377+ int rcode ,
378+ DnsAnswer * answer ,
379+ unsigned max_rrs ,
380+ usec_t timestamp ,
381+ int owner_family ,
382+ const union in_addr_union * owner_address ) {
383+
353384 unsigned i ;
354385 int r ;
355386
@@ -382,7 +413,7 @@ int dns_cache_put(DnsCache *c, DnsQuestion *q, int rcode, DnsAnswer *answer, uns
382413
383414 /* Second, add in positive entries for all contained RRs */
384415 for (i = 0 ; i < MIN (max_rrs , answer -> n_rrs ); i ++ ) {
385- r = dns_cache_put_positive (c , answer -> rrs [i ], timestamp );
416+ r = dns_cache_put_positive (c , answer -> rrs [i ], timestamp , owner_family , owner_address );
386417 if (r < 0 )
387418 goto fail ;
388419 }
@@ -403,7 +434,7 @@ int dns_cache_put(DnsCache *c, DnsQuestion *q, int rcode, DnsAnswer *answer, uns
403434 if (r == 0 )
404435 continue ;
405436
406- r = dns_cache_put_negative (c , q -> keys [i ], rcode , timestamp , MIN (soa -> soa .minimum , soa -> ttl ));
437+ r = dns_cache_put_negative (c , q -> keys [i ], rcode , timestamp , MIN (soa -> soa .minimum , soa -> ttl ), owner_family , owner_address );
407438 if (r < 0 )
408439 goto fail ;
409440 }
@@ -495,3 +526,39 @@ int dns_cache_lookup(DnsCache *c, DnsQuestion *q, int *rcode, DnsAnswer **ret) {
495526
496527 return n ;
497528}
529+
530+ int dns_cache_check_conflicts (DnsCache * cache , DnsResourceRecord * rr , int owner_family , const union in_addr_union * owner_address ) {
531+ DnsCacheItem * i , * first ;
532+ bool same_owner = true;
533+
534+ assert (cache );
535+ assert (rr );
536+
537+ dns_cache_prune (cache );
538+
539+ /* See if there's a cache entry for the same key. If there
540+ * isn't there's no conflict */
541+ first = hashmap_get (cache -> by_key , rr -> key );
542+ if (!first )
543+ return 0 ;
544+
545+ /* See if the RR key is owned by the same owner, if so, there
546+ * isn't a conflict either */
547+ LIST_FOREACH (by_key , i , first ) {
548+ if (i -> owner_family != owner_family ||
549+ !in_addr_equal (owner_family , & i -> owner_address , owner_address )) {
550+ same_owner = false;
551+ break ;
552+ }
553+ }
554+ if (same_owner )
555+ return 0 ;
556+
557+ /* See if there's the exact same RR in the cache. If yes, then
558+ * there's no conflict. */
559+ if (dns_cache_get (cache , rr ))
560+ return 0 ;
561+
562+ /* There's a conflict */
563+ return 1 ;
564+ }
0 commit comments