diff --git a/src/resolve/resolved-dns-browse-services.c b/src/resolve/resolved-dns-browse-services.c index 6a48089a59..8b5544c01a 100644 --- a/src/resolve/resolved-dns-browse-services.c +++ b/src/resolve/resolved-dns-browse-services.c @@ -178,8 +178,8 @@ int dns_add_new_service(DnsServiceBrowser *sb, DnsResourceRecord *rr, int owner_ .query = NULL, .rr_ttl_state = DNS_RECORD_TTL_STATE_80_PERCENT, }; - - LIST_PREPEND(dns_services, sb->dns_services, s); + if (!s->rr) + return log_oom(); /* Schedule the first cache maintenance query at 80% of the record's * TTL. Subsequent queries issued at 5% increments until 100% of the @@ -219,6 +219,8 @@ int dns_add_new_service(DnsServiceBrowser *sb, DnsResourceRecord *rr, int owner_ r, "Failed to schedule mDNS maintenance query for DNS service: %m"); + LIST_PREPEND(dns_services, sb->dns_services, s); + TAKE_PTR(s); return 0; } diff --git a/src/resolve/resolved-dns-zone.c b/src/resolve/resolved-dns-zone.c index c005342958..48dce9d742 100644 --- a/src/resolve/resolved-dns-zone.c +++ b/src/resolve/resolved-dns-zone.c @@ -161,8 +161,15 @@ static int dns_zone_link_item(DnsZone *z, DnsZoneItem *i) { assert_se(hashmap_replace(z->by_name, dns_resource_key_name(first->rr->key), first) >= 0); } else { r = hashmap_put(z->by_name, dns_resource_key_name(i->rr->key), i); - if (r < 0) + if (r < 0) { + first = hashmap_get(z->by_key, i->rr->key); + LIST_REMOVE(by_key, first, i); + if (first) + assert_se(hashmap_replace(z->by_key, first->rr->key, first) >= 0); + else + hashmap_remove(z->by_key, i->rr->key); return r; + } } return 0; diff --git a/src/resolve/test-dns-answer.c b/src/resolve/test-dns-answer.c index 2454ca1c06..aea1ebcc3c 100644 --- a/src/resolve/test-dns-answer.c +++ b/src/resolve/test-dns-answer.c @@ -371,6 +371,23 @@ TEST(dns_answer_remove_by_rr) { ASSERT_NULL(answer); } +TEST(dns_answer_remove_shared) { + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = prepare_answer(), *alias = NULL; + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; + + alias = dns_answer_ref(answer); + ASSERT_PTR_EQ(alias, answer); + + rr = ASSERT_NOT_NULL(dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, "b.example.com")); + rr->a.in_addr.s_addr = htobe32(0xc0a8017f); + + ASSERT_OK_POSITIVE(dns_answer_remove_by_rr(&answer, rr)); + ASSERT_EQ(dns_answer_size(answer), 2u); + ASSERT_EQ(dns_answer_size(alias), 3u); + ASSERT_FALSE(dns_answer_contains(answer, rr)); + ASSERT_TRUE(dns_answer_contains(alias, rr)); +} + TEST(dns_answer_remove_by_answer_keys) { _cleanup_(dns_answer_unrefp) DnsAnswer *a = prepare_answer(), *b = prepare_answer(); DnsResourceKey *key; diff --git a/src/shared/dns-answer.c b/src/shared/dns-answer.c index 24174d2bd2..037ad207ef 100644 --- a/src/shared/dns-answer.c +++ b/src/shared/dns-answer.c @@ -555,14 +555,28 @@ int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rr) { if (r < 0) return r; if (r > 0) { - dns_answer_item_unref(ordered_set_remove((*a)->items, item)); found = true; + break; } } if (!found) return 0; + if ((*a)->n_ref > 1) { + r = dns_answer_reserve_or_clone(a, 1); + if (r < 0) + return r; + } + + DNS_ANSWER_FOREACH_ITEM(item, *a) { + r = dns_resource_record_equal(item->rr, rr); + if (r < 0) + return r; + if (r > 0) + dns_answer_item_unref(ordered_set_remove((*a)->items, item)); + } + if (dns_answer_isempty(*a)) *a = dns_answer_unref(*a); /* Return NULL for the empty answer */