diff options
author | Garming Sam <garming@catalyst.net.nz> | 2016-02-17 11:30:21 +1300 |
---|---|---|
committer | Garming Sam <garming@samba.org> | 2016-05-03 08:10:09 +0200 |
commit | 5caebde11d1a25581e5f8d7c7f7deadfeae7759e (patch) | |
tree | 6f872bfed07db21e49b16b8f0a5eb1443484c71b | |
parent | 870b74d73eb6812d2002e4d88a2553d6edd545c4 (diff) | |
download | samba-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.xml | 5 | ||||
-rw-r--r-- | source4/dns_server/dns_query.c | 100 | ||||
-rw-r--r-- | source4/dns_server/dns_server.c | 6 |
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; } |