2014-07-16 00:26:02 +02:00
|
|
|
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
|
|
|
|
|
|
|
/***
|
|
|
|
This file is part of systemd.
|
|
|
|
|
|
|
|
Copyright 2014 Lennart Poettering
|
|
|
|
|
|
|
|
systemd is free software; you can redistribute it and/or modify it
|
|
|
|
under the terms of the GNU Lesser General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
systemd is distributed in the hope that it will be useful, but
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
|
|
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
***/
|
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2015-08-14 13:17:05 +02:00
|
|
|
#include "dns-domain.h"
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "hostname-util.h"
|
2015-08-17 23:54:08 +02:00
|
|
|
#include "local-addresses.h"
|
2014-07-16 00:26:02 +02:00
|
|
|
#include "resolved-dns-query.h"
|
|
|
|
|
2014-07-30 01:47:48 +02:00
|
|
|
/* How long to wait for the query in total */
|
2014-07-16 00:26:02 +02:00
|
|
|
#define QUERY_TIMEOUT_USEC (30 * USEC_PER_SEC)
|
2014-07-30 01:47:48 +02:00
|
|
|
|
2014-07-16 22:09:00 +02:00
|
|
|
#define CNAME_MAX 8
|
2014-07-17 01:58:14 +02:00
|
|
|
#define QUERIES_MAX 2048
|
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
|
|
|
#define AUXILIARY_QUERIES_MAX 64
|
2014-07-16 22:09:00 +02:00
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
static int dns_query_candidate_new(DnsQueryCandidate **ret, DnsQuery *q, DnsScope *s) {
|
|
|
|
DnsQueryCandidate *c;
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
assert(ret);
|
2014-07-22 21:48:41 +02:00
|
|
|
assert(q);
|
2015-11-25 20:47:27 +01:00
|
|
|
assert(s);
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
c = new0(DnsQueryCandidate, 1);
|
|
|
|
if (!c)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
c->query = q;
|
|
|
|
c->scope = s;
|
|
|
|
|
|
|
|
LIST_PREPEND(candidates_by_query, q->candidates, c);
|
|
|
|
LIST_PREPEND(candidates_by_scope, s->query_candidates, c);
|
|
|
|
|
|
|
|
*ret = c;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dns_query_candidate_stop(DnsQueryCandidate *c) {
|
|
|
|
DnsTransaction *t;
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
assert(c);
|
|
|
|
|
|
|
|
while ((t = set_steal_first(c->transactions))) {
|
resolved: chase DNSKEY/DS RRs when doing look-ups with DNSSEC enabled
This adds initial support for validating RRSIG/DNSKEY/DS chains when
doing lookups. Proof-of-non-existance, or proof-of-unsigned-zones is not
implemented yet.
With this change DnsTransaction objects will generate additional
DnsTransaction objects when looking for DNSKEY or DS RRs to validate an
RRSIG on a response. DnsTransaction objects are thus created for three
reasons now:
1) Because a user asked for something to be resolved, i.e. requested by
a DnsQuery/DnsQueryCandidate object.
2) As result of LLMNR RR probing, requested by a DnsZoneItem.
3) Because another DnsTransaction requires the requested RRs for
validation of its own response.
DnsTransactions are shared between all these users, and are GC
automatically as soon as all of these users don't need a specific
transaction anymore.
To unify the handling of these three reasons for existance for a
DnsTransaction, a new common naming is introduced: each DnsTransaction
now tracks its "owners" via a Set* object named "notify_xyz", containing
all owners to notify on completion.
A new DnsTransaction state is introduced called "VALIDATING" that is
entered after a response has been receieved which needs to be validated,
as long as we are still waiting for the DNSKEY/DS RRs from other
DnsTransactions.
This patch will request the DNSKEY/DS RRs bottom-up, and then validate
them top-down.
Caching of RRs is now only done after verification, so that the cache is
not poisoned with known invalid data.
The "DnsAnswer" object gained a substantial number of new calls, since
we need to add/remove RRs to it dynamically now.
2015-12-09 18:13:16 +01:00
|
|
|
set_remove(t->notify_query_candidates, c);
|
2014-07-31 17:46:40 +02:00
|
|
|
dns_transaction_gc(t);
|
2014-07-16 00:26:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c) {
|
|
|
|
|
|
|
|
if (!c)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
dns_query_candidate_stop(c);
|
|
|
|
|
|
|
|
set_free(c->transactions);
|
|
|
|
dns_search_domain_unref(c->search_domain);
|
|
|
|
|
|
|
|
if (c->query)
|
|
|
|
LIST_REMOVE(candidates_by_query, c->query->candidates, c);
|
|
|
|
|
|
|
|
if (c->scope)
|
|
|
|
LIST_REMOVE(candidates_by_scope, c->scope->query_candidates, c);
|
|
|
|
|
|
|
|
free(c);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dns_query_candidate_next_search_domain(DnsQueryCandidate *c) {
|
|
|
|
DnsSearchDomain *next = NULL;
|
|
|
|
|
|
|
|
assert(c);
|
|
|
|
|
|
|
|
if (c->search_domain && c->search_domain->linked) {
|
|
|
|
next = c->search_domain->domains_next;
|
|
|
|
|
2015-11-27 00:06:19 +01:00
|
|
|
if (!next) /* We hit the end of the list */
|
|
|
|
return 0;
|
2015-11-25 20:47:27 +01:00
|
|
|
|
|
|
|
} else {
|
|
|
|
next = dns_scope_get_search_domains(c->scope);
|
|
|
|
|
2015-11-27 00:06:19 +01:00
|
|
|
if (!next) /* OK, there's nothing. */
|
2015-11-25 20:47:27 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_search_domain_unref(c->search_domain);
|
|
|
|
c->search_domain = dns_search_domain_ref(next);
|
2015-11-27 00:06:19 +01:00
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResourceKey *key) {
|
|
|
|
DnsTransaction *t;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(c);
|
|
|
|
assert(key);
|
|
|
|
|
|
|
|
t = dns_scope_find_transaction(c->scope, key, true);
|
|
|
|
if (!t) {
|
|
|
|
r = dns_transaction_new(&t, c->scope, key);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
resolved: chase DNSKEY/DS RRs when doing look-ups with DNSSEC enabled
This adds initial support for validating RRSIG/DNSKEY/DS chains when
doing lookups. Proof-of-non-existance, or proof-of-unsigned-zones is not
implemented yet.
With this change DnsTransaction objects will generate additional
DnsTransaction objects when looking for DNSKEY or DS RRs to validate an
RRSIG on a response. DnsTransaction objects are thus created for three
reasons now:
1) Because a user asked for something to be resolved, i.e. requested by
a DnsQuery/DnsQueryCandidate object.
2) As result of LLMNR RR probing, requested by a DnsZoneItem.
3) Because another DnsTransaction requires the requested RRs for
validation of its own response.
DnsTransactions are shared between all these users, and are GC
automatically as soon as all of these users don't need a specific
transaction anymore.
To unify the handling of these three reasons for existance for a
DnsTransaction, a new common naming is introduced: each DnsTransaction
now tracks its "owners" via a Set* object named "notify_xyz", containing
all owners to notify on completion.
A new DnsTransaction state is introduced called "VALIDATING" that is
entered after a response has been receieved which needs to be validated,
as long as we are still waiting for the DNSKEY/DS RRs from other
DnsTransactions.
This patch will request the DNSKEY/DS RRs bottom-up, and then validate
them top-down.
Caching of RRs is now only done after verification, so that the cache is
not poisoned with known invalid data.
The "DnsAnswer" object gained a substantial number of new calls, since
we need to add/remove RRs to it dynamically now.
2015-12-09 18:13:16 +01:00
|
|
|
} else {
|
|
|
|
if (set_contains(c->transactions, t))
|
|
|
|
return 0;
|
2015-11-25 20:47:27 +01:00
|
|
|
}
|
|
|
|
|
resolved: chase DNSKEY/DS RRs when doing look-ups with DNSSEC enabled
This adds initial support for validating RRSIG/DNSKEY/DS chains when
doing lookups. Proof-of-non-existance, or proof-of-unsigned-zones is not
implemented yet.
With this change DnsTransaction objects will generate additional
DnsTransaction objects when looking for DNSKEY or DS RRs to validate an
RRSIG on a response. DnsTransaction objects are thus created for three
reasons now:
1) Because a user asked for something to be resolved, i.e. requested by
a DnsQuery/DnsQueryCandidate object.
2) As result of LLMNR RR probing, requested by a DnsZoneItem.
3) Because another DnsTransaction requires the requested RRs for
validation of its own response.
DnsTransactions are shared between all these users, and are GC
automatically as soon as all of these users don't need a specific
transaction anymore.
To unify the handling of these three reasons for existance for a
DnsTransaction, a new common naming is introduced: each DnsTransaction
now tracks its "owners" via a Set* object named "notify_xyz", containing
all owners to notify on completion.
A new DnsTransaction state is introduced called "VALIDATING" that is
entered after a response has been receieved which needs to be validated,
as long as we are still waiting for the DNSKEY/DS RRs from other
DnsTransactions.
This patch will request the DNSKEY/DS RRs bottom-up, and then validate
them top-down.
Caching of RRs is now only done after verification, so that the cache is
not poisoned with known invalid data.
The "DnsAnswer" object gained a substantial number of new calls, since
we need to add/remove RRs to it dynamically now.
2015-12-09 18:13:16 +01:00
|
|
|
r = set_ensure_allocated(&c->transactions, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
goto gc;
|
|
|
|
|
|
|
|
r = set_ensure_allocated(&t->notify_query_candidates, NULL);
|
2015-11-25 20:47:27 +01:00
|
|
|
if (r < 0)
|
|
|
|
goto gc;
|
|
|
|
|
resolved: chase DNSKEY/DS RRs when doing look-ups with DNSSEC enabled
This adds initial support for validating RRSIG/DNSKEY/DS chains when
doing lookups. Proof-of-non-existance, or proof-of-unsigned-zones is not
implemented yet.
With this change DnsTransaction objects will generate additional
DnsTransaction objects when looking for DNSKEY or DS RRs to validate an
RRSIG on a response. DnsTransaction objects are thus created for three
reasons now:
1) Because a user asked for something to be resolved, i.e. requested by
a DnsQuery/DnsQueryCandidate object.
2) As result of LLMNR RR probing, requested by a DnsZoneItem.
3) Because another DnsTransaction requires the requested RRs for
validation of its own response.
DnsTransactions are shared between all these users, and are GC
automatically as soon as all of these users don't need a specific
transaction anymore.
To unify the handling of these three reasons for existance for a
DnsTransaction, a new common naming is introduced: each DnsTransaction
now tracks its "owners" via a Set* object named "notify_xyz", containing
all owners to notify on completion.
A new DnsTransaction state is introduced called "VALIDATING" that is
entered after a response has been receieved which needs to be validated,
as long as we are still waiting for the DNSKEY/DS RRs from other
DnsTransactions.
This patch will request the DNSKEY/DS RRs bottom-up, and then validate
them top-down.
Caching of RRs is now only done after verification, so that the cache is
not poisoned with known invalid data.
The "DnsAnswer" object gained a substantial number of new calls, since
we need to add/remove RRs to it dynamically now.
2015-12-09 18:13:16 +01:00
|
|
|
r = set_put(t->notify_query_candidates, c);
|
2015-11-25 20:47:27 +01:00
|
|
|
if (r < 0)
|
|
|
|
goto gc;
|
|
|
|
|
|
|
|
r = set_put(c->transactions, t);
|
|
|
|
if (r < 0) {
|
resolved: chase DNSKEY/DS RRs when doing look-ups with DNSSEC enabled
This adds initial support for validating RRSIG/DNSKEY/DS chains when
doing lookups. Proof-of-non-existance, or proof-of-unsigned-zones is not
implemented yet.
With this change DnsTransaction objects will generate additional
DnsTransaction objects when looking for DNSKEY or DS RRs to validate an
RRSIG on a response. DnsTransaction objects are thus created for three
reasons now:
1) Because a user asked for something to be resolved, i.e. requested by
a DnsQuery/DnsQueryCandidate object.
2) As result of LLMNR RR probing, requested by a DnsZoneItem.
3) Because another DnsTransaction requires the requested RRs for
validation of its own response.
DnsTransactions are shared between all these users, and are GC
automatically as soon as all of these users don't need a specific
transaction anymore.
To unify the handling of these three reasons for existance for a
DnsTransaction, a new common naming is introduced: each DnsTransaction
now tracks its "owners" via a Set* object named "notify_xyz", containing
all owners to notify on completion.
A new DnsTransaction state is introduced called "VALIDATING" that is
entered after a response has been receieved which needs to be validated,
as long as we are still waiting for the DNSKEY/DS RRs from other
DnsTransactions.
This patch will request the DNSKEY/DS RRs bottom-up, and then validate
them top-down.
Caching of RRs is now only done after verification, so that the cache is
not poisoned with known invalid data.
The "DnsAnswer" object gained a substantial number of new calls, since
we need to add/remove RRs to it dynamically now.
2015-12-09 18:13:16 +01:00
|
|
|
(void) set_remove(t->notify_query_candidates, c);
|
2015-11-25 20:47:27 +01:00
|
|
|
goto gc;
|
|
|
|
}
|
|
|
|
|
resolved: chase DNSKEY/DS RRs when doing look-ups with DNSSEC enabled
This adds initial support for validating RRSIG/DNSKEY/DS chains when
doing lookups. Proof-of-non-existance, or proof-of-unsigned-zones is not
implemented yet.
With this change DnsTransaction objects will generate additional
DnsTransaction objects when looking for DNSKEY or DS RRs to validate an
RRSIG on a response. DnsTransaction objects are thus created for three
reasons now:
1) Because a user asked for something to be resolved, i.e. requested by
a DnsQuery/DnsQueryCandidate object.
2) As result of LLMNR RR probing, requested by a DnsZoneItem.
3) Because another DnsTransaction requires the requested RRs for
validation of its own response.
DnsTransactions are shared between all these users, and are GC
automatically as soon as all of these users don't need a specific
transaction anymore.
To unify the handling of these three reasons for existance for a
DnsTransaction, a new common naming is introduced: each DnsTransaction
now tracks its "owners" via a Set* object named "notify_xyz", containing
all owners to notify on completion.
A new DnsTransaction state is introduced called "VALIDATING" that is
entered after a response has been receieved which needs to be validated,
as long as we are still waiting for the DNSKEY/DS RRs from other
DnsTransactions.
This patch will request the DNSKEY/DS RRs bottom-up, and then validate
them top-down.
Caching of RRs is now only done after verification, so that the cache is
not poisoned with known invalid data.
The "DnsAnswer" object gained a substantial number of new calls, since
we need to add/remove RRs to it dynamically now.
2015-12-09 18:13:16 +01:00
|
|
|
return 1;
|
2015-11-25 20:47:27 +01:00
|
|
|
|
|
|
|
gc:
|
|
|
|
dns_transaction_gc(t);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dns_query_candidate_go(DnsQueryCandidate *c) {
|
|
|
|
DnsTransaction *t;
|
|
|
|
Iterator i;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(c);
|
|
|
|
|
|
|
|
/* Start the transactions that are not started yet */
|
|
|
|
SET_FOREACH(t, c->transactions, i) {
|
|
|
|
if (t->state != DNS_TRANSACTION_NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = dns_transaction_go(t);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static DnsTransactionState dns_query_candidate_state(DnsQueryCandidate *c) {
|
|
|
|
DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
|
|
|
|
DnsTransaction *t;
|
|
|
|
Iterator i;
|
|
|
|
|
|
|
|
assert(c);
|
|
|
|
|
|
|
|
if (c->error_code != 0)
|
|
|
|
return DNS_TRANSACTION_RESOURCES;
|
|
|
|
|
|
|
|
SET_FOREACH(t, c->transactions, i) {
|
|
|
|
|
|
|
|
switch (t->state) {
|
|
|
|
|
2015-12-14 21:21:59 +01:00
|
|
|
case DNS_TRANSACTION_NULL:
|
|
|
|
/* If there's a NULL transaction pending, then
|
|
|
|
* this means not all transactions where
|
|
|
|
* started yet, and we were called from within
|
|
|
|
* the stackframe that is supposed to start
|
|
|
|
* remaining transactions. In this case,
|
|
|
|
* simply claim the candidate is pending. */
|
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
case DNS_TRANSACTION_PENDING:
|
resolved: chase DNSKEY/DS RRs when doing look-ups with DNSSEC enabled
This adds initial support for validating RRSIG/DNSKEY/DS chains when
doing lookups. Proof-of-non-existance, or proof-of-unsigned-zones is not
implemented yet.
With this change DnsTransaction objects will generate additional
DnsTransaction objects when looking for DNSKEY or DS RRs to validate an
RRSIG on a response. DnsTransaction objects are thus created for three
reasons now:
1) Because a user asked for something to be resolved, i.e. requested by
a DnsQuery/DnsQueryCandidate object.
2) As result of LLMNR RR probing, requested by a DnsZoneItem.
3) Because another DnsTransaction requires the requested RRs for
validation of its own response.
DnsTransactions are shared between all these users, and are GC
automatically as soon as all of these users don't need a specific
transaction anymore.
To unify the handling of these three reasons for existance for a
DnsTransaction, a new common naming is introduced: each DnsTransaction
now tracks its "owners" via a Set* object named "notify_xyz", containing
all owners to notify on completion.
A new DnsTransaction state is introduced called "VALIDATING" that is
entered after a response has been receieved which needs to be validated,
as long as we are still waiting for the DNSKEY/DS RRs from other
DnsTransactions.
This patch will request the DNSKEY/DS RRs bottom-up, and then validate
them top-down.
Caching of RRs is now only done after verification, so that the cache is
not poisoned with known invalid data.
The "DnsAnswer" object gained a substantial number of new calls, since
we need to add/remove RRs to it dynamically now.
2015-12-09 18:13:16 +01:00
|
|
|
case DNS_TRANSACTION_VALIDATING:
|
|
|
|
/* If there's one transaction currently in
|
|
|
|
* VALIDATING state, then this means there's
|
|
|
|
* also one in PENDING state, hence we can
|
|
|
|
* return PENDING immediately. */
|
|
|
|
return DNS_TRANSACTION_PENDING;
|
2015-11-25 20:47:27 +01:00
|
|
|
|
|
|
|
case DNS_TRANSACTION_SUCCESS:
|
|
|
|
state = t->state;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if (state != DNS_TRANSACTION_SUCCESS)
|
|
|
|
state = t->state;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dns_query_candidate_setup_transactions(DnsQueryCandidate *c) {
|
|
|
|
DnsResourceKey *key;
|
|
|
|
int n = 0, r;
|
|
|
|
|
|
|
|
assert(c);
|
|
|
|
|
|
|
|
dns_query_candidate_stop(c);
|
|
|
|
|
|
|
|
/* Create one transaction per question key */
|
|
|
|
DNS_QUESTION_FOREACH(key, c->query->question) {
|
|
|
|
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *new_key = NULL;
|
|
|
|
|
|
|
|
if (c->search_domain) {
|
|
|
|
r = dns_resource_key_new_append_suffix(&new_key, key, c->search_domain->name);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = dns_query_candidate_add_transaction(c, new_key ?: key);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
dns_query_candidate_stop(c);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
resolved: chase DNSKEY/DS RRs when doing look-ups with DNSSEC enabled
This adds initial support for validating RRSIG/DNSKEY/DS chains when
doing lookups. Proof-of-non-existance, or proof-of-unsigned-zones is not
implemented yet.
With this change DnsTransaction objects will generate additional
DnsTransaction objects when looking for DNSKEY or DS RRs to validate an
RRSIG on a response. DnsTransaction objects are thus created for three
reasons now:
1) Because a user asked for something to be resolved, i.e. requested by
a DnsQuery/DnsQueryCandidate object.
2) As result of LLMNR RR probing, requested by a DnsZoneItem.
3) Because another DnsTransaction requires the requested RRs for
validation of its own response.
DnsTransactions are shared between all these users, and are GC
automatically as soon as all of these users don't need a specific
transaction anymore.
To unify the handling of these three reasons for existance for a
DnsTransaction, a new common naming is introduced: each DnsTransaction
now tracks its "owners" via a Set* object named "notify_xyz", containing
all owners to notify on completion.
A new DnsTransaction state is introduced called "VALIDATING" that is
entered after a response has been receieved which needs to be validated,
as long as we are still waiting for the DNSKEY/DS RRs from other
DnsTransactions.
This patch will request the DNSKEY/DS RRs bottom-up, and then validate
them top-down.
Caching of RRs is now only done after verification, so that the cache is
not poisoned with known invalid data.
The "DnsAnswer" object gained a substantial number of new calls, since
we need to add/remove RRs to it dynamically now.
2015-12-09 18:13:16 +01:00
|
|
|
void dns_query_candidate_notify(DnsQueryCandidate *c) {
|
2015-11-25 20:47:27 +01:00
|
|
|
DnsTransactionState state;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(c);
|
|
|
|
|
|
|
|
state = dns_query_candidate_state(c);
|
|
|
|
|
resolved: chase DNSKEY/DS RRs when doing look-ups with DNSSEC enabled
This adds initial support for validating RRSIG/DNSKEY/DS chains when
doing lookups. Proof-of-non-existance, or proof-of-unsigned-zones is not
implemented yet.
With this change DnsTransaction objects will generate additional
DnsTransaction objects when looking for DNSKEY or DS RRs to validate an
RRSIG on a response. DnsTransaction objects are thus created for three
reasons now:
1) Because a user asked for something to be resolved, i.e. requested by
a DnsQuery/DnsQueryCandidate object.
2) As result of LLMNR RR probing, requested by a DnsZoneItem.
3) Because another DnsTransaction requires the requested RRs for
validation of its own response.
DnsTransactions are shared between all these users, and are GC
automatically as soon as all of these users don't need a specific
transaction anymore.
To unify the handling of these three reasons for existance for a
DnsTransaction, a new common naming is introduced: each DnsTransaction
now tracks its "owners" via a Set* object named "notify_xyz", containing
all owners to notify on completion.
A new DnsTransaction state is introduced called "VALIDATING" that is
entered after a response has been receieved which needs to be validated,
as long as we are still waiting for the DNSKEY/DS RRs from other
DnsTransactions.
This patch will request the DNSKEY/DS RRs bottom-up, and then validate
them top-down.
Caching of RRs is now only done after verification, so that the cache is
not poisoned with known invalid data.
The "DnsAnswer" object gained a substantial number of new calls, since
we need to add/remove RRs to it dynamically now.
2015-12-09 18:13:16 +01:00
|
|
|
if (DNS_TRANSACTION_IS_LIVE(state))
|
2015-11-25 20:47:27 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (state != DNS_TRANSACTION_SUCCESS && c->search_domain) {
|
|
|
|
|
|
|
|
r = dns_query_candidate_next_search_domain(c);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
if (r > 0) {
|
|
|
|
/* OK, there's another search domain to try, let's do so. */
|
|
|
|
|
|
|
|
r = dns_query_candidate_setup_transactions(c);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
if (r > 0) {
|
|
|
|
/* New transactions where queued. Start them and wait */
|
|
|
|
|
|
|
|
r = dns_query_candidate_go(c);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_query_ready(c->query);
|
|
|
|
return;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
log_warning_errno(r, "Failed to follow search domains: %m");
|
|
|
|
c->error_code = r;
|
|
|
|
dns_query_ready(c->query);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dns_query_stop(DnsQuery *q) {
|
|
|
|
DnsQueryCandidate *c;
|
|
|
|
|
|
|
|
assert(q);
|
|
|
|
|
|
|
|
q->timeout_event_source = sd_event_source_unref(q->timeout_event_source);
|
|
|
|
|
|
|
|
LIST_FOREACH(candidates_by_query, c, q->candidates)
|
|
|
|
dns_query_candidate_stop(c);
|
|
|
|
}
|
|
|
|
|
2014-07-16 00:26:02 +02:00
|
|
|
DnsQuery *dns_query_free(DnsQuery *q) {
|
|
|
|
if (!q)
|
|
|
|
return NULL;
|
|
|
|
|
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
|
|
|
while (q->auxiliary_queries)
|
|
|
|
dns_query_free(q->auxiliary_queries);
|
|
|
|
|
|
|
|
if (q->auxiliary_for) {
|
|
|
|
assert(q->auxiliary_for->n_auxiliary_queries > 0);
|
|
|
|
q->auxiliary_for->n_auxiliary_queries--;
|
|
|
|
LIST_REMOVE(auxiliary_queries, q->auxiliary_for->auxiliary_queries, q);
|
|
|
|
}
|
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
while (q->candidates)
|
|
|
|
dns_query_candidate_free(q->candidates);
|
2014-07-17 19:38:37 +02:00
|
|
|
|
2014-07-22 21:48:41 +02:00
|
|
|
dns_question_unref(q->question);
|
|
|
|
dns_answer_unref(q->answer);
|
2015-11-25 20:47:27 +01:00
|
|
|
dns_search_domain_unref(q->answer_search_domain);
|
2014-07-17 19:38:37 +02:00
|
|
|
|
2014-07-31 17:46:40 +02:00
|
|
|
sd_bus_message_unref(q->request);
|
2014-08-06 16:32:55 +02:00
|
|
|
sd_bus_track_unref(q->bus_track);
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2014-07-17 01:58:14 +02:00
|
|
|
if (q->manager) {
|
2014-07-16 00:26:02 +02:00
|
|
|
LIST_REMOVE(queries, q->manager->dns_queries, q);
|
2014-07-17 01:58:14 +02:00
|
|
|
q->manager->n_dns_queries--;
|
|
|
|
}
|
2014-07-16 00:26:02 +02:00
|
|
|
|
|
|
|
free(q);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-08-14 01:00:15 +02:00
|
|
|
int dns_query_new(Manager *m, DnsQuery **ret, DnsQuestion *question, int ifindex, uint64_t flags) {
|
2014-07-16 00:26:02 +02:00
|
|
|
_cleanup_(dns_query_freep) DnsQuery *q = NULL;
|
2014-07-22 21:48:41 +02:00
|
|
|
unsigned i;
|
|
|
|
int r;
|
2014-07-16 00:26:02 +02:00
|
|
|
|
|
|
|
assert(m);
|
2014-07-22 21:48:41 +02:00
|
|
|
assert(question);
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2015-11-24 01:25:24 +01:00
|
|
|
r = dns_question_is_valid_for_query(question);
|
2014-07-22 21:48:41 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2014-07-17 01:58:14 +02:00
|
|
|
if (m->n_dns_queries >= QUERIES_MAX)
|
|
|
|
return -EBUSY;
|
|
|
|
|
2014-07-16 00:26:02 +02:00
|
|
|
q = new0(DnsQuery, 1);
|
|
|
|
if (!q)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2014-07-22 21:48:41 +02:00
|
|
|
q->question = dns_question_ref(question);
|
2014-08-14 01:00:15 +02:00
|
|
|
q->ifindex = ifindex;
|
|
|
|
q->flags = flags;
|
2015-11-25 20:47:27 +01:00
|
|
|
q->answer_family = AF_UNSPEC;
|
|
|
|
q->answer_protocol = _DNS_PROTOCOL_INVALID;
|
2014-07-17 19:38:37 +02:00
|
|
|
|
2014-07-22 21:48:41 +02:00
|
|
|
for (i = 0; i < question->n_keys; i++) {
|
2014-07-30 20:39:52 +02:00
|
|
|
_cleanup_free_ char *p;
|
|
|
|
|
|
|
|
r = dns_resource_key_to_string(question->keys[i], &p);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
log_debug("Looking up RR for %s", p);
|
2014-07-16 00:26:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
LIST_PREPEND(queries, m->dns_queries, q);
|
2014-07-17 01:58:14 +02:00
|
|
|
m->n_dns_queries++;
|
2014-07-16 00:26:02 +02:00
|
|
|
q->manager = m;
|
|
|
|
|
2014-07-16 22:09:00 +02:00
|
|
|
if (ret)
|
|
|
|
*ret = q;
|
|
|
|
q = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
|
|
|
int dns_query_make_auxiliary(DnsQuery *q, DnsQuery *auxiliary_for) {
|
|
|
|
assert(q);
|
|
|
|
assert(auxiliary_for);
|
|
|
|
|
|
|
|
/* Ensure that that the query is not auxiliary yet, and
|
|
|
|
* nothing else is auxiliary to it either */
|
|
|
|
assert(!q->auxiliary_for);
|
|
|
|
assert(!q->auxiliary_queries);
|
|
|
|
|
|
|
|
/* Ensure that the unit we shall be made auxiliary for isn't
|
|
|
|
* auxiliary itself */
|
|
|
|
assert(!auxiliary_for->auxiliary_for);
|
|
|
|
|
|
|
|
if (auxiliary_for->n_auxiliary_queries >= AUXILIARY_QUERIES_MAX)
|
|
|
|
return -EAGAIN;
|
|
|
|
|
|
|
|
LIST_PREPEND(auxiliary_queries, auxiliary_for->auxiliary_queries, q);
|
|
|
|
q->auxiliary_for = auxiliary_for;
|
|
|
|
|
|
|
|
auxiliary_for->n_auxiliary_queries++;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-07-31 17:46:40 +02:00
|
|
|
static void dns_query_complete(DnsQuery *q, DnsTransactionState state) {
|
2014-07-16 22:09:00 +02:00
|
|
|
assert(q);
|
resolved: chase DNSKEY/DS RRs when doing look-ups with DNSSEC enabled
This adds initial support for validating RRSIG/DNSKEY/DS chains when
doing lookups. Proof-of-non-existance, or proof-of-unsigned-zones is not
implemented yet.
With this change DnsTransaction objects will generate additional
DnsTransaction objects when looking for DNSKEY or DS RRs to validate an
RRSIG on a response. DnsTransaction objects are thus created for three
reasons now:
1) Because a user asked for something to be resolved, i.e. requested by
a DnsQuery/DnsQueryCandidate object.
2) As result of LLMNR RR probing, requested by a DnsZoneItem.
3) Because another DnsTransaction requires the requested RRs for
validation of its own response.
DnsTransactions are shared between all these users, and are GC
automatically as soon as all of these users don't need a specific
transaction anymore.
To unify the handling of these three reasons for existance for a
DnsTransaction, a new common naming is introduced: each DnsTransaction
now tracks its "owners" via a Set* object named "notify_xyz", containing
all owners to notify on completion.
A new DnsTransaction state is introduced called "VALIDATING" that is
entered after a response has been receieved which needs to be validated,
as long as we are still waiting for the DNSKEY/DS RRs from other
DnsTransactions.
This patch will request the DNSKEY/DS RRs bottom-up, and then validate
them top-down.
Caching of RRs is now only done after verification, so that the cache is
not poisoned with known invalid data.
The "DnsAnswer" object gained a substantial number of new calls, since
we need to add/remove RRs to it dynamically now.
2015-12-09 18:13:16 +01:00
|
|
|
assert(!DNS_TRANSACTION_IS_LIVE(state));
|
|
|
|
assert(DNS_TRANSACTION_IS_LIVE(q->state));
|
2014-07-16 22:09:00 +02:00
|
|
|
|
2014-07-17 19:38:37 +02:00
|
|
|
/* Note that this call might invalidate the query. Callers
|
|
|
|
* should hence not attempt to access the query or transaction
|
|
|
|
* after calling this function. */
|
2014-07-16 22:09:00 +02:00
|
|
|
|
|
|
|
q->state = state;
|
|
|
|
|
2014-07-17 19:38:37 +02:00
|
|
|
dns_query_stop(q);
|
|
|
|
if (q->complete)
|
|
|
|
q->complete(q);
|
2014-07-16 22:09:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
|
|
|
|
DnsQuery *q = userdata;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
assert(q);
|
|
|
|
|
2014-07-31 17:46:40 +02:00
|
|
|
dns_query_complete(q, DNS_TRANSACTION_TIMEOUT);
|
2014-07-16 22:09:00 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
static int dns_query_add_candidate(DnsQuery *q, DnsScope *s) {
|
|
|
|
DnsQueryCandidate *c;
|
2014-07-22 21:48:41 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(q);
|
2014-07-31 17:46:40 +02:00
|
|
|
assert(s);
|
2014-07-22 21:48:41 +02:00
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
r = dns_query_candidate_new(&c, q, s);
|
2014-07-22 21:48:41 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
/* If this a single-label domain on DNS, we might append a suitable search domain first. */
|
2015-12-03 18:20:56 +01:00
|
|
|
if ((q->flags & SD_RESOLVED_NO_SEARCH) == 0) {
|
|
|
|
r = dns_scope_name_needs_search_domain(s, dns_question_first_name(q->question));
|
|
|
|
if (r < 0)
|
2015-11-25 20:47:27 +01:00
|
|
|
goto fail;
|
2015-12-03 18:20:56 +01:00
|
|
|
if (r > 0) {
|
|
|
|
/* OK, we need a search domain now. Let's find one for this scope */
|
|
|
|
|
|
|
|
r = dns_query_candidate_next_search_domain(c);
|
|
|
|
if (r <= 0) /* if there's no search domain, then we won't add any transaction. */
|
|
|
|
goto fail;
|
|
|
|
}
|
2014-07-22 21:48:41 +02:00
|
|
|
}
|
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
r = dns_query_candidate_setup_transactions(c);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
|
|
|
|
2014-07-22 21:48:41 +02:00
|
|
|
return 0;
|
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
fail:
|
|
|
|
dns_query_candidate_free(c);
|
2014-07-22 21:48:41 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2015-08-14 13:17:05 +02:00
|
|
|
static int SYNTHESIZE_IFINDEX(int ifindex) {
|
|
|
|
|
2015-08-17 23:54:08 +02:00
|
|
|
/* When the caller asked for resolving on a specific
|
|
|
|
* interface, we synthesize the answer for that
|
|
|
|
* interface. However, if nothing specific was claimed and we
|
|
|
|
* only return localhost RRs, we synthesize the answer for
|
2015-08-14 13:17:05 +02:00
|
|
|
* localhost. */
|
|
|
|
|
|
|
|
if (ifindex > 0)
|
|
|
|
return ifindex;
|
|
|
|
|
|
|
|
return LOOPBACK_IFINDEX;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int SYNTHESIZE_FAMILY(uint64_t flags) {
|
|
|
|
|
|
|
|
/* Picks an address family depending on set flags. This is
|
|
|
|
* purely for synthesized answers, where the family we return
|
|
|
|
* for the reply should match what was requested in the
|
|
|
|
* question, even though we are synthesizing the answer
|
|
|
|
* here. */
|
|
|
|
|
|
|
|
if (!(flags & SD_RESOLVED_DNS)) {
|
|
|
|
if (flags & SD_RESOLVED_LLMNR_IPV4)
|
|
|
|
return AF_INET;
|
|
|
|
if (flags & SD_RESOLVED_LLMNR_IPV6)
|
|
|
|
return AF_INET6;
|
|
|
|
}
|
|
|
|
|
|
|
|
return AF_UNSPEC;
|
|
|
|
}
|
|
|
|
|
|
|
|
static DnsProtocol SYNTHESIZE_PROTOCOL(uint64_t flags) {
|
|
|
|
|
|
|
|
/* Similar as SYNTHESIZE_FAMILY() but does this for the
|
|
|
|
* protocol. If resolving via DNS was requested, we claim it
|
|
|
|
* was DNS. Similar, if nothing specific was
|
|
|
|
* requested. However, if only resolving via LLMNR was
|
|
|
|
* requested we return that. */
|
|
|
|
|
|
|
|
if (flags & SD_RESOLVED_DNS)
|
|
|
|
return DNS_PROTOCOL_DNS;
|
|
|
|
if (flags & SD_RESOLVED_LLMNR)
|
|
|
|
return DNS_PROTOCOL_LLMNR;
|
|
|
|
|
|
|
|
return DNS_PROTOCOL_DNS;
|
|
|
|
}
|
|
|
|
|
2015-08-17 23:54:08 +02:00
|
|
|
static int dns_type_to_af(uint16_t t) {
|
|
|
|
switch (t) {
|
|
|
|
|
|
|
|
case DNS_TYPE_A:
|
|
|
|
return AF_INET;
|
|
|
|
|
|
|
|
case DNS_TYPE_AAAA:
|
|
|
|
return AF_INET6;
|
|
|
|
|
|
|
|
case DNS_TYPE_ANY:
|
|
|
|
return AF_UNSPEC;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int synthesize_localhost_rr(DnsQuery *q, DnsResourceKey *key, DnsAnswer **answer) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(q);
|
|
|
|
assert(key);
|
|
|
|
assert(answer);
|
|
|
|
|
|
|
|
r = dns_answer_reserve(answer, 2);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_ANY)) {
|
|
|
|
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
|
|
|
|
|
|
|
|
rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, DNS_RESOURCE_KEY_NAME(key));
|
|
|
|
if (!rr)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
rr->a.in_addr.s_addr = htobe32(INADDR_LOOPBACK);
|
|
|
|
|
2015-12-18 14:37:06 +01:00
|
|
|
r = dns_answer_add(*answer, rr, SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
|
2015-08-17 23:54:08 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IN_SET(key->type, DNS_TYPE_AAAA, DNS_TYPE_ANY)) {
|
|
|
|
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
|
|
|
|
|
|
|
|
rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, DNS_RESOURCE_KEY_NAME(key));
|
|
|
|
if (!rr)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
rr->aaaa.in6_addr = in6addr_loopback;
|
|
|
|
|
2015-12-18 14:37:06 +01:00
|
|
|
r = dns_answer_add(*answer, rr, SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
|
2015-08-17 23:54:08 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-12-18 14:37:06 +01:00
|
|
|
static int answer_add_ptr(DnsAnswer **answer, const char *from, const char *to, int ifindex, DnsAnswerFlags flags) {
|
2015-08-17 23:54:08 +02:00
|
|
|
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
|
|
|
|
|
|
|
|
rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR, from);
|
|
|
|
if (!rr)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
rr->ptr.name = strdup(to);
|
|
|
|
if (!rr->ptr.name)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2015-12-18 14:37:06 +01:00
|
|
|
return dns_answer_add(*answer, rr, ifindex, flags);
|
2015-08-17 23:54:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int synthesize_localhost_ptr(DnsQuery *q, DnsResourceKey *key, DnsAnswer **answer) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(q);
|
|
|
|
assert(key);
|
|
|
|
assert(answer);
|
|
|
|
|
|
|
|
if (IN_SET(key->type, DNS_TYPE_PTR, DNS_TYPE_ANY)) {
|
2015-12-18 14:37:06 +01:00
|
|
|
r = dns_answer_reserve(answer, 1);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = answer_add_ptr(answer, DNS_RESOURCE_KEY_NAME(key), "localhost", SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
|
2015-08-17 23:54:08 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int answer_add_addresses_rr(
|
|
|
|
DnsAnswer **answer,
|
|
|
|
const char *name,
|
|
|
|
struct local_address *addresses,
|
|
|
|
unsigned n_addresses) {
|
|
|
|
|
|
|
|
unsigned j;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(answer);
|
|
|
|
assert(name);
|
|
|
|
|
|
|
|
r = dns_answer_reserve(answer, n_addresses);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
for (j = 0; j < n_addresses; j++) {
|
|
|
|
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
|
|
|
|
|
|
|
|
r = dns_resource_record_new_address(&rr, addresses[j].family, &addresses[j].address, name);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-12-18 14:37:06 +01:00
|
|
|
r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED);
|
2015-08-17 23:54:08 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int answer_add_addresses_ptr(
|
|
|
|
DnsAnswer **answer,
|
|
|
|
const char *name,
|
|
|
|
struct local_address *addresses,
|
|
|
|
unsigned n_addresses,
|
|
|
|
int af, const union in_addr_union *match) {
|
|
|
|
|
|
|
|
unsigned j;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(answer);
|
|
|
|
assert(name);
|
|
|
|
|
|
|
|
for (j = 0; j < n_addresses; j++) {
|
|
|
|
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
|
|
|
|
|
|
|
|
if (af != AF_UNSPEC) {
|
|
|
|
|
|
|
|
if (addresses[j].family != af)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (match && !in_addr_equal(af, match, &addresses[j].address))
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = dns_answer_reserve(answer, 1);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = dns_resource_record_new_reverse(&rr, addresses[j].family, &addresses[j].address, name);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-12-18 14:37:06 +01:00
|
|
|
r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED);
|
2015-08-17 23:54:08 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int synthesize_system_hostname_rr(DnsQuery *q, DnsResourceKey *key, DnsAnswer **answer) {
|
|
|
|
_cleanup_free_ struct local_address *addresses = NULL;
|
|
|
|
int n = 0, af;
|
|
|
|
|
|
|
|
assert(q);
|
|
|
|
assert(key);
|
|
|
|
assert(answer);
|
|
|
|
|
|
|
|
af = dns_type_to_af(key->type);
|
|
|
|
if (af >= 0) {
|
|
|
|
n = local_addresses(q->manager->rtnl, q->ifindex, af, &addresses);
|
|
|
|
if (n < 0)
|
|
|
|
return n;
|
|
|
|
|
|
|
|
if (n == 0) {
|
|
|
|
struct local_address buffer[2];
|
|
|
|
|
|
|
|
/* If we have no local addresses then use ::1
|
|
|
|
* and 127.0.0.2 as local ones. */
|
|
|
|
|
|
|
|
if (af == AF_INET || af == AF_UNSPEC)
|
|
|
|
buffer[n++] = (struct local_address) {
|
|
|
|
.family = AF_INET,
|
|
|
|
.ifindex = SYNTHESIZE_IFINDEX(q->ifindex),
|
|
|
|
.address.in.s_addr = htobe32(0x7F000002),
|
|
|
|
};
|
|
|
|
|
|
|
|
if (af == AF_INET6 || af == AF_UNSPEC)
|
|
|
|
buffer[n++] = (struct local_address) {
|
|
|
|
.family = AF_INET6,
|
|
|
|
.ifindex = SYNTHESIZE_IFINDEX(q->ifindex),
|
|
|
|
.address.in6 = in6addr_loopback,
|
|
|
|
};
|
|
|
|
|
|
|
|
return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), buffer, n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int synthesize_system_hostname_ptr(DnsQuery *q, int af, const union in_addr_union *address, DnsAnswer **answer) {
|
|
|
|
_cleanup_free_ struct local_address *addresses = NULL;
|
|
|
|
int n, r;
|
|
|
|
|
|
|
|
assert(q);
|
|
|
|
assert(address);
|
|
|
|
assert(answer);
|
|
|
|
|
|
|
|
if (af == AF_INET && address->in.s_addr == htobe32(0x7F000002)) {
|
|
|
|
|
|
|
|
/* Always map the IPv4 address 127.0.0.2 to the local
|
|
|
|
* hostname, in addition to "localhost": */
|
|
|
|
|
|
|
|
r = dns_answer_reserve(answer, 3);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-12-18 14:37:06 +01:00
|
|
|
r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", q->manager->llmnr_hostname, SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
|
2015-08-17 23:54:08 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-12-18 14:37:06 +01:00
|
|
|
r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", q->manager->mdns_hostname, SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
|
2015-08-17 23:54:08 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-12-18 14:37:06 +01:00
|
|
|
r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", "localhost", SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
|
2015-08-17 23:54:08 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = local_addresses(q->manager->rtnl, q->ifindex, af, &addresses);
|
|
|
|
if (n < 0)
|
|
|
|
return n;
|
|
|
|
|
|
|
|
r = answer_add_addresses_ptr(answer, q->manager->llmnr_hostname, addresses, n, af, address);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return answer_add_addresses_ptr(answer, q->manager->mdns_hostname, addresses, n, af, address);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int synthesize_gateway_rr(DnsQuery *q, DnsResourceKey *key, DnsAnswer **answer) {
|
|
|
|
_cleanup_free_ struct local_address *addresses = NULL;
|
|
|
|
int n = 0, af;
|
|
|
|
|
|
|
|
assert(q);
|
|
|
|
assert(key);
|
|
|
|
assert(answer);
|
|
|
|
|
|
|
|
af = dns_type_to_af(key->type);
|
|
|
|
if (af >= 0) {
|
|
|
|
n = local_gateways(q->manager->rtnl, q->ifindex, af, &addresses);
|
|
|
|
if (n < 0)
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int synthesize_gateway_ptr(DnsQuery *q, int af, const union in_addr_union *address, DnsAnswer **answer) {
|
|
|
|
_cleanup_free_ struct local_address *addresses = NULL;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
assert(q);
|
|
|
|
assert(address);
|
|
|
|
assert(answer);
|
|
|
|
|
|
|
|
n = local_gateways(q->manager->rtnl, q->ifindex, af, &addresses);
|
|
|
|
if (n < 0)
|
|
|
|
return n;
|
|
|
|
|
|
|
|
return answer_add_addresses_ptr(answer, "gateway", addresses, n, af, address);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
|
2015-08-14 13:17:05 +02:00
|
|
|
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
|
|
|
|
unsigned i;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(q);
|
|
|
|
assert(state);
|
|
|
|
|
|
|
|
/* Tries to synthesize localhost RR replies where appropriate */
|
|
|
|
|
|
|
|
if (!IN_SET(*state,
|
2015-12-18 19:49:25 +01:00
|
|
|
DNS_TRANSACTION_RCODE_FAILURE,
|
2015-08-14 13:17:05 +02:00
|
|
|
DNS_TRANSACTION_NO_SERVERS,
|
|
|
|
DNS_TRANSACTION_TIMEOUT,
|
|
|
|
DNS_TRANSACTION_ATTEMPTS_MAX_REACHED))
|
2015-08-17 23:54:08 +02:00
|
|
|
return 0;
|
2015-08-14 13:17:05 +02:00
|
|
|
|
|
|
|
for (i = 0; i < q->question->n_keys; i++) {
|
2015-08-17 23:54:08 +02:00
|
|
|
union in_addr_union address;
|
2015-08-14 13:17:05 +02:00
|
|
|
const char *name;
|
2015-08-17 23:54:08 +02:00
|
|
|
int af;
|
2015-08-14 13:17:05 +02:00
|
|
|
|
|
|
|
if (q->question->keys[i]->class != DNS_CLASS_IN &&
|
|
|
|
q->question->keys[i]->class != DNS_CLASS_ANY)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
name = DNS_RESOURCE_KEY_NAME(q->question->keys[i]);
|
|
|
|
|
|
|
|
if (is_localhost(name)) {
|
|
|
|
|
2015-08-17 23:54:08 +02:00
|
|
|
r = synthesize_localhost_rr(q, q->question->keys[i], &answer);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to synthesize localhost RRs: %m");
|
2015-08-14 13:17:05 +02:00
|
|
|
|
2015-08-17 23:54:08 +02:00
|
|
|
} else if (manager_is_own_hostname(q->manager, name)) {
|
2015-08-14 13:17:05 +02:00
|
|
|
|
2015-08-17 23:54:08 +02:00
|
|
|
r = synthesize_system_hostname_rr(q, q->question->keys[i], &answer);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to synthesize system hostname RRs: %m");
|
2015-08-14 13:17:05 +02:00
|
|
|
|
2015-08-17 23:54:08 +02:00
|
|
|
} else if (is_gateway_hostname(name)) {
|
2015-08-14 13:17:05 +02:00
|
|
|
|
2015-08-17 23:54:08 +02:00
|
|
|
r = synthesize_gateway_rr(q, q->question->keys[i], &answer);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to synthesize gateway RRs: %m");
|
2015-08-14 13:17:05 +02:00
|
|
|
|
2015-08-17 23:54:08 +02:00
|
|
|
} else if ((dns_name_endswith(name, "127.in-addr.arpa") > 0 && dns_name_equal(name, "2.0.0.127.in-addr.arpa") == 0) ||
|
|
|
|
dns_name_equal(name, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0) {
|
2015-08-14 13:17:05 +02:00
|
|
|
|
2015-08-17 23:54:08 +02:00
|
|
|
r = synthesize_localhost_ptr(q, q->question->keys[i], &answer);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to synthesize localhost PTR RRs: %m");
|
2015-08-14 13:17:05 +02:00
|
|
|
|
2015-08-17 23:54:08 +02:00
|
|
|
} else if (dns_name_address(name, &af, &address) > 0) {
|
2015-08-14 13:17:05 +02:00
|
|
|
|
2015-08-17 23:54:08 +02:00
|
|
|
r = synthesize_system_hostname_ptr(q, af, &address, &answer);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to synthesize system hostname PTR RR: %m");
|
2015-08-14 13:17:05 +02:00
|
|
|
|
2015-08-17 23:54:08 +02:00
|
|
|
r = synthesize_gateway_ptr(q, af, &address, &answer);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to synthesize gateway hostname PTR RR: %m");
|
2015-08-14 13:17:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!answer)
|
2015-08-17 23:54:08 +02:00
|
|
|
return 0;
|
2015-08-14 13:17:05 +02:00
|
|
|
|
|
|
|
dns_answer_unref(q->answer);
|
|
|
|
q->answer = answer;
|
|
|
|
answer = NULL;
|
|
|
|
|
|
|
|
q->answer_rcode = DNS_RCODE_SUCCESS;
|
2015-11-25 20:47:27 +01:00
|
|
|
q->answer_protocol = SYNTHESIZE_PROTOCOL(q->flags);
|
|
|
|
q->answer_family = SYNTHESIZE_FAMILY(q->flags);
|
2015-08-14 13:17:05 +02:00
|
|
|
|
|
|
|
*state = DNS_TRANSACTION_SUCCESS;
|
2015-08-17 23:54:08 +02:00
|
|
|
|
|
|
|
return 1;
|
2015-08-14 13:17:05 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 19:38:37 +02:00
|
|
|
int dns_query_go(DnsQuery *q) {
|
2014-07-16 22:09:00 +02:00
|
|
|
DnsScopeMatch found = DNS_SCOPE_NO;
|
|
|
|
DnsScope *s, *first = NULL;
|
2015-11-25 20:47:27 +01:00
|
|
|
DnsQueryCandidate *c;
|
2014-07-22 21:48:41 +02:00
|
|
|
const char *name;
|
2014-07-16 22:09:00 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(q);
|
|
|
|
|
2014-07-31 17:46:40 +02:00
|
|
|
if (q->state != DNS_TRANSACTION_NULL)
|
2014-07-16 22:09:00 +02:00
|
|
|
return 0;
|
|
|
|
|
2014-07-22 21:48:41 +02:00
|
|
|
assert(q->question);
|
|
|
|
assert(q->question->n_keys > 0);
|
|
|
|
|
2015-11-24 01:25:24 +01:00
|
|
|
name = dns_question_first_name(q->question);
|
2014-07-16 22:09:00 +02:00
|
|
|
|
|
|
|
LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
|
2014-07-16 00:26:02 +02:00
|
|
|
DnsScopeMatch match;
|
|
|
|
|
2014-08-14 01:00:15 +02:00
|
|
|
match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
|
2014-07-16 00:26:02 +02:00
|
|
|
if (match < 0)
|
|
|
|
return match;
|
|
|
|
|
|
|
|
if (match == DNS_SCOPE_NO)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
found = match;
|
|
|
|
|
|
|
|
if (match == DNS_SCOPE_YES) {
|
|
|
|
first = s;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
assert(match == DNS_SCOPE_MAYBE);
|
|
|
|
|
|
|
|
if (!first)
|
|
|
|
first = s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-14 13:17:05 +02:00
|
|
|
if (found == DNS_SCOPE_NO) {
|
|
|
|
DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
|
|
|
|
|
|
|
|
dns_query_synthesize_reply(q, &state);
|
2015-08-24 23:44:33 +02:00
|
|
|
dns_query_complete(q, state);
|
|
|
|
return 1;
|
2015-08-14 13:17:05 +02:00
|
|
|
}
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
r = dns_query_add_candidate(q, first);
|
2014-07-16 00:26:02 +02:00
|
|
|
if (r < 0)
|
2014-07-31 17:46:40 +02:00
|
|
|
goto fail;
|
2014-07-16 00:26:02 +02:00
|
|
|
|
|
|
|
LIST_FOREACH(scopes, s, first->scopes_next) {
|
|
|
|
DnsScopeMatch match;
|
|
|
|
|
2014-08-14 01:00:15 +02:00
|
|
|
match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
|
2014-07-16 00:26:02 +02:00
|
|
|
if (match < 0)
|
2014-07-31 17:46:40 +02:00
|
|
|
goto fail;
|
2014-07-16 00:26:02 +02:00
|
|
|
|
|
|
|
if (match != found)
|
|
|
|
continue;
|
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
r = dns_query_add_candidate(q, s);
|
2014-07-16 00:26:02 +02:00
|
|
|
if (r < 0)
|
2014-07-31 17:46:40 +02:00
|
|
|
goto fail;
|
2014-07-16 00:26:02 +02:00
|
|
|
}
|
|
|
|
|
2014-07-22 21:48:41 +02:00
|
|
|
q->answer = dns_answer_unref(q->answer);
|
|
|
|
q->answer_rcode = 0;
|
2014-08-14 01:00:15 +02:00
|
|
|
q->answer_family = AF_UNSPEC;
|
|
|
|
q->answer_protocol = _DNS_PROTOCOL_INVALID;
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2014-08-01 00:55:51 +02:00
|
|
|
r = sd_event_add_time(
|
|
|
|
q->manager->event,
|
|
|
|
&q->timeout_event_source,
|
|
|
|
clock_boottime_or_monotonic(),
|
|
|
|
now(clock_boottime_or_monotonic()) + QUERY_TIMEOUT_USEC, 0,
|
|
|
|
on_query_timeout, q);
|
2014-07-16 00:26:02 +02:00
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
|
|
|
|
2014-07-31 17:46:40 +02:00
|
|
|
q->state = DNS_TRANSACTION_PENDING;
|
2014-07-22 21:48:41 +02:00
|
|
|
q->block_ready++;
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
/* Start the transactions */
|
|
|
|
LIST_FOREACH(candidates_by_query, c, q->candidates) {
|
|
|
|
r = dns_query_candidate_go(c);
|
|
|
|
if (r < 0) {
|
|
|
|
q->block_ready--;
|
2014-07-31 17:46:40 +02:00
|
|
|
goto fail;
|
2015-11-25 20:47:27 +01:00
|
|
|
}
|
2014-07-16 00:26:02 +02:00
|
|
|
}
|
|
|
|
|
2014-07-22 21:48:41 +02:00
|
|
|
q->block_ready--;
|
|
|
|
dns_query_ready(q);
|
2014-07-17 19:38:37 +02:00
|
|
|
|
2014-07-16 22:09:00 +02:00
|
|
|
return 1;
|
2014-07-16 00:26:02 +02:00
|
|
|
|
|
|
|
fail:
|
2014-07-16 22:09:00 +02:00
|
|
|
dns_query_stop(q);
|
2014-07-16 00:26:02 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) {
|
2014-07-31 17:46:40 +02:00
|
|
|
DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
|
resolved: chase DNSKEY/DS RRs when doing look-ups with DNSSEC enabled
This adds initial support for validating RRSIG/DNSKEY/DS chains when
doing lookups. Proof-of-non-existance, or proof-of-unsigned-zones is not
implemented yet.
With this change DnsTransaction objects will generate additional
DnsTransaction objects when looking for DNSKEY or DS RRs to validate an
RRSIG on a response. DnsTransaction objects are thus created for three
reasons now:
1) Because a user asked for something to be resolved, i.e. requested by
a DnsQuery/DnsQueryCandidate object.
2) As result of LLMNR RR probing, requested by a DnsZoneItem.
3) Because another DnsTransaction requires the requested RRs for
validation of its own response.
DnsTransactions are shared between all these users, and are GC
automatically as soon as all of these users don't need a specific
transaction anymore.
To unify the handling of these three reasons for existance for a
DnsTransaction, a new common naming is introduced: each DnsTransaction
now tracks its "owners" via a Set* object named "notify_xyz", containing
all owners to notify on completion.
A new DnsTransaction state is introduced called "VALIDATING" that is
entered after a response has been receieved which needs to be validated,
as long as we are still waiting for the DNSKEY/DS RRs from other
DnsTransactions.
This patch will request the DNSKEY/DS RRs bottom-up, and then validate
them top-down.
Caching of RRs is now only done after verification, so that the cache is
not poisoned with known invalid data.
The "DnsAnswer" object gained a substantial number of new calls, since
we need to add/remove RRs to it dynamically now.
2015-12-09 18:13:16 +01:00
|
|
|
bool has_authenticated = false, has_non_authenticated = false;
|
2015-12-18 20:09:30 +01:00
|
|
|
DnssecResult dnssec_result_authenticated = _DNSSEC_RESULT_INVALID, dnssec_result_non_authenticated = _DNSSEC_RESULT_INVALID;
|
2015-11-25 20:47:27 +01:00
|
|
|
DnsTransaction *t;
|
2014-07-22 21:48:41 +02:00
|
|
|
Iterator i;
|
resolved: chase DNSKEY/DS RRs when doing look-ups with DNSSEC enabled
This adds initial support for validating RRSIG/DNSKEY/DS chains when
doing lookups. Proof-of-non-existance, or proof-of-unsigned-zones is not
implemented yet.
With this change DnsTransaction objects will generate additional
DnsTransaction objects when looking for DNSKEY or DS RRs to validate an
RRSIG on a response. DnsTransaction objects are thus created for three
reasons now:
1) Because a user asked for something to be resolved, i.e. requested by
a DnsQuery/DnsQueryCandidate object.
2) As result of LLMNR RR probing, requested by a DnsZoneItem.
3) Because another DnsTransaction requires the requested RRs for
validation of its own response.
DnsTransactions are shared between all these users, and are GC
automatically as soon as all of these users don't need a specific
transaction anymore.
To unify the handling of these three reasons for existance for a
DnsTransaction, a new common naming is introduced: each DnsTransaction
now tracks its "owners" via a Set* object named "notify_xyz", containing
all owners to notify on completion.
A new DnsTransaction state is introduced called "VALIDATING" that is
entered after a response has been receieved which needs to be validated,
as long as we are still waiting for the DNSKEY/DS RRs from other
DnsTransactions.
This patch will request the DNSKEY/DS RRs bottom-up, and then validate
them top-down.
Caching of RRs is now only done after verification, so that the cache is
not poisoned with known invalid data.
The "DnsAnswer" object gained a substantial number of new calls, since
we need to add/remove RRs to it dynamically now.
2015-12-09 18:13:16 +01:00
|
|
|
int r;
|
2014-07-16 00:26:02 +02:00
|
|
|
|
|
|
|
assert(q);
|
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
if (!c) {
|
|
|
|
dns_query_synthesize_reply(q, &state);
|
|
|
|
dns_query_complete(q, state);
|
2014-07-16 00:26:02 +02:00
|
|
|
return;
|
2015-11-25 20:47:27 +01:00
|
|
|
}
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
SET_FOREACH(t, c->transactions, i) {
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
switch (t->state) {
|
2014-07-23 01:59:36 +02:00
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
case DNS_TRANSACTION_SUCCESS: {
|
|
|
|
/* We found a successfuly reply, merge it into the answer */
|
resolved: chase DNSKEY/DS RRs when doing look-ups with DNSSEC enabled
This adds initial support for validating RRSIG/DNSKEY/DS chains when
doing lookups. Proof-of-non-existance, or proof-of-unsigned-zones is not
implemented yet.
With this change DnsTransaction objects will generate additional
DnsTransaction objects when looking for DNSKEY or DS RRs to validate an
RRSIG on a response. DnsTransaction objects are thus created for three
reasons now:
1) Because a user asked for something to be resolved, i.e. requested by
a DnsQuery/DnsQueryCandidate object.
2) As result of LLMNR RR probing, requested by a DnsZoneItem.
3) Because another DnsTransaction requires the requested RRs for
validation of its own response.
DnsTransactions are shared between all these users, and are GC
automatically as soon as all of these users don't need a specific
transaction anymore.
To unify the handling of these three reasons for existance for a
DnsTransaction, a new common naming is introduced: each DnsTransaction
now tracks its "owners" via a Set* object named "notify_xyz", containing
all owners to notify on completion.
A new DnsTransaction state is introduced called "VALIDATING" that is
entered after a response has been receieved which needs to be validated,
as long as we are still waiting for the DNSKEY/DS RRs from other
DnsTransactions.
This patch will request the DNSKEY/DS RRs bottom-up, and then validate
them top-down.
Caching of RRs is now only done after verification, so that the cache is
not poisoned with known invalid data.
The "DnsAnswer" object gained a substantial number of new calls, since
we need to add/remove RRs to it dynamically now.
2015-12-09 18:13:16 +01:00
|
|
|
r = dns_answer_extend(&q->answer, t->answer);
|
|
|
|
if (r < 0) {
|
2015-11-25 20:47:27 +01:00
|
|
|
dns_query_complete(q, DNS_TRANSACTION_RESOURCES);
|
|
|
|
return;
|
|
|
|
}
|
2015-12-18 20:09:30 +01:00
|
|
|
|
2015-11-26 22:51:35 +01:00
|
|
|
q->answer_rcode = t->answer_rcode;
|
2015-11-25 20:47:27 +01:00
|
|
|
|
2015-12-18 20:09:30 +01:00
|
|
|
if (t->answer_authenticated) {
|
2015-12-03 21:04:52 +01:00
|
|
|
has_authenticated = true;
|
2015-12-18 20:09:30 +01:00
|
|
|
dnssec_result_authenticated = t->answer_dnssec_result;
|
|
|
|
} else {
|
2015-12-03 21:04:52 +01:00
|
|
|
has_non_authenticated = true;
|
2015-12-18 20:09:30 +01:00
|
|
|
dnssec_result_non_authenticated = t->answer_dnssec_result;
|
|
|
|
}
|
2015-12-03 21:04:52 +01:00
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
state = DNS_TRANSACTION_SUCCESS;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case DNS_TRANSACTION_NULL:
|
resolved: chase DNSKEY/DS RRs when doing look-ups with DNSSEC enabled
This adds initial support for validating RRSIG/DNSKEY/DS chains when
doing lookups. Proof-of-non-existance, or proof-of-unsigned-zones is not
implemented yet.
With this change DnsTransaction objects will generate additional
DnsTransaction objects when looking for DNSKEY or DS RRs to validate an
RRSIG on a response. DnsTransaction objects are thus created for three
reasons now:
1) Because a user asked for something to be resolved, i.e. requested by
a DnsQuery/DnsQueryCandidate object.
2) As result of LLMNR RR probing, requested by a DnsZoneItem.
3) Because another DnsTransaction requires the requested RRs for
validation of its own response.
DnsTransactions are shared between all these users, and are GC
automatically as soon as all of these users don't need a specific
transaction anymore.
To unify the handling of these three reasons for existance for a
DnsTransaction, a new common naming is introduced: each DnsTransaction
now tracks its "owners" via a Set* object named "notify_xyz", containing
all owners to notify on completion.
A new DnsTransaction state is introduced called "VALIDATING" that is
entered after a response has been receieved which needs to be validated,
as long as we are still waiting for the DNSKEY/DS RRs from other
DnsTransactions.
This patch will request the DNSKEY/DS RRs bottom-up, and then validate
them top-down.
Caching of RRs is now only done after verification, so that the cache is
not poisoned with known invalid data.
The "DnsAnswer" object gained a substantial number of new calls, since
we need to add/remove RRs to it dynamically now.
2015-12-09 18:13:16 +01:00
|
|
|
case DNS_TRANSACTION_PENDING:
|
|
|
|
case DNS_TRANSACTION_VALIDATING:
|
2015-11-25 20:47:27 +01:00
|
|
|
case DNS_TRANSACTION_ABORTED:
|
|
|
|
/* Ignore transactions that didn't complete */
|
|
|
|
continue;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* Any kind of failure? Store the data away,
|
|
|
|
* if there's nothing stored yet. */
|
2014-07-23 01:59:36 +02:00
|
|
|
|
2015-12-18 20:09:30 +01:00
|
|
|
if (state == DNS_TRANSACTION_SUCCESS)
|
|
|
|
continue;
|
2014-07-23 01:59:36 +02:00
|
|
|
|
2015-12-21 19:56:05 +01:00
|
|
|
q->answer = dns_answer_unref(q->answer);
|
2015-12-18 20:09:30 +01:00
|
|
|
q->answer_rcode = t->answer_rcode;
|
|
|
|
q->answer_dnssec_result = t->answer_dnssec_result;
|
2014-07-23 01:59:36 +02:00
|
|
|
|
2015-12-18 20:09:30 +01:00
|
|
|
state = t->state;
|
2015-11-25 20:47:27 +01:00
|
|
|
break;
|
2014-07-16 00:26:02 +02:00
|
|
|
}
|
2015-11-25 20:47:27 +01:00
|
|
|
}
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2015-12-18 20:09:30 +01:00
|
|
|
if (state == DNS_TRANSACTION_SUCCESS) {
|
|
|
|
q->answer_authenticated = has_authenticated && !has_non_authenticated;
|
|
|
|
q->answer_dnssec_result = q->answer_authenticated ? dnssec_result_authenticated : dnssec_result_non_authenticated;
|
|
|
|
}
|
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
q->answer_protocol = c->scope->protocol;
|
|
|
|
q->answer_family = c->scope->family;
|
2014-07-23 01:59:36 +02:00
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
dns_search_domain_unref(q->answer_search_domain);
|
|
|
|
q->answer_search_domain = dns_search_domain_ref(c->search_domain);
|
2014-07-23 00:57:25 +02:00
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
dns_query_synthesize_reply(q, &state);
|
|
|
|
dns_query_complete(q, state);
|
|
|
|
}
|
2014-07-23 01:59:36 +02:00
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
void dns_query_ready(DnsQuery *q) {
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
DnsQueryCandidate *bad = NULL, *c;
|
|
|
|
bool pending = false;
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
assert(q);
|
resolved: chase DNSKEY/DS RRs when doing look-ups with DNSSEC enabled
This adds initial support for validating RRSIG/DNSKEY/DS chains when
doing lookups. Proof-of-non-existance, or proof-of-unsigned-zones is not
implemented yet.
With this change DnsTransaction objects will generate additional
DnsTransaction objects when looking for DNSKEY or DS RRs to validate an
RRSIG on a response. DnsTransaction objects are thus created for three
reasons now:
1) Because a user asked for something to be resolved, i.e. requested by
a DnsQuery/DnsQueryCandidate object.
2) As result of LLMNR RR probing, requested by a DnsZoneItem.
3) Because another DnsTransaction requires the requested RRs for
validation of its own response.
DnsTransactions are shared between all these users, and are GC
automatically as soon as all of these users don't need a specific
transaction anymore.
To unify the handling of these three reasons for existance for a
DnsTransaction, a new common naming is introduced: each DnsTransaction
now tracks its "owners" via a Set* object named "notify_xyz", containing
all owners to notify on completion.
A new DnsTransaction state is introduced called "VALIDATING" that is
entered after a response has been receieved which needs to be validated,
as long as we are still waiting for the DNSKEY/DS RRs from other
DnsTransactions.
This patch will request the DNSKEY/DS RRs bottom-up, and then validate
them top-down.
Caching of RRs is now only done after verification, so that the cache is
not poisoned with known invalid data.
The "DnsAnswer" object gained a substantial number of new calls, since
we need to add/remove RRs to it dynamically now.
2015-12-09 18:13:16 +01:00
|
|
|
assert(DNS_TRANSACTION_IS_LIVE(q->state));
|
2014-07-30 20:39:52 +02:00
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
/* Note that this call might invalidate the query. Callers
|
|
|
|
* should hence not attempt to access the query or transaction
|
|
|
|
* after calling this function, unless the block_ready
|
|
|
|
* counter was explicitly bumped before doing so. */
|
|
|
|
|
|
|
|
if (q->block_ready > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
LIST_FOREACH(candidates_by_query, c, q->candidates) {
|
|
|
|
DnsTransactionState state;
|
|
|
|
|
|
|
|
state = dns_query_candidate_state(c);
|
|
|
|
switch (state) {
|
|
|
|
|
|
|
|
case DNS_TRANSACTION_SUCCESS:
|
resolved: chase DNSKEY/DS RRs when doing look-ups with DNSSEC enabled
This adds initial support for validating RRSIG/DNSKEY/DS chains when
doing lookups. Proof-of-non-existance, or proof-of-unsigned-zones is not
implemented yet.
With this change DnsTransaction objects will generate additional
DnsTransaction objects when looking for DNSKEY or DS RRs to validate an
RRSIG on a response. DnsTransaction objects are thus created for three
reasons now:
1) Because a user asked for something to be resolved, i.e. requested by
a DnsQuery/DnsQueryCandidate object.
2) As result of LLMNR RR probing, requested by a DnsZoneItem.
3) Because another DnsTransaction requires the requested RRs for
validation of its own response.
DnsTransactions are shared between all these users, and are GC
automatically as soon as all of these users don't need a specific
transaction anymore.
To unify the handling of these three reasons for existance for a
DnsTransaction, a new common naming is introduced: each DnsTransaction
now tracks its "owners" via a Set* object named "notify_xyz", containing
all owners to notify on completion.
A new DnsTransaction state is introduced called "VALIDATING" that is
entered after a response has been receieved which needs to be validated,
as long as we are still waiting for the DNSKEY/DS RRs from other
DnsTransactions.
This patch will request the DNSKEY/DS RRs bottom-up, and then validate
them top-down.
Caching of RRs is now only done after verification, so that the cache is
not poisoned with known invalid data.
The "DnsAnswer" object gained a substantial number of new calls, since
we need to add/remove RRs to it dynamically now.
2015-12-09 18:13:16 +01:00
|
|
|
/* One of the candidates is successful,
|
2015-11-25 20:47:27 +01:00
|
|
|
* let's use it, and copy its data out */
|
|
|
|
dns_query_accept(q, c);
|
2014-07-30 20:39:52 +02:00
|
|
|
return;
|
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
case DNS_TRANSACTION_NULL:
|
resolved: chase DNSKEY/DS RRs when doing look-ups with DNSSEC enabled
This adds initial support for validating RRSIG/DNSKEY/DS chains when
doing lookups. Proof-of-non-existance, or proof-of-unsigned-zones is not
implemented yet.
With this change DnsTransaction objects will generate additional
DnsTransaction objects when looking for DNSKEY or DS RRs to validate an
RRSIG on a response. DnsTransaction objects are thus created for three
reasons now:
1) Because a user asked for something to be resolved, i.e. requested by
a DnsQuery/DnsQueryCandidate object.
2) As result of LLMNR RR probing, requested by a DnsZoneItem.
3) Because another DnsTransaction requires the requested RRs for
validation of its own response.
DnsTransactions are shared between all these users, and are GC
automatically as soon as all of these users don't need a specific
transaction anymore.
To unify the handling of these three reasons for existance for a
DnsTransaction, a new common naming is introduced: each DnsTransaction
now tracks its "owners" via a Set* object named "notify_xyz", containing
all owners to notify on completion.
A new DnsTransaction state is introduced called "VALIDATING" that is
entered after a response has been receieved which needs to be validated,
as long as we are still waiting for the DNSKEY/DS RRs from other
DnsTransactions.
This patch will request the DNSKEY/DS RRs bottom-up, and then validate
them top-down.
Caching of RRs is now only done after verification, so that the cache is
not poisoned with known invalid data.
The "DnsAnswer" object gained a substantial number of new calls, since
we need to add/remove RRs to it dynamically now.
2015-12-09 18:13:16 +01:00
|
|
|
case DNS_TRANSACTION_PENDING:
|
|
|
|
case DNS_TRANSACTION_VALIDATING:
|
|
|
|
/* One of the candidates is still going on,
|
|
|
|
* let's maybe wait for it */
|
2015-11-25 20:47:27 +01:00
|
|
|
pending = true;
|
|
|
|
break;
|
2014-07-30 20:39:52 +02:00
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
default:
|
|
|
|
/* Any kind of failure */
|
|
|
|
bad = c;
|
|
|
|
break;
|
|
|
|
}
|
2014-07-22 21:48:41 +02:00
|
|
|
}
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
if (pending)
|
|
|
|
return;
|
2015-08-14 13:17:05 +02:00
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
dns_query_accept(q, bad);
|
2014-07-16 00:26:02 +02:00
|
|
|
}
|
2014-07-16 22:09:00 +02:00
|
|
|
|
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
|
|
|
static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) {
|
2014-07-22 21:48:41 +02:00
|
|
|
_cleanup_(dns_question_unrefp) DnsQuestion *nq = NULL;
|
|
|
|
int r;
|
2014-07-16 22:09:00 +02:00
|
|
|
|
|
|
|
assert(q);
|
|
|
|
|
2015-12-09 18:04:03 +01:00
|
|
|
log_debug("Following CNAME %s → %s", dns_question_first_name(q->question), cname->cname.name);
|
|
|
|
|
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
|
|
|
q->n_cname_redirects ++;
|
2014-07-22 21:48:41 +02:00
|
|
|
if (q->n_cname_redirects > CNAME_MAX)
|
2014-07-16 22:09:00 +02:00
|
|
|
return -ELOOP;
|
|
|
|
|
2015-09-04 01:56:23 +02:00
|
|
|
r = dns_question_cname_redirect(q->question, cname, &nq);
|
2014-07-22 21:48:41 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-07-16 22:09:00 +02:00
|
|
|
|
2014-07-22 21:48:41 +02:00
|
|
|
dns_question_unref(q->question);
|
|
|
|
q->question = nq;
|
|
|
|
nq = NULL;
|
2014-07-16 22:09:00 +02:00
|
|
|
|
2014-07-17 19:38:37 +02:00
|
|
|
dns_query_stop(q);
|
2014-07-31 17:46:40 +02:00
|
|
|
q->state = DNS_TRANSACTION_NULL;
|
2014-07-17 19:38:37 +02:00
|
|
|
|
2014-07-16 22:09:00 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2014-08-06 16:32:55 +02:00
|
|
|
|
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
|
|
|
int dns_query_process_cname(DnsQuery *q) {
|
|
|
|
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL;
|
|
|
|
DnsResourceRecord *rr;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(q);
|
|
|
|
|
|
|
|
if (q->state != DNS_TRANSACTION_SUCCESS)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
DNS_ANSWER_FOREACH(rr, q->answer) {
|
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
r = dns_question_matches_rr(q->question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
|
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r > 0)
|
|
|
|
return 0; /* The answer matches directly, no need to follow cnames */
|
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
r = dns_question_matches_cname(q->question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
|
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r > 0 && !cname)
|
|
|
|
cname = dns_resource_record_ref(rr);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cname)
|
|
|
|
return 0; /* No cname to follow */
|
|
|
|
|
|
|
|
if (q->flags & SD_RESOLVED_NO_CNAME)
|
|
|
|
return -ELOOP;
|
|
|
|
|
|
|
|
/* OK, let's actually follow the CNAME */
|
|
|
|
r = dns_query_cname_redirect(q, cname);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
/* Let's see if the answer can already answer the new
|
|
|
|
* redirected question */
|
|
|
|
DNS_ANSWER_FOREACH(rr, q->answer) {
|
2015-11-25 20:47:27 +01:00
|
|
|
r = dns_question_matches_rr(q->question, rr, NULL);
|
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r > 0)
|
|
|
|
return 0; /* It can answer it, yay! */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* OK, it cannot, let's begin with the new query */
|
|
|
|
r = dns_query_go(q);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 1; /* We return > 0, if we restarted the query for a new cname */
|
|
|
|
}
|
|
|
|
|
2014-08-06 16:32:55 +02:00
|
|
|
static int on_bus_track(sd_bus_track *t, void *userdata) {
|
|
|
|
DnsQuery *q = userdata;
|
|
|
|
|
|
|
|
assert(t);
|
|
|
|
assert(q);
|
|
|
|
|
|
|
|
log_debug("Client of active query vanished, aborting query.");
|
|
|
|
dns_query_complete(q, DNS_TRANSACTION_ABORTED);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-29 19:10:09 +02:00
|
|
|
int dns_query_bus_track(DnsQuery *q, sd_bus_message *m) {
|
2014-08-06 16:32:55 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(q);
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (!q->bus_track) {
|
2015-04-29 19:10:09 +02:00
|
|
|
r = sd_bus_track_new(sd_bus_message_get_bus(m), &q->bus_track, on_bus_track, q);
|
2014-08-06 16:32:55 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_bus_track_add_sender(q->bus_track, m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|