summaryrefslogtreecommitdiff
path: root/src/resolve/resolved-dns-query.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/resolve/resolved-dns-query.c')
-rw-r--r--src/resolve/resolved-dns-query.c94
1 files changed, 90 insertions, 4 deletions
diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c
index f7cb84e2a6..c1cd650651 100644
--- a/src/resolve/resolved-dns-query.c
+++ b/src/resolve/resolved-dns-query.c
@@ -30,6 +30,7 @@
#define CNAME_MAX 8
#define QUERIES_MAX 2048
+#define AUXILIARY_QUERIES_MAX 64
static void dns_query_stop(DnsQuery *q) {
DnsTransaction *t;
@@ -48,6 +49,15 @@ DnsQuery *dns_query_free(DnsQuery *q) {
if (!q)
return NULL;
+ 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);
+ }
+
dns_query_stop(q);
set_free(q->transactions);
@@ -111,6 +121,29 @@ int dns_query_new(Manager *m, DnsQuery **ret, DnsQuestion *question, int ifindex
return 0;
}
+int dns_query_make_auxiliary(DnsQuery *q, DnsQuery *auxiliary_for) {
+ assert(q);
+ assert(auxiliary_for);
+
+ /* Ensure that that the query is not auxiliary yet, and
+ * nothing else is auxiliary to it either */
+ assert(!q->auxiliary_for);
+ assert(!q->auxiliary_queries);
+
+ /* Ensure that the unit we shall be made auxiliary for isn't
+ * auxiliary itself */
+ assert(!auxiliary_for->auxiliary_for);
+
+ if (auxiliary_for->n_auxiliary_queries >= AUXILIARY_QUERIES_MAX)
+ return -EAGAIN;
+
+ LIST_PREPEND(auxiliary_queries, auxiliary_for->auxiliary_queries, q);
+ q->auxiliary_for = auxiliary_for;
+
+ auxiliary_for->n_auxiliary_queries++;
+ return 0;
+}
+
static void dns_query_complete(DnsQuery *q, DnsTransactionState state) {
assert(q);
assert(!IN_SET(state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING));
@@ -622,7 +655,7 @@ int dns_query_go(DnsQuery *q) {
assert(q->question);
assert(q->question->n_keys > 0);
- name = DNS_RESOURCE_KEY_NAME(q->question->keys[0]);
+ name = dns_question_name(q->question);
LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
DnsScopeMatch match;
@@ -831,12 +864,13 @@ void dns_query_ready(DnsQuery *q) {
dns_query_complete(q, state);
}
-int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) {
+static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) {
_cleanup_(dns_question_unrefp) DnsQuestion *nq = NULL;
int r;
assert(q);
+ q->n_cname_redirects ++;
if (q->n_cname_redirects > CNAME_MAX)
return -ELOOP;
@@ -848,14 +882,66 @@ int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) {
q->question = nq;
nq = NULL;
- q->n_cname_redirects++;
-
dns_query_stop(q);
q->state = DNS_TRANSACTION_NULL;
return 0;
}
+int dns_query_process_cname(DnsQuery *q) {
+ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL;
+ DnsResourceRecord *rr;
+ int r;
+
+ assert(q);
+
+ if (q->state != DNS_TRANSACTION_SUCCESS)
+ return 0;
+
+ DNS_ANSWER_FOREACH(rr, q->answer) {
+
+ r = dns_question_matches_rr(q->question, rr);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ return 0; /* The answer matches directly, no need to follow cnames */
+
+ r = dns_question_matches_cname(q->question, rr);
+ if (r < 0)
+ return r;
+ if (r > 0 && !cname)
+ cname = dns_resource_record_ref(rr);
+ }
+
+ if (!cname)
+ return 0; /* No cname to follow */
+
+ if (q->flags & SD_RESOLVED_NO_CNAME)
+ return -ELOOP;
+
+ /* OK, let's actually follow the CNAME */
+ r = dns_query_cname_redirect(q, cname);
+ if (r < 0)
+ return r;
+
+ /* Let's see if the answer can already answer the new
+ * redirected question */
+ DNS_ANSWER_FOREACH(rr, q->answer) {
+ r = dns_question_matches_rr(q->question, rr);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ return 0; /* It can answer it, yay! */
+ }
+
+ /* OK, it cannot, let's begin with the new query */
+ r = dns_query_go(q);
+ if (r < 0)
+ return r;
+
+ return 1; /* We return > 0, if we restarted the query for a new cname */
+}
+
static int on_bus_track(sd_bus_track *t, void *userdata) {
DnsQuery *q = userdata;