summaryrefslogtreecommitdiff
path: root/src/resolve/resolved-dns-answer.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2015-08-17 23:54:08 +0200
committerLennart Poettering <lennart@poettering.net>2015-08-21 12:41:08 +0200
commit78c6a153c47f8d597c827bdcaf8c4e42ac87f738 (patch)
treec0b378f70987c6de3cbbcc02fd6cc2c6549d2a3a /src/resolve/resolved-dns-answer.c
parent8013e860b6344cb109e68208a3a91b0fc3cb9ed1 (diff)
resolved: rework synthesizing logic
With this change we'll now also generate synthesized RRs for the local LLMNR hostname (first label of system hostname), the local mDNS hostname (first label of system hostname suffixed with .local), the "gateway" hostname and all the reverse PTRs. This hence takes over part of what nss-myhostname already implemented. Local hostnames resolve to the set of local IP addresses. Since the addresses are possibly on different interfaces it is necessary to change the internal DnsAnswer object to track per-RR interface indexes, and to change the bus API to always return the interface per-address rather than per-reply. This change also patches the existing clients for resolved accordingly (nss-resolve + systemd-resolve-host). This also changes the routing logic for queries slightly: we now ensure that the local hostname is never resolved via LLMNR, thus making it trustable on the local system.
Diffstat (limited to 'src/resolve/resolved-dns-answer.c')
-rw-r--r--src/resolve/resolved-dns-answer.c102
1 files changed, 74 insertions, 28 deletions
diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c
index f77b98e505..13ad4ca6bd 100644
--- a/src/resolve/resolved-dns-answer.c
+++ b/src/resolve/resolved-dns-answer.c
@@ -25,7 +25,7 @@
DnsAnswer *dns_answer_new(unsigned n) {
DnsAnswer *a;
- a = malloc0(offsetof(DnsAnswer, rrs) + sizeof(DnsResourceRecord*) * n);
+ a = malloc0(offsetof(DnsAnswer, items) + sizeof(DnsAnswerItem) * n);
if (!a)
return NULL;
@@ -54,7 +54,7 @@ DnsAnswer *dns_answer_unref(DnsAnswer *a) {
unsigned i;
for (i = 0; i < a->n_rrs; i++)
- dns_resource_record_unref(a->rrs[i]);
+ dns_resource_record_unref(a->items[i].rr);
free(a);
} else
@@ -63,25 +63,30 @@ DnsAnswer *dns_answer_unref(DnsAnswer *a) {
return NULL;
}
-int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr) {
+int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex) {
unsigned i;
int r;
- assert(a);
assert(rr);
+ if (!a)
+ return -ENOSPC;
+
for (i = 0; i < a->n_rrs; i++) {
- r = dns_resource_record_equal(a->rrs[i], rr);
+ if (a->items[i].ifindex != ifindex)
+ continue;
+
+ r = dns_resource_record_equal(a->items[i].rr, rr);
if (r < 0)
return r;
if (r > 0) {
/* Entry already exists, keep the entry with
* the higher RR, or the one with TTL 0 */
- if (rr->ttl == 0 || (rr->ttl > a->rrs[i]->ttl && a->rrs[i]->ttl != 0)) {
+ if (rr->ttl == 0 || (rr->ttl > a->items[i].rr->ttl && a->items[i].rr->ttl != 0)) {
dns_resource_record_ref(rr);
- dns_resource_record_unref(a->rrs[i]);
- a->rrs[i] = rr;
+ dns_resource_record_unref(a->items[i].rr);
+ a->items[i].rr = rr;
}
return 0;
@@ -91,7 +96,10 @@ int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr) {
if (a->n_rrs >= a->n_allocated)
return -ENOSPC;
- a->rrs[a->n_rrs++] = dns_resource_record_ref(rr);
+ a->items[a->n_rrs].rr = dns_resource_record_ref(rr);
+ a->items[a->n_rrs].ifindex = ifindex;
+ a->n_rrs++;
+
return 1;
}
@@ -118,18 +126,20 @@ int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl) {
soa->soa.expire = 1;
soa->soa.minimum = ttl;
- return dns_answer_add(a, soa);
+ return dns_answer_add(a, soa, 0);
}
int dns_answer_contains(DnsAnswer *a, DnsResourceKey *key) {
unsigned i;
int r;
- assert(a);
assert(key);
+ if (!a)
+ return 0;
+
for (i = 0; i < a->n_rrs; i++) {
- r = dns_resource_key_match_rr(key, a->rrs[i]);
+ r = dns_resource_key_match_rr(key, a->items[i].rr);
if (r < 0)
return r;
if (r > 0)
@@ -142,24 +152,26 @@ int dns_answer_contains(DnsAnswer *a, DnsResourceKey *key) {
int dns_answer_find_soa(DnsAnswer *a, DnsResourceKey *key, DnsResourceRecord **ret) {
unsigned i;
- assert(a);
assert(key);
assert(ret);
+ if (!a)
+ return 0;
+
/* For a SOA record we can never find a matching SOA record */
if (key->type == DNS_TYPE_SOA)
return 0;
for (i = 0; i < a->n_rrs; i++) {
- if (a->rrs[i]->key->class != DNS_CLASS_IN)
+ if (a->items[i].rr->key->class != DNS_CLASS_IN)
continue;
- if (a->rrs[i]->key->type != DNS_TYPE_SOA)
+ if (a->items[i].rr->key->type != DNS_TYPE_SOA)
continue;
- if (dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(a->rrs[i]->key))) {
- *ret = a->rrs[i];
+ if (dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(a->items[i].rr->key))) {
+ *ret = a->items[i].rr;
return 1;
}
}
@@ -184,7 +196,7 @@ DnsAnswer *dns_answer_merge(DnsAnswer *a, DnsAnswer *b) {
if (a) {
for (i = 0; i < a->n_rrs; i++) {
- r = dns_answer_add(ret, a->rrs[i]);
+ r = dns_answer_add(ret, a->items[i].rr, a->items[i].ifindex);
if (r < 0)
return NULL;
}
@@ -192,7 +204,7 @@ DnsAnswer *dns_answer_merge(DnsAnswer *a, DnsAnswer *b) {
if (b) {
for (i = 0; i < b->n_rrs; i++) {
- r = dns_answer_add(ret, b->rrs[i]);
+ r = dns_answer_add(ret, b->items[i].rr, b->items[i].ifindex);
if (r < 0)
return NULL;
}
@@ -205,9 +217,11 @@ DnsAnswer *dns_answer_merge(DnsAnswer *a, DnsAnswer *b) {
}
void dns_answer_order_by_scope(DnsAnswer *a, bool prefer_link_local) {
- DnsResourceRecord **rrs;
+ DnsAnswerItem *items;
unsigned i, start, end;
- assert(a);
+
+ if (!a)
+ return;
if (a->n_rrs <= 1)
return;
@@ -218,19 +232,51 @@ void dns_answer_order_by_scope(DnsAnswer *a, bool prefer_link_local) {
/* RFC 4795, Section 2.6 suggests we should order entries
* depending on whether the sender is a link-local address. */
- rrs = newa(DnsResourceRecord*, a->n_rrs);
+ items = newa(DnsAnswerItem, a->n_rrs);
for (i = 0; i < a->n_rrs; i++) {
- if (a->rrs[i]->key->class == DNS_CLASS_IN &&
- ((a->rrs[i]->key->type == DNS_TYPE_A && in_addr_is_link_local(AF_INET, (union in_addr_union*) &a->rrs[i]->a.in_addr) != prefer_link_local) ||
- (a->rrs[i]->key->type == DNS_TYPE_AAAA && in_addr_is_link_local(AF_INET6, (union in_addr_union*) &a->rrs[i]->aaaa.in6_addr) != prefer_link_local)))
+ if (a->items[i].rr->key->class == DNS_CLASS_IN &&
+ ((a->items[i].rr->key->type == DNS_TYPE_A && in_addr_is_link_local(AF_INET, (union in_addr_union*) &a->items[i].rr->a.in_addr) != prefer_link_local) ||
+ (a->items[i].rr->key->type == DNS_TYPE_AAAA && in_addr_is_link_local(AF_INET6, (union in_addr_union*) &a->items[i].rr->aaaa.in6_addr) != prefer_link_local)))
/* Order address records that are are not preferred to the end of the array */
- rrs[end--] = a->rrs[i];
+ items[end--] = a->items[i];
else
/* Order all other records to the beginning of the array */
- rrs[start++] = a->rrs[i];
+ items[start++] = a->items[i];
}
assert(start == end+1);
- memcpy(a->rrs, rrs, sizeof(DnsResourceRecord*) * a->n_rrs);
+ memcpy(a->items, items, sizeof(DnsAnswerItem) * a->n_rrs);
+}
+
+int dns_answer_reserve(DnsAnswer **a, unsigned n_free) {
+ DnsAnswer *n;
+
+ if (n_free <= 0)
+ return 0;
+
+ if (*a) {
+ unsigned ns;
+
+ if ((*a)->n_ref > 1)
+ return -EBUSY;
+
+ ns = (*a)->n_rrs + n_free;
+
+ if ((*a)->n_allocated >= ns)
+ return 0;
+
+ n = realloc(*a, offsetof(DnsAnswer, items) + sizeof(DnsAnswerItem) * ns);
+ if (!n)
+ return -ENOMEM;
+
+ n->n_allocated = ns;
+ } else {
+ n = dns_answer_new(n_free);
+ if (!n)
+ return -ENOMEM;
+ }
+
+ *a = n;
+ return 0;
}