a->set_items = set_free(a->set_items);
- DNS_ANSWER_FOREACH_ITEM(item, a)
+ DNS_ANSWER_FOREACH_ITEM(item, a) {
dns_resource_record_unref(item->rr);
+ dns_resource_record_unref(item->rrsig);
+ }
a->n_rrs = 0;
}
DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsAnswer, dns_answer, dns_answer_free);
-static int dns_answer_add_raw(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) {
+static int dns_answer_add_raw(
+ DnsAnswer *a,
+ DnsResourceRecord *rr,
+ int ifindex,
+ DnsAnswerFlags flags,
+ DnsResourceRecord *rrsig) {
+
int r;
assert(rr);
.rr = rr,
.ifindex = ifindex,
.flags = flags,
+ .rrsig = dns_resource_record_ref(rrsig),
};
r = set_put(a->set_items, &a->items[a->n_rrs]);
a,
item->rr,
item->ifindex,
- item->flags);
+ item->flags,
+ item->rrsig);
if (r < 0)
return r;
}
return 0;
}
-int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) {
+int dns_answer_add(
+ DnsAnswer *a,
+ DnsResourceRecord *rr,
+ int ifindex,
+ DnsAnswerFlags flags,
+ DnsResourceRecord *rrsig) {
+
DnsAnswerItem tmp, *exist;
assert(rr);
if (rr->ttl > exist->rr->ttl) {
dns_resource_record_unref(exist->rr);
exist->rr = dns_resource_record_ref(rr);
+
+ /* Update RRSIG and RR at the same time */
+ if (rrsig) {
+ dns_resource_record_ref(rrsig);
+ dns_resource_record_unref(exist->rrsig);
+ exist->rrsig = rrsig;
+ }
}
exist->flags |= flags;
return 0;
}
- return dns_answer_add_raw(a, rr, ifindex, flags);
+ return dns_answer_add_raw(a, rr, ifindex, flags, rrsig);
}
static int dns_answer_add_all(DnsAnswer *a, DnsAnswer *b) {
int r;
DNS_ANSWER_FOREACH_ITEM(item, b) {
- r = dns_answer_add(a, item->rr, item->ifindex, item->flags);
+ r = dns_answer_add(a, item->rr, item->ifindex, item->flags, item->rrsig);
if (r < 0)
return r;
}
return 0;
}
-int dns_answer_add_extend(DnsAnswer **a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) {
+int dns_answer_add_extend(
+ DnsAnswer **a,
+ DnsResourceRecord *rr,
+ int ifindex,
+ DnsAnswerFlags flags,
+ DnsResourceRecord *rrsig) {
+
int r;
assert(a);
if (r < 0)
return r;
- return dns_answer_add(*a, rr, ifindex, flags);
+ return dns_answer_add(*a, rr, ifindex, flags, rrsig);
}
int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl, int ifindex) {
soa->soa.expire = 1;
soa->soa.minimum = ttl;
- return dns_answer_add(a, soa, ifindex, DNS_ANSWER_AUTHENTICATED);
+ return dns_answer_add(a, soa, ifindex, DNS_ANSWER_AUTHENTICATED, NULL);
}
int dns_answer_match_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *ret_flags) {
if (r > 0)
continue;
- r = dns_answer_add_raw(copy, item->rr, item->ifindex, item->flags);
+ r = dns_answer_add_raw(copy, item->rr, item->ifindex, item->flags, item->rrsig);
if (r < 0)
return r;
}
/* Kill this entry */
dns_resource_record_unref((*a)->items[i].rr);
+ dns_resource_record_unref((*a)->items[i].rrsig);
+
memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1));
(*a)->n_rrs--;
continue;
if (r > 0)
continue;
- r = dns_answer_add_raw(copy, item->rr, item->ifindex, item->flags);
+ r = dns_answer_add_raw(copy, item->rr, item->ifindex, item->flags, item->rrsig);
if (r < 0)
return r;
}
/* Kill this entry */
dns_resource_record_unref((*a)->items[i].rr);
+ dns_resource_record_unref((*a)->items[i].rrsig);
memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1));
(*a)->n_rrs--;
continue;
return 1;
}
-int dns_answer_copy_by_key(DnsAnswer **a, DnsAnswer *source, const DnsResourceKey *key, DnsAnswerFlags or_flags) {
+int dns_answer_copy_by_key(
+ DnsAnswer **a,
+ DnsAnswer *source,
+ const DnsResourceKey *key,
+ DnsAnswerFlags or_flags,
+ DnsResourceRecord *rrsig) {
+
DnsAnswerItem *item;
int r;
if (r < 0)
return r;
- r = dns_answer_add(*a, item->rr, item->ifindex, item->flags|or_flags);
+ r = dns_answer_add(*a, item->rr, item->ifindex, item->flags|or_flags, item->rrsig);
if (r < 0)
return r;
}
return 0;
}
-int dns_answer_move_by_key(DnsAnswer **to, DnsAnswer **from, const DnsResourceKey *key, DnsAnswerFlags or_flags) {
+int dns_answer_move_by_key(
+ DnsAnswer **to,
+ DnsAnswer **from,
+ const DnsResourceKey *key,
+ DnsAnswerFlags or_flags,
+ DnsResourceRecord *rrsig) {
int r;
assert(to);
assert(from);
assert(key);
- r = dns_answer_copy_by_key(to, *from, key, or_flags);
+ r = dns_answer_copy_by_key(to, *from, key, or_flags, rrsig);
if (r < 0)
return r;
fputs(t, f);
- if (item->ifindex != 0 || item->flags != 0)
+ if (item->ifindex != 0 || item->rrsig || item->flags != 0)
fputs("\t;", f);
if (item->ifindex != 0)
fprintf(f, " ifindex=%i", item->ifindex);
+ if (item->rrsig)
+ fputs(" rrsig", f);
if (item->flags & DNS_ANSWER_AUTHENTICATED)
fputs(" authenticated", f);
if (item->flags & DNS_ANSWER_CACHEABLE)
struct DnsAnswerItem {
DnsResourceRecord *rr;
+ DnsResourceRecord *rrsig; /* Optionally, also store RRSIG RR that successfully validates this item */
int ifindex;
DnsAnswerFlags flags;
};
DnsAnswer *dns_answer_ref(DnsAnswer *a);
DnsAnswer *dns_answer_unref(DnsAnswer *a);
-int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags);
-int dns_answer_add_extend(DnsAnswer **a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags);
+int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags, DnsResourceRecord *rrsig);
+int dns_answer_add_extend(DnsAnswer **a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags, DnsResourceRecord *rrsig);
int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl, int ifindex);
int dns_answer_match_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *combined_flags);
int dns_answer_remove_by_key(DnsAnswer **a, const DnsResourceKey *key);
int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rr);
-int dns_answer_copy_by_key(DnsAnswer **a, DnsAnswer *source, const DnsResourceKey *key, DnsAnswerFlags or_flags);
-int dns_answer_move_by_key(DnsAnswer **to, DnsAnswer **from, const DnsResourceKey *key, DnsAnswerFlags or_flags);
+int dns_answer_copy_by_key(DnsAnswer **a, DnsAnswer *source, const DnsResourceKey *key, DnsAnswerFlags or_flags, DnsResourceRecord *rrsig);
+int dns_answer_move_by_key(DnsAnswer **to, DnsAnswer **from, const DnsResourceKey *key, DnsAnswerFlags or_flags, DnsResourceRecord *rrsig);
int dns_answer_has_dname_for_cname(DnsAnswer *a, DnsResourceRecord *cname);
return r;
}
- r = dns_answer_add(answer, rr ?: j->rr, j->ifindex, j->authenticated ? DNS_ANSWER_AUTHENTICATED : 0);
+ r = dns_answer_add(answer, rr ?: j->rr, j->ifindex, j->authenticated ? DNS_ANSWER_AUTHENTICATED : 0, NULL);
if (r < 0)
return r;
}
else
flags |= DNS_ANSWER_SECTION_ADDITIONAL;
- r = dns_answer_add(answer, rr, p->ifindex, flags);
+ r = dns_answer_add(answer, rr, p->ifindex, flags, NULL);
if (r < 0)
return r;
}
else
flags = goodbye ? (DNS_ANSWER_GOODBYE|DNS_ANSWER_CACHE_FLUSH) : DNS_ANSWER_CACHE_FLUSH;
- r = dns_answer_add(answer, i->rr, 0 , flags);
+ r = dns_answer_add(answer, i->rr, 0, flags, NULL);
if (r < 0)
return log_debug_errno(r, "Failed to add RR to announce: %m");
}
if (r < 0)
log_warning_errno(r, "Failed to add DNS-SD PTR record to MDNS zone: %m");
- r = dns_answer_add(answer, rr, 0 , 0);
+ r = dns_answer_add(answer, rr, 0, 0, NULL);
if (r < 0)
return log_debug_errno(r, "Failed to add RR to announce: %m");
}
rr->a.in_addr.s_addr = htobe32(INADDR_LOOPBACK);
- r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
+ r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED, NULL);
if (r < 0)
return r;
}
rr->aaaa.in6_addr = in6addr_loopback;
- r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
+ r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED, NULL);
if (r < 0)
return r;
}
if (!rr->ptr.name)
return -ENOMEM;
- return dns_answer_add(*answer, rr, ifindex, flags);
+ return dns_answer_add(*answer, rr, ifindex, flags, NULL);
}
static int synthesize_localhost_ptr(Manager *m, const DnsResourceKey *key, int ifindex, DnsAnswer **answer) {
if (r < 0)
return r;
- r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED);
+ r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED, NULL);
if (r < 0)
return r;
}
if (r < 0)
return r;
- r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED);
+ r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED, NULL);
if (r < 0)
return r;
}
static int dns_transaction_validate_dnskey_by_ds(DnsTransaction *t) {
- DnsResourceRecord *rr;
- int ifindex, r;
+ DnsAnswerItem *item;
+ int r;
assert(t);
* RRs from the list of validated keys to the list of
* validated keys. */
- DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, t->answer) {
+ DNS_ANSWER_FOREACH_ITEM(item, t->answer) {
- r = dnssec_verify_dnskey_by_ds_search(rr, t->validated_keys);
+ r = dnssec_verify_dnskey_by_ds_search(item->rr, t->validated_keys);
if (r < 0)
return r;
if (r == 0)
continue;
/* If so, the DNSKEY is validated too. */
- r = dns_answer_add_extend(&t->validated_keys, rr, ifindex, DNS_ANSWER_AUTHENTICATED);
+ r = dns_answer_add_extend(&t->validated_keys, item->rr, item->ifindex, item->flags|DNS_ANSWER_AUTHENTICATED, item->rrsig);
if (r < 0)
return r;
}
continue;
}
- r = dnssec_verify_rrset_search(t->answer, rr->key, t->validated_keys, USEC_INFINITY, &result, &rrsig);
+ r = dnssec_verify_rrset_search(
+ t->answer,
+ rr->key,
+ t->validated_keys,
+ USEC_INFINITY,
+ &result,
+ &rrsig);
if (r < 0)
return r;
log_debug("Looking at %s: %s", strna(dns_resource_record_to_string(rr)), dnssec_result_to_string(result));
if (result == DNSSEC_VALIDATED) {
+ assert(rrsig);
if (rr->key->type == DNS_TYPE_DNSKEY) {
/* If we just validated a DNSKEY RRset, then let's add these keys to
* the set of validated keys for this transaction. */
- r = dns_answer_copy_by_key(&t->validated_keys, t->answer, rr->key, DNS_ANSWER_AUTHENTICATED);
+ r = dns_answer_copy_by_key(&t->validated_keys, t->answer, rr->key, DNS_ANSWER_AUTHENTICATED, rrsig);
if (r < 0)
return r;
return r;
}
- /* Add the validated RRset to the new list of validated
- * RRsets, and remove it from the unvalidated RRsets.
- * We mark the RRset as authenticated and cacheable. */
- r = dns_answer_move_by_key(validated, &t->answer, rr->key, DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE);
+ /* Add the validated RRset to the new list of validated RRsets, and remove it from
+ * the unvalidated RRsets. We mark the RRset as authenticated and cacheable. */
+ r = dns_answer_move_by_key(validated, &t->answer, rr->key, DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE, rrsig);
if (r < 0)
return r;
bool authenticated = false;
const char *source;
+ assert(rrsig);
+
/* This RRset validated, but as a wildcard. This means we need
* to prove via NSEC/NSEC3 that no matching non-wildcard RR exists. */
if (r == 0)
result = DNSSEC_INVALID;
else {
- r = dns_answer_move_by_key(validated, &t->answer, rr->key,
- authenticated ? (DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE) : 0);
+ r = dns_answer_move_by_key(
+ validated,
+ &t->answer,
+ rr->key,
+ authenticated ? (DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE) : 0,
+ rrsig);
if (r < 0)
return r;
if (r == 0) {
/* Data does not require signing. In that case, just copy it over,
* but remember that this is by no means authenticated. */
- r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0);
+ r = dns_answer_move_by_key(
+ validated,
+ &t->answer,
+ rr->key,
+ 0,
+ NULL);
if (r < 0)
return r;
/* Downgrading is OK? If so, just consider the information unsigned */
- r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0);
+ r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0, NULL);
if (r < 0)
return r;
log_info("Detected RRset %s is in a private DNS zone, permitting unsigned RRs.",
dns_resource_key_to_string(rr->key, s, sizeof s));
- r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0);
+ r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0, NULL);
if (r < 0)
return r;
/* The DNSKEY transaction was not authenticated, this means there's
* no DS for this, which means it's OK if no keys are found for this signature. */
- r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0);
+ r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0, NULL);
if (r < 0)
return r;
if (!rr->ds.digest)
return -ENOMEM;
- r = dns_answer_add(answer, rr, 0, DNS_ANSWER_AUTHENTICATED);
+ r = dns_answer_add(answer, rr, 0, DNS_ANSWER_AUTHENTICATED, NULL);
if (r < 0)
return r;
old_answer = hashmap_get(d->positive_by_key, rr->key);
answer = dns_answer_ref(old_answer);
- r = dns_answer_add_extend(&answer, rr, 0, DNS_ANSWER_AUTHENTICATED);
+ r = dns_answer_add_extend(&answer, rr, 0, DNS_ANSWER_AUTHENTICATED, NULL);
if (r < 0)
return log_error_errno(r, "Failed to add trust anchor RR: %m");
else
flags = DNS_ANSWER_AUTHENTICATED;
- return dns_answer_add(a, i->rr, ifindex, flags);
+ return dns_answer_add(a, i->rr, ifindex, flags, NULL);
}
int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, int ifindex, DnsAnswer **ret_answer, DnsAnswer **ret_soa, bool *ret_tentative) {
if (!rr->ptr.name)
return -ENOMEM;
- r = dns_answer_add(*answer, rr, 0, DNS_ANSWER_AUTHENTICATED);
+ r = dns_answer_add(*answer, rr, 0, DNS_ANSWER_AUTHENTICATED, NULL);
if (r < 0)
return r;
}
if (r < 0)
return r;
- r = dns_answer_add(*answer, rr, 0, DNS_ANSWER_AUTHENTICATED);
+ r = dns_answer_add(*answer, rr, 0, DNS_ANSWER_AUTHENTICATED, NULL);
if (r < 0)
return r;
}
answer = dns_answer_new(1);
assert_se(answer);
- assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
+ assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
assert_se(dnssec_verify_rrset(answer, mx->key, rrsig, dnskey,
rrsig->rrsig.inception * USEC_PER_SEC, &result) >= 0);
answer = dns_answer_new(1);
assert_se(answer);
- assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
+ assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
assert_se(dnssec_verify_rrset(answer, mx->key, rrsig, dnskey,
rrsig->rrsig.inception * USEC_PER_SEC, &result) >= 0);
answer = dns_answer_new(1);
assert_se(answer);
- assert_se(dns_answer_add(answer, a, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
+ assert_se(dns_answer_add(answer, a, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
/* Validate the RR as it if was 2015-12-2 today */
assert_se(dnssec_verify_rrset(answer, a->key, rrsig, dnskey, 1449092754*USEC_PER_SEC, &result) >= 0);
answer = dns_answer_new(1);
assert_se(answer);
- assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
+ assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
/* Validate the RR as it if was 2015-12-11 today */
assert_se(dnssec_verify_rrset(answer, nsec->key, rrsig, dnskey, 1449849318*USEC_PER_SEC, &result) >= 0);
answer = dns_answer_new(4);
assert_se(answer);
- assert_se(dns_answer_add(answer, mx1, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
- assert_se(dns_answer_add(answer, mx2, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
- assert_se(dns_answer_add(answer, mx3, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
- assert_se(dns_answer_add(answer, mx4, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
+ assert_se(dns_answer_add(answer, mx1, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
+ assert_se(dns_answer_add(answer, mx2, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
+ assert_se(dns_answer_add(answer, mx3, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
+ assert_se(dns_answer_add(answer, mx4, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
/* Validate the RR as it if was 2020-02-24 today */
assert_se(dnssec_verify_rrset(answer, mx1->key, rrsig, dnskey, 1582534685*USEC_PER_SEC, &result) >= 0);