summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarming Sam <garming@catalyst.net.nz>2016-02-17 11:30:21 +1300
committerGarming Sam <garming@samba.org>2016-05-03 08:10:09 +0200
commit5caebde11d1a25581e5f8d7c7f7deadfeae7759e (patch)
tree6f872bfed07db21e49b16b8f0a5eb1443484c71b
parent870b74d73eb6812d2002e4d88a2553d6edd545c4 (diff)
downloadsamba-5caebde11d1a25581e5f8d7c7f7deadfeae7759e.tar.gz
dns: modify dns forwarder param to be multi-valued
This allows a secondary DNS forwarder for a trivial failover. Requests which fail/timeout at the primary DNS forwarder will be restarted entirely with the next forwarder in the list. Signed-off-by: Garming Sam <garming@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
-rw-r--r--docs-xml/smbdotconf/domain/dnsforwarder.xml5
-rw-r--r--source4/dns_server/dns_query.c100
-rw-r--r--source4/dns_server/dns_server.c6
3 files changed, 94 insertions, 17 deletions
diff --git a/docs-xml/smbdotconf/domain/dnsforwarder.xml b/docs-xml/smbdotconf/domain/dnsforwarder.xml
index 4147ef8524f..d3c8b768495 100644
--- a/docs-xml/smbdotconf/domain/dnsforwarder.xml
+++ b/docs-xml/smbdotconf/domain/dnsforwarder.xml
@@ -1,10 +1,9 @@
<samba:parameter name="dns forwarder"
context="G"
- type="string"
- constant="1"
+ type="cmdlist"
xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
<description>
- <para>This option specifies the DNS server that DNS requests will be
+ <para>This option specifies the list of DNS servers that DNS requests will be
forwarded to if they can not be handled by Samba itself.
</para>
diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c
index c251430a5ef..146054bf4de 100644
--- a/source4/dns_server/dns_query.c
+++ b/source4/dns_server/dns_query.c
@@ -31,6 +31,7 @@
#include "dsdb/common/util.h"
#include "dns_server/dns_server.h"
#include "libcli/dns/libdns.h"
+#include "lib/util/dlinklist.h"
#include "lib/util/util_net.h"
#include "lib/util/tevent_werror.h"
#include "auth/auth.h"
@@ -40,6 +41,11 @@
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_DNS
+struct forwarder_string {
+ const char *forwarder;
+ struct forwarder_string *prev, *next;
+};
+
static WERROR add_response_rr(const char *name,
const struct dnsp_DnssrvRpcRecord *rec,
struct dns_res_rec **answers)
@@ -912,12 +918,17 @@ static WERROR handle_tkey(struct dns_server *dns,
}
struct dns_server_process_query_state {
+ struct tevent_context *ev;
+ struct dns_server *dns;
+ struct dns_name_question *question;
+
struct dns_res_rec *answers;
uint16_t ancount;
struct dns_res_rec *nsrecs;
uint16_t nscount;
struct dns_res_rec *additional;
uint16_t arcount;
+ struct forwarder_string *forwarders;
};
static void dns_server_process_query_got_auth(struct tevent_req *subreq);
@@ -930,6 +941,8 @@ struct tevent_req *dns_server_process_query_send(
{
struct tevent_req *req, *subreq;
struct dns_server_process_query_state *state;
+ const char **forwarders = NULL;
+ unsigned int i;
req = tevent_req_create(mem_ctx, &state,
struct dns_server_process_query_state);
@@ -959,6 +972,18 @@ struct tevent_req *dns_server_process_query_send(
return tevent_req_post(req, ev);
}
+ state->dns = dns;
+ state->ev = ev;
+ state->question = &in->questions[0];
+
+ forwarders = lpcfg_dns_forwarder(dns->task->lp_ctx);
+ for (i = 0; forwarders != NULL && forwarders[i] != NULL; i++) {
+ struct forwarder_string *f = talloc_zero(state,
+ struct forwarder_string);
+ f->forwarder = forwarders[i];
+ DLIST_ADD_END(state->forwarders, f);
+ }
+
if (dns_authorative_for_zone(dns, in->questions[0].name)) {
req_state->flags |= DNS_FLAG_AUTHORITATIVE;
@@ -978,7 +1003,7 @@ struct tevent_req *dns_server_process_query_send(
}
subreq = handle_authoritative_send(
- state, ev, dns, lpcfg_dns_forwarder(dns->task->lp_ctx),
+ state, ev, dns, (forwarders == NULL ? NULL : forwarders[0]),
&in->questions[0], &state->answers, &state->nsrecs);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
@@ -993,9 +1018,9 @@ struct tevent_req *dns_server_process_query_send(
DEBUG(2, ("Not authoritative for '%s', forwarding\n",
in->questions[0].name));
- subreq = ask_forwarder_send(
- state, ev, dns, lpcfg_dns_forwarder(dns->task->lp_ctx),
- &in->questions[0]);
+ subreq = ask_forwarder_send(state, ev, dns,
+ (forwarders == NULL ? NULL : forwarders[0]),
+ &in->questions[0]);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
@@ -1014,16 +1039,42 @@ static void dns_server_process_query_got_response(struct tevent_req *subreq)
subreq, struct tevent_req);
struct dns_server_process_query_state *state = tevent_req_data(
req, struct dns_server_process_query_state);
- WERROR err;
+ WERROR werr;
- err = ask_forwarder_recv(subreq, state,
- &state->answers, &state->ancount,
- &state->nsrecs, &state->nscount,
- &state->additional, &state->arcount);
+ werr = ask_forwarder_recv(subreq, state,
+ &state->answers, &state->ancount,
+ &state->nsrecs, &state->nscount,
+ &state->additional, &state->arcount);
TALLOC_FREE(subreq);
- if (tevent_req_werror(req, err)) {
+
+ /* If you get an error, attempt a different forwarder */
+ if (!W_ERROR_IS_OK(werr)) {
+ if (state->forwarders != NULL) {
+ DLIST_REMOVE(state->forwarders, state->forwarders);
+ }
+
+ /* If you have run out of forwarders, simply finish */
+ if (state->forwarders == NULL) {
+ tevent_req_werror(req, werr);
+ return;
+ }
+
+ DEBUG(5, ("DNS query returned %s, trying another forwarder.\n",
+ win_errstr(werr)));
+ subreq = ask_forwarder_send(state, state->ev, state->dns,
+ state->forwarders->forwarder,
+ state->question);
+
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+
+ tevent_req_set_callback(subreq,
+ dns_server_process_query_got_response,
+ req);
return;
}
+
tevent_req_done(req);
}
@@ -1037,9 +1088,36 @@ static void dns_server_process_query_got_auth(struct tevent_req *subreq)
werr = handle_authoritative_recv(subreq);
TALLOC_FREE(subreq);
- if (tevent_req_werror(req, werr)) {
+
+ /* If you get an error, attempt a different forwarder */
+ if (!W_ERROR_IS_OK(werr)) {
+ if (state->forwarders != NULL) {
+ DLIST_REMOVE(state->forwarders, state->forwarders);
+ }
+
+ /* If you have run out of forwarders, simply finish */
+ if (state->forwarders == NULL) {
+ tevent_req_werror(req, werr);
+ return;
+ }
+
+ DEBUG(5, ("Error: %s, trying a different forwarder.\n",
+ win_errstr(werr)));
+ subreq = handle_authoritative_send(state, state->ev, state->dns,
+ state->forwarders->forwarder,
+ state->question, &state->answers,
+ &state->nsrecs);
+
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+
+ tevent_req_set_callback(subreq,
+ dns_server_process_query_got_auth,
+ req);
return;
}
+
state->ancount = talloc_array_length(state->answers);
state->nscount = talloc_array_length(state->nsrecs);
state->arcount = talloc_array_length(state->additional);
diff --git a/source4/dns_server/dns_server.c b/source4/dns_server/dns_server.c
index a2dc15195bf..ae7ec7aad6f 100644
--- a/source4/dns_server/dns_server.c
+++ b/source4/dns_server/dns_server.c
@@ -123,7 +123,7 @@ static struct tevent_req *dns_process_send(TALLOC_CTX *mem_ctx,
struct dns_process_state *state;
enum ndr_err_code ndr_err;
WERROR ret;
- const char *forwarder = lpcfg_dns_forwarder(dns->task->lp_ctx);
+ const char **forwarder = lpcfg_dns_forwarder(dns->task->lp_ctx);
req = tevent_req_create(mem_ctx, &state, struct dns_process_state);
if (req == NULL) {
return NULL;
@@ -169,8 +169,8 @@ static struct tevent_req *dns_process_send(TALLOC_CTX *mem_ctx,
state->state.flags = state->in_packet.operation;
state->state.flags |= DNS_FLAG_REPLY;
-
- if (forwarder && *forwarder) {
+
+ if (forwarder && *forwarder && **forwarder) {
state->state.flags |= DNS_FLAG_RECURSION_AVAIL;
}