2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2015-08-14 13:17:05 +02:00
|
|
|
#include "dns-domain.h"
|
2016-02-01 00:00:01 +01:00
|
|
|
#include "dns-type.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"
|
2016-01-20 22:06:26 +01:00
|
|
|
#include "resolved-dns-synthesize.h"
|
2016-01-22 12:24:20 +01:00
|
|
|
#include "resolved-etc-hosts.h"
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
#include "string-util.h"
|
2014-07-16 00:26:02 +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);
|
2016-02-22 20:39:45 +01:00
|
|
|
set_remove(t->notify_query_candidates_done, 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);
|
|
|
|
|
2016-10-17 00:28:30 +02:00
|
|
|
return mfree(c);
|
2015-11-25 20:47:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int dns_query_candidate_next_search_domain(DnsQueryCandidate *c) {
|
|
|
|
DnsSearchDomain *next = NULL;
|
|
|
|
|
|
|
|
assert(c);
|
|
|
|
|
2016-01-25 23:19:49 +01:00
|
|
|
if (c->search_domain && c->search_domain->linked)
|
2015-11-25 20:47:27 +01:00
|
|
|
next = c->search_domain->domains_next;
|
2016-01-25 23:19:49 +01:00
|
|
|
else
|
|
|
|
next = dns_scope_get_search_domains(c->scope);
|
2015-11-25 20:47:27 +01:00
|
|
|
|
2016-01-25 23:19:49 +01:00
|
|
|
for (;;) {
|
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
|
|
|
|
2016-01-25 23:19:49 +01:00
|
|
|
if (!next->route_only)
|
|
|
|
break;
|
2015-11-25 20:47:27 +01:00
|
|
|
|
2016-01-25 23:19:49 +01:00
|
|
|
/* Skip over route-only domains */
|
|
|
|
next = next->domains_next;
|
2015-11-25 20:47:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2020-06-03 14:25:18 +02:00
|
|
|
_cleanup_(dns_transaction_gcp) DnsTransaction *t = NULL;
|
2015-11-25 20:47:27 +01:00
|
|
|
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;
|
2020-06-03 14:25:18 +02: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)
|
2020-06-03 14:25:18 +02:00
|
|
|
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
|
|
|
|
|
|
|
r = set_ensure_allocated(&t->notify_query_candidates, NULL);
|
2015-11-25 20:47:27 +01:00
|
|
|
if (r < 0)
|
2020-06-03 14:25:18 +02:00
|
|
|
return r;
|
2015-11-25 20:47:27 +01:00
|
|
|
|
2016-02-22 20:39:45 +01:00
|
|
|
r = set_ensure_allocated(&t->notify_query_candidates_done, NULL);
|
|
|
|
if (r < 0)
|
2020-06-03 14:25:18 +02:00
|
|
|
return r;
|
2016-02-22 20:39:45 +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_put(t->notify_query_candidates, c);
|
2015-11-25 20:47:27 +01:00
|
|
|
if (r < 0)
|
2020-06-03 14:25:18 +02:00
|
|
|
return r;
|
2015-11-25 20:47:27 +01:00
|
|
|
|
|
|
|
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);
|
2020-06-03 14:25:18 +02:00
|
|
|
return r;
|
2015-11-25 20:47:27 +01:00
|
|
|
}
|
|
|
|
|
2016-06-20 21:24:46 +02:00
|
|
|
t->clamp_ttl = c->query->clamp_ttl;
|
2020-06-03 14:25:18 +02:00
|
|
|
TAKE_PTR(t);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
static int dns_query_candidate_go(DnsQueryCandidate *c) {
|
|
|
|
DnsTransaction *t;
|
|
|
|
Iterator i;
|
|
|
|
int r;
|
2016-02-01 00:00:01 +01:00
|
|
|
unsigned n = 0;
|
2015-11-25 20:47:27 +01:00
|
|
|
|
|
|
|
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;
|
2016-02-01 00:00:01 +01:00
|
|
|
|
|
|
|
n++;
|
2015-11-25 20:47:27 +01:00
|
|
|
}
|
|
|
|
|
2016-02-01 00:00:01 +01:00
|
|
|
/* If there was nothing to start, then let's proceed immediately */
|
|
|
|
if (n == 0)
|
|
|
|
dns_query_candidate_notify(c);
|
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
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)
|
2016-01-22 17:22:23 +01:00
|
|
|
return DNS_TRANSACTION_ERRNO;
|
2015-11-25 20:47:27 +01:00
|
|
|
|
|
|
|
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) {
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
DnsQuestion *question;
|
2015-11-25 20:47:27 +01:00
|
|
|
DnsResourceKey *key;
|
|
|
|
int n = 0, r;
|
|
|
|
|
|
|
|
assert(c);
|
|
|
|
|
|
|
|
dns_query_candidate_stop(c);
|
|
|
|
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
question = dns_query_question_for_protocol(c->query, c->scope->protocol);
|
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
/* Create one transaction per question key */
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
DNS_QUESTION_FOREACH(key, question) {
|
2015-11-25 20:47:27 +01:00
|
|
|
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *new_key = NULL;
|
2016-02-01 00:00:01 +01:00
|
|
|
DnsResourceKey *qkey;
|
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
if (c->search_domain) {
|
|
|
|
r = dns_resource_key_new_append_suffix(&new_key, key, c->search_domain->name);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
|
|
|
|
2016-02-01 00:00:01 +01:00
|
|
|
qkey = new_key;
|
|
|
|
} else
|
|
|
|
qkey = key;
|
|
|
|
|
|
|
|
if (!dns_scope_good_key(c->scope, qkey))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = dns_query_candidate_add_transaction(c, qkey);
|
2015-11-25 20:47:27 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2016-01-18 21:30:45 +01:00
|
|
|
static void dns_query_free_candidates(DnsQuery *q) {
|
|
|
|
assert(q);
|
|
|
|
|
|
|
|
while (q->candidates)
|
|
|
|
dns_query_candidate_free(q->candidates);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dns_query_reset_answer(DnsQuery *q) {
|
|
|
|
assert(q);
|
|
|
|
|
|
|
|
q->answer = dns_answer_unref(q->answer);
|
|
|
|
q->answer_rcode = 0;
|
|
|
|
q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
|
2016-01-22 17:22:23 +01:00
|
|
|
q->answer_errno = 0;
|
2016-01-18 21:30:45 +01:00
|
|
|
q->answer_authenticated = false;
|
|
|
|
q->answer_protocol = _DNS_PROTOCOL_INVALID;
|
|
|
|
q->answer_family = AF_UNSPEC;
|
|
|
|
q->answer_search_domain = dns_search_domain_unref(q->answer_search_domain);
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2016-01-18 21:30:45 +01:00
|
|
|
dns_query_free_candidates(q);
|
2014-07-17 19:38:37 +02:00
|
|
|
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
dns_question_unref(q->question_idna);
|
|
|
|
dns_question_unref(q->question_utf8);
|
2016-01-18 21:30:45 +01:00
|
|
|
|
|
|
|
dns_query_reset_answer(q);
|
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
|
|
|
|
resolved: respond to local resolver requests on 127.0.0.53:53
In order to improve compatibility with local clients that speak DNS directly
(and do not use NSS or our bus API) listen locally on 127.0.0.53:53 and process
any queries made that way.
Note that resolved does not implement a full DNS server on this port, but
simply enough to allow normal, local clients to resolve RRs through resolved.
Specifically it does not implement queries without the RD bit set (these are
requests where recursive lookups are explicitly disabled), and neither queries
with DNSSEC DO set in combination with DNSSEC CD (i.e. DNSSEC lookups with
validation turned off). It also refuses zone transfers and obsolete RR types.
All lookups done this way will be rejected with a clean error code, so that the
client side can repeat the query with a reduced feature set.
The code will set the DNSSEC AD flag however, depending on whether the data
resolved has been validated (or comes from a local, trusted source).
Lookups made via this mechanisms are propagated to LLMNR and mDNS as necessary,
but this is only partially useful as DNS packets cannot carry IP scope data
(i.e. the ifindex), and hence link-local addresses returned cannot be used
properly (and given that LLMNR/mDNS are mostly about link-local communication
this is quite a limitation). Also, given that DNS tends to use IDNA for
non-ASCII names, while LLMNR/mDNS uses UTF-8 lookups cannot be mapped 1:1.
In general this should improve compatibility with clients bypassing NSS but
it is highly recommended for clients to instead use NSS or our native bus API.
This patch also beefs up the DnsStream logic, as it reuses the code for local
TCP listening. DnsStream now provides proper reference counting for its
objects.
In order to avoid feedback loops resolved will no silently ignore 127.0.0.53
specified as DNS server when reading configuration.
resolved listens on 127.0.0.53:53 instead of 127.0.0.1:53 in order to leave
the latter free for local, external DNS servers or forwarders.
This also changes the "etc.conf" tmpfiles snippet to create a symlink from
/etc/resolv.conf to /usr/lib/systemd/resolv.conf by default, thus making this
stub the default mode of operation if /etc is not populated.
2016-06-21 00:58:47 +02:00
|
|
|
dns_packet_unref(q->request_dns_packet);
|
2017-02-08 19:12:55 +01:00
|
|
|
dns_packet_unref(q->reply_dns_packet);
|
resolved: respond to local resolver requests on 127.0.0.53:53
In order to improve compatibility with local clients that speak DNS directly
(and do not use NSS or our bus API) listen locally on 127.0.0.53:53 and process
any queries made that way.
Note that resolved does not implement a full DNS server on this port, but
simply enough to allow normal, local clients to resolve RRs through resolved.
Specifically it does not implement queries without the RD bit set (these are
requests where recursive lookups are explicitly disabled), and neither queries
with DNSSEC DO set in combination with DNSSEC CD (i.e. DNSSEC lookups with
validation turned off). It also refuses zone transfers and obsolete RR types.
All lookups done this way will be rejected with a clean error code, so that the
client side can repeat the query with a reduced feature set.
The code will set the DNSSEC AD flag however, depending on whether the data
resolved has been validated (or comes from a local, trusted source).
Lookups made via this mechanisms are propagated to LLMNR and mDNS as necessary,
but this is only partially useful as DNS packets cannot carry IP scope data
(i.e. the ifindex), and hence link-local addresses returned cannot be used
properly (and given that LLMNR/mDNS are mostly about link-local communication
this is quite a limitation). Also, given that DNS tends to use IDNA for
non-ASCII names, while LLMNR/mDNS uses UTF-8 lookups cannot be mapped 1:1.
In general this should improve compatibility with clients bypassing NSS but
it is highly recommended for clients to instead use NSS or our native bus API.
This patch also beefs up the DnsStream logic, as it reuses the code for local
TCP listening. DnsStream now provides proper reference counting for its
objects.
In order to avoid feedback loops resolved will no silently ignore 127.0.0.53
specified as DNS server when reading configuration.
resolved listens on 127.0.0.53:53 instead of 127.0.0.1:53 in order to leave
the latter free for local, external DNS servers or forwarders.
This also changes the "etc.conf" tmpfiles snippet to create a symlink from
/etc/resolv.conf to /usr/lib/systemd/resolv.conf by default, thus making this
stub the default mode of operation if /etc is not populated.
2016-06-21 00:58:47 +02:00
|
|
|
|
|
|
|
if (q->request_dns_stream) {
|
|
|
|
/* Detach the stream from our query, in case something else keeps a reference to it. */
|
2019-01-21 19:44:30 +01:00
|
|
|
(void) set_remove(q->request_dns_stream->queries, q);
|
|
|
|
q->request_dns_stream = dns_stream_unref(q->request_dns_stream);
|
resolved: respond to local resolver requests on 127.0.0.53:53
In order to improve compatibility with local clients that speak DNS directly
(and do not use NSS or our bus API) listen locally on 127.0.0.53:53 and process
any queries made that way.
Note that resolved does not implement a full DNS server on this port, but
simply enough to allow normal, local clients to resolve RRs through resolved.
Specifically it does not implement queries without the RD bit set (these are
requests where recursive lookups are explicitly disabled), and neither queries
with DNSSEC DO set in combination with DNSSEC CD (i.e. DNSSEC lookups with
validation turned off). It also refuses zone transfers and obsolete RR types.
All lookups done this way will be rejected with a clean error code, so that the
client side can repeat the query with a reduced feature set.
The code will set the DNSSEC AD flag however, depending on whether the data
resolved has been validated (or comes from a local, trusted source).
Lookups made via this mechanisms are propagated to LLMNR and mDNS as necessary,
but this is only partially useful as DNS packets cannot carry IP scope data
(i.e. the ifindex), and hence link-local addresses returned cannot be used
properly (and given that LLMNR/mDNS are mostly about link-local communication
this is quite a limitation). Also, given that DNS tends to use IDNA for
non-ASCII names, while LLMNR/mDNS uses UTF-8 lookups cannot be mapped 1:1.
In general this should improve compatibility with clients bypassing NSS but
it is highly recommended for clients to instead use NSS or our native bus API.
This patch also beefs up the DnsStream logic, as it reuses the code for local
TCP listening. DnsStream now provides proper reference counting for its
objects.
In order to avoid feedback loops resolved will no silently ignore 127.0.0.53
specified as DNS server when reading configuration.
resolved listens on 127.0.0.53:53 instead of 127.0.0.1:53 in order to leave
the latter free for local, external DNS servers or forwarders.
This also changes the "etc.conf" tmpfiles snippet to create a symlink from
/etc/resolv.conf to /usr/lib/systemd/resolv.conf by default, thus making this
stub the default mode of operation if /etc is not populated.
2016-06-21 00:58:47 +02:00
|
|
|
}
|
|
|
|
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
free(q->request_address_string);
|
|
|
|
|
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
|
|
|
|
2016-10-17 00:28:30 +02:00
|
|
|
return mfree(q);
|
2014-07-16 00:26:02 +02:00
|
|
|
}
|
|
|
|
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
int dns_query_new(
|
|
|
|
Manager *m,
|
|
|
|
DnsQuery **ret,
|
|
|
|
DnsQuestion *question_utf8,
|
|
|
|
DnsQuestion *question_idna,
|
2016-06-20 21:24:46 +02:00
|
|
|
int ifindex,
|
|
|
|
uint64_t flags) {
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
|
2014-07-16 00:26:02 +02:00
|
|
|
_cleanup_(dns_query_freep) DnsQuery *q = NULL;
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
DnsResourceKey *key;
|
|
|
|
bool good = false;
|
2014-07-22 21:48:41 +02:00
|
|
|
int r;
|
2016-02-15 00:51:55 +01:00
|
|
|
char key_str[DNS_RESOURCE_KEY_STRING_MAX];
|
2014-07-16 00:26:02 +02:00
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
if (dns_question_size(question_utf8) > 0) {
|
|
|
|
r = dns_question_is_valid_for_query(question_utf8);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
good = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the IDNA and UTF8 questions are the same, merge their references */
|
|
|
|
r = dns_question_is_equal(question_idna, question_utf8);
|
2014-07-22 21:48:41 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
if (r > 0)
|
|
|
|
question_idna = question_utf8;
|
|
|
|
else {
|
|
|
|
if (dns_question_size(question_idna) > 0) {
|
|
|
|
r = dns_question_is_valid_for_query(question_idna);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
good = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!good) /* don't allow empty queries */
|
|
|
|
return -EINVAL;
|
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;
|
|
|
|
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
q->question_utf8 = dns_question_ref(question_utf8);
|
|
|
|
q->question_idna = dns_question_ref(question_idna);
|
2014-08-14 01:00:15 +02:00
|
|
|
q->ifindex = ifindex;
|
|
|
|
q->flags = flags;
|
2016-01-18 21:30:45 +01:00
|
|
|
q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
|
2015-11-25 20:47:27 +01:00
|
|
|
q->answer_protocol = _DNS_PROTOCOL_INVALID;
|
2016-01-18 21:30:45 +01:00
|
|
|
q->answer_family = AF_UNSPEC;
|
2014-07-17 19:38:37 +02:00
|
|
|
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
/* First dump UTF8 question */
|
2016-02-15 00:51:55 +01:00
|
|
|
DNS_QUESTION_FOREACH(key, question_utf8)
|
|
|
|
log_debug("Looking up RR for %s.",
|
|
|
|
dns_resource_key_to_string(key, key_str, sizeof key_str));
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
|
|
|
|
/* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */
|
|
|
|
DNS_QUESTION_FOREACH(key, question_idna) {
|
|
|
|
r = dns_question_contains(question_utf8, key);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r > 0)
|
|
|
|
continue;
|
|
|
|
|
2016-02-15 00:51:55 +01:00
|
|
|
log_debug("Looking up IDNA RR for %s.",
|
|
|
|
dns_resource_key_to_string(key, key_str, sizeof key_str));
|
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);
|
|
|
|
|
2016-07-10 14:48:23 +02:00
|
|
|
/* Ensure that the query is not auxiliary yet, and
|
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
|
|
|
* 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. */
|
2018-06-25 06:46:52 +02:00
|
|
|
if ((q->flags & SD_RESOLVED_NO_SEARCH) == 0 &&
|
|
|
|
dns_scope_name_needs_search_domain(s, dns_question_first_name(q->question_idna))) {
|
|
|
|
/* OK, we need a search domain now. Let's find one for this scope */
|
2015-12-03 18:20:56 +01:00
|
|
|
|
2018-06-25 06:46:52 +02:00
|
|
|
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-17 23:54:08 +02:00
|
|
|
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;
|
2016-01-22 12:24:20 +01:00
|
|
|
int r;
|
2015-08-14 13:17:05 +02:00
|
|
|
|
|
|
|
assert(q);
|
|
|
|
assert(state);
|
|
|
|
|
2016-01-22 12:24:20 +01:00
|
|
|
/* Tries to synthesize localhost RR replies (and others) where appropriate. Note that this is done *after* the
|
|
|
|
* the normal lookup finished. The data from the network hence takes precedence over the data we
|
|
|
|
* synthesize. (But note that many scopes refuse to resolve certain domain names) */
|
2015-08-14 13:17:05 +02:00
|
|
|
|
|
|
|
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,
|
2016-01-20 21:28:22 +01:00
|
|
|
DNS_TRANSACTION_ATTEMPTS_MAX_REACHED,
|
2016-01-22 12:09:38 +01:00
|
|
|
DNS_TRANSACTION_NETWORK_DOWN,
|
|
|
|
DNS_TRANSACTION_NOT_FOUND))
|
2015-08-17 23:54:08 +02:00
|
|
|
return 0;
|
2015-08-14 13:17:05 +02:00
|
|
|
|
2016-01-20 22:06:26 +01:00
|
|
|
r = dns_synthesize_answer(
|
|
|
|
q->manager,
|
|
|
|
q->question_utf8,
|
|
|
|
q->ifindex,
|
2016-01-22 12:24:20 +01:00
|
|
|
&answer);
|
2017-09-29 18:01:04 +02:00
|
|
|
if (r == -ENXIO) {
|
|
|
|
/* If we get ENXIO this tells us to generate NXDOMAIN unconditionally. */
|
2015-08-14 13:17:05 +02:00
|
|
|
|
2017-09-29 18:01:04 +02:00
|
|
|
dns_query_reset_answer(q);
|
|
|
|
q->answer_rcode = DNS_RCODE_NXDOMAIN;
|
|
|
|
q->answer_protocol = dns_synthesize_protocol(q->flags);
|
|
|
|
q->answer_family = dns_synthesize_family(q->flags);
|
|
|
|
q->answer_authenticated = true;
|
|
|
|
*state = DNS_TRANSACTION_RCODE_FAILURE;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2016-01-20 22:06:26 +01:00
|
|
|
if (r <= 0)
|
|
|
|
return r;
|
2015-08-14 13:17:05 +02:00
|
|
|
|
2016-01-20 22:06:26 +01:00
|
|
|
dns_query_reset_answer(q);
|
2015-08-14 13:17:05 +02:00
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
q->answer = TAKE_PTR(answer);
|
2015-08-14 13:17:05 +02:00
|
|
|
q->answer_rcode = DNS_RCODE_SUCCESS;
|
2016-01-22 12:24:20 +01:00
|
|
|
q->answer_protocol = dns_synthesize_protocol(q->flags);
|
|
|
|
q->answer_family = dns_synthesize_family(q->flags);
|
2016-01-20 22:06:26 +01:00
|
|
|
q->answer_authenticated = true;
|
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
|
|
|
}
|
|
|
|
|
2016-01-22 12:24:20 +01:00
|
|
|
static int dns_query_try_etc_hosts(DnsQuery *q) {
|
|
|
|
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(q);
|
|
|
|
|
|
|
|
/* Looks in /etc/hosts for matching entries. Note that this is done *before* the normal lookup is done. The
|
|
|
|
* data from /etc/hosts hence takes precedence over the network. */
|
|
|
|
|
|
|
|
r = manager_etc_hosts_lookup(
|
|
|
|
q->manager,
|
|
|
|
q->question_utf8,
|
|
|
|
&answer);
|
|
|
|
if (r <= 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
dns_query_reset_answer(q);
|
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
q->answer = TAKE_PTR(answer);
|
2016-01-22 12:24:20 +01:00
|
|
|
q->answer_rcode = DNS_RCODE_SUCCESS;
|
|
|
|
q->answer_protocol = dns_synthesize_protocol(q->flags);
|
|
|
|
q->answer_family = dns_synthesize_family(q->flags);
|
|
|
|
q->answer_authenticated = true;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
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-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;
|
|
|
|
|
2016-01-22 12:24:20 +01:00
|
|
|
r = dns_query_try_etc_hosts(q);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r > 0) {
|
|
|
|
dns_query_complete(q, DNS_TRANSACTION_SUCCESS);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
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;
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
const char *name;
|
|
|
|
|
|
|
|
name = dns_question_first_name(dns_query_question_for_protocol(q, s->protocol));
|
|
|
|
if (!name)
|
|
|
|
continue;
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2014-08-14 01:00:15 +02:00
|
|
|
match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
|
2018-12-03 16:25:00 +01:00
|
|
|
if (match < 0) {
|
|
|
|
log_debug("Couldn't check if '%s' matches against scope, ignoring.", name);
|
2014-07-16 00:26:02 +02:00
|
|
|
continue;
|
2018-12-03 16:25:00 +01:00
|
|
|
}
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2018-12-03 16:25:00 +01:00
|
|
|
if (match > found) { /* Does this match better? If so, remember how well it matched, and the first one
|
|
|
|
* that matches this well */
|
|
|
|
found = match;
|
2014-07-16 00:26:02 +02:00
|
|
|
first = s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-14 13:17:05 +02:00
|
|
|
if (found == DNS_SCOPE_NO) {
|
|
|
|
DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
|
|
|
|
|
2016-01-22 17:22:23 +01:00
|
|
|
r = dns_query_synthesize_reply(q, &state);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
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;
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
const char *name;
|
|
|
|
|
|
|
|
name = dns_question_first_name(dns_query_question_for_protocol(q, s->protocol));
|
|
|
|
if (!name)
|
|
|
|
continue;
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2014-08-14 01:00:15 +02:00
|
|
|
match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
|
2018-12-03 16:25:00 +01:00
|
|
|
if (match < 0) {
|
2019-01-23 22:33:29 +01:00
|
|
|
log_debug("Couldn't check if '%s' matches against scope, ignoring.", name);
|
2018-12-03 16:25:00 +01:00
|
|
|
continue;
|
|
|
|
}
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2018-12-03 16:25:00 +01:00
|
|
|
if (match < found)
|
2014-07-16 00:26:02 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2016-01-22 17:34:10 +01:00
|
|
|
dns_query_reset_answer(q);
|
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(),
|
2018-01-23 01:53:31 +01:00
|
|
|
now(clock_boottime_or_monotonic()) + SD_RESOLVED_QUERY_TIMEOUT_USEC,
|
|
|
|
0, on_query_timeout, q);
|
2014-07-16 00:26:02 +02:00
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
|
|
|
|
2016-01-08 02:20:39 +01:00
|
|
|
(void) sd_event_source_set_description(q->timeout_event_source, "query-timeout");
|
|
|
|
|
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) {
|
2016-01-22 17:22:23 +01:00
|
|
|
r = dns_query_synthesize_reply(q, &state);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
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
|
|
|
|
2016-01-22 17:24:05 +01:00
|
|
|
if (c->error_code != 0) {
|
|
|
|
/* If the candidate had an error condition of its own, start with that. */
|
|
|
|
state = DNS_TRANSACTION_ERRNO;
|
|
|
|
q->answer = dns_answer_unref(q->answer);
|
|
|
|
q->answer_rcode = 0;
|
|
|
|
q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
|
2017-02-15 15:29:05 +01:00
|
|
|
q->answer_authenticated = false;
|
2016-01-22 17:24:05 +01:00
|
|
|
q->answer_errno = c->error_code;
|
|
|
|
}
|
|
|
|
|
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: {
|
2016-05-04 11:26:17 +02:00
|
|
|
/* We found a successfully 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);
|
2016-01-22 17:22:23 +01:00
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
2015-12-18 20:09:30 +01:00
|
|
|
|
2015-11-26 22:51:35 +01:00
|
|
|
q->answer_rcode = t->answer_rcode;
|
2016-01-22 17:22:23 +01:00
|
|
|
q->answer_errno = 0;
|
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:
|
2017-02-15 15:29:05 +01:00
|
|
|
/* Any kind of failure? Store the data away, if there's nothing stored yet. */
|
2015-12-18 20:09:30 +01:00
|
|
|
if (state == DNS_TRANSACTION_SUCCESS)
|
|
|
|
continue;
|
2014-07-23 01:59:36 +02:00
|
|
|
|
2017-02-15 15:29:05 +01:00
|
|
|
/* If there's already an authenticated negative reply stored, then prefer that over any unauthenticated one */
|
|
|
|
if (q->answer_authenticated && !t->answer_authenticated)
|
|
|
|
continue;
|
|
|
|
|
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;
|
2017-02-15 15:29:05 +01:00
|
|
|
q->answer_authenticated = t->answer_authenticated;
|
2016-01-22 17:22:23 +01:00
|
|
|
q->answer_errno = t->answer_errno;
|
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
|
|
|
|
2016-01-22 17:22:23 +01:00
|
|
|
r = dns_query_synthesize_reply(q, &state);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
|
|
|
|
2015-11-25 20:47:27 +01:00
|
|
|
dns_query_complete(q, state);
|
2016-01-22 17:22:23 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
q->answer_errno = -r;
|
|
|
|
dns_query_complete(q, DNS_TRANSACTION_ERRNO);
|
2015-11-25 20:47:27 +01:00
|
|
|
}
|
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) {
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
_cleanup_(dns_question_unrefp) DnsQuestion *nq_idna = NULL, *nq_utf8 = NULL;
|
|
|
|
int r, k;
|
2014-07-16 22:09:00 +02:00
|
|
|
|
|
|
|
assert(q);
|
|
|
|
|
2016-02-23 05:32:04 +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;
|
|
|
|
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
r = dns_question_cname_redirect(q->question_idna, cname, &nq_idna);
|
2014-07-22 21:48:41 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
else if (r > 0)
|
2016-01-18 22:34:41 +01:00
|
|
|
log_debug("Following CNAME/DNAME %s → %s.", dns_question_first_name(q->question_idna), dns_question_first_name(nq_idna));
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
|
|
|
|
k = dns_question_is_equal(q->question_idna, q->question_utf8);
|
|
|
|
if (k < 0)
|
|
|
|
return r;
|
|
|
|
if (k > 0) {
|
|
|
|
/* Same question? Shortcut new question generation */
|
|
|
|
nq_utf8 = dns_question_ref(nq_idna);
|
|
|
|
k = r;
|
|
|
|
} else {
|
|
|
|
k = dns_question_cname_redirect(q->question_utf8, cname, &nq_utf8);
|
|
|
|
if (k < 0)
|
|
|
|
return k;
|
|
|
|
else if (k > 0)
|
2016-01-18 22:34:41 +01:00
|
|
|
log_debug("Following UTF8 CNAME/DNAME %s → %s.", dns_question_first_name(q->question_utf8), dns_question_first_name(nq_utf8));
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
}
|
2014-07-16 22:09:00 +02:00
|
|
|
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
if (r == 0 && k == 0) /* No actual cname happened? */
|
|
|
|
return -ELOOP;
|
|
|
|
|
2016-02-04 00:14:25 +01:00
|
|
|
if (q->answer_protocol == DNS_PROTOCOL_DNS) {
|
|
|
|
/* Don't permit CNAME redirects from unicast DNS to LLMNR or MulticastDNS, so that global resources
|
|
|
|
* cannot invade the local namespace. The opposite way we permit: local names may redirect to global
|
|
|
|
* ones. */
|
|
|
|
|
|
|
|
q->flags &= ~(SD_RESOLVED_LLMNR|SD_RESOLVED_MDNS); /* mask away the local protocols */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Turn off searching for the new name */
|
|
|
|
q->flags |= SD_RESOLVED_NO_SEARCH;
|
|
|
|
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
dns_question_unref(q->question_idna);
|
2018-04-05 07:26:26 +02:00
|
|
|
q->question_idna = TAKE_PTR(nq_idna);
|
2016-01-17 21:53:16 +01:00
|
|
|
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
dns_question_unref(q->question_utf8);
|
2018-04-05 07:26:26 +02:00
|
|
|
q->question_utf8 = TAKE_PTR(nq_utf8);
|
2014-07-16 22:09:00 +02:00
|
|
|
|
2016-01-18 21:30:45 +01:00
|
|
|
dns_query_free_candidates(q);
|
|
|
|
dns_query_reset_answer(q);
|
2014-07-17 19:38:37 +02:00
|
|
|
|
2016-02-04 00:14:25 +01:00
|
|
|
q->state = DNS_TRANSACTION_NULL;
|
2016-01-18 21:31:16 +01: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;
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
DnsQuestion *question;
|
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
|
|
|
DnsResourceRecord *rr;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(q);
|
|
|
|
|
2016-01-05 17:56:45 +01:00
|
|
|
if (!IN_SET(q->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_NULL))
|
|
|
|
return DNS_QUERY_NOMATCH;
|
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
|
|
|
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
question = dns_query_question_for_protocol(q, q->answer_protocol);
|
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
|
|
|
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
DNS_ANSWER_FOREACH(rr, q->answer) {
|
|
|
|
r = dns_question_matches_rr(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)
|
2016-01-05 17:56:45 +01:00
|
|
|
return DNS_QUERY_MATCH; /* The answer matches directly, no need to follow cnames */
|
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
|
|
|
|
2016-01-18 22:33:23 +01:00
|
|
|
r = dns_question_matches_cname_or_dname(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)
|
2016-01-05 17:56:45 +01:00
|
|
|
return DNS_QUERY_NOMATCH; /* No match and no cname to follow */
|
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 (q->flags & SD_RESOLVED_NO_CNAME)
|
|
|
|
return -ELOOP;
|
|
|
|
|
2017-02-08 19:22:49 +01:00
|
|
|
if (!q->answer_authenticated)
|
|
|
|
q->previous_redirect_unauthenticated = true;
|
|
|
|
|
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
|
|
|
/* 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 */
|
2016-01-05 17:56:45 +01:00
|
|
|
r = dns_query_process_cname(q);
|
|
|
|
if (r != DNS_QUERY_NOMATCH)
|
|
|
|
return r;
|
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
|
|
|
|
|
|
|
/* OK, it cannot, let's begin with the new query */
|
|
|
|
r = dns_query_go(q);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2016-01-05 17:56:45 +01:00
|
|
|
return DNS_QUERY_RESTARTED; /* We restarted the query for a new cname */
|
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
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
resolved: rework IDNA logic
Move IDNA logic out of the normal domain name processing, and into the bus frontend calls. Previously whenever
comparing two domain names we'd implicitly do IDNA conversion so that "pöttering.de" and "xn--pttering-n4a.de" would be
considered equal. This is problematic not only for DNSSEC, but actually also against he IDNA specs.
Moreover it creates problems when encoding DNS-SD services in classic DNS. There, the specification suggests using
UTF8 encoding for the actual service name, but apply IDNA encoding to the domain suffix.
With this change IDNA conversion is done only:
- When the user passes a non-ASCII hostname when resolving a host name using ResolveHostname()
- When the user passes a non-ASCII domain suffix when resolving a service using ResolveService()
No IDNA encoding is done anymore:
- When the user does raw ResolveRecord() RR resolving
- On the service part of a DNS-SD service name
Previously, IDNA encoding was done when serializing names into packets, at a point where information whether something
is a label that needs IDNA encoding or not was not available, but at a point whether it was known whether to generate a
classic DNS packet (where IDNA applies), or an mDNS/LLMNR packet (where IDNA does not apply, and UTF8 is used instead
for all host names). With this change each DnsQuery object will now maintain two copies of the DnsQuestion to ask: one
encoded in IDNA for use with classic DNS, and one encoded in UTF8 for use with LLMNR and MulticastDNS.
2016-01-18 20:31:39 +01:00
|
|
|
|
|
|
|
DnsQuestion* dns_query_question_for_protocol(DnsQuery *q, DnsProtocol protocol) {
|
|
|
|
assert(q);
|
|
|
|
|
|
|
|
switch (protocol) {
|
|
|
|
|
|
|
|
case DNS_PROTOCOL_DNS:
|
|
|
|
return q->question_idna;
|
|
|
|
|
|
|
|
case DNS_PROTOCOL_MDNS:
|
|
|
|
case DNS_PROTOCOL_LLMNR:
|
|
|
|
return q->question_utf8;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *dns_query_string(DnsQuery *q) {
|
|
|
|
const char *name;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
/* Returns a somewhat useful human-readable lookup key string for this query */
|
|
|
|
|
|
|
|
if (q->request_address_string)
|
|
|
|
return q->request_address_string;
|
|
|
|
|
|
|
|
if (q->request_address_valid) {
|
|
|
|
r = in_addr_to_string(q->request_family, &q->request_address, &q->request_address_string);
|
|
|
|
if (r >= 0)
|
|
|
|
return q->request_address_string;
|
|
|
|
}
|
|
|
|
|
|
|
|
name = dns_question_first_name(q->question_utf8);
|
|
|
|
if (name)
|
|
|
|
return name;
|
|
|
|
|
|
|
|
return dns_question_first_name(q->question_idna);
|
|
|
|
}
|
2017-02-08 19:22:49 +01:00
|
|
|
|
|
|
|
bool dns_query_fully_authenticated(DnsQuery *q) {
|
|
|
|
assert(q);
|
|
|
|
|
|
|
|
return q->answer_authenticated && !q->previous_redirect_unauthenticated;
|
|
|
|
}
|