2010-10-01 23:59:22 +04:00
/*
Unix SMB / CIFS implementation .
DNS server handler for queries
Copyright ( C ) 2010 Kai Blin < kai @ samba . org >
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2012-03-27 17:00:01 +04:00
# include "smbd/service_task.h"
2010-10-12 01:39:44 +04:00
# include "libcli/util/werror.h"
2010-10-01 23:59:22 +04:00
# include "librpc/ndr/libndr.h"
# include "librpc/gen_ndr/ndr_dns.h"
# include "librpc/gen_ndr/ndr_dnsp.h"
# include <ldb.h>
2012-03-27 17:00:01 +04:00
# include "param/param.h"
2010-10-01 23:59:22 +04:00
# include "dsdb/samdb/samdb.h"
# include "dsdb/common/util.h"
# include "dns_server/dns_server.h"
2012-03-27 10:42:22 +04:00
# include "libcli/dns/libdns.h"
2016-02-17 01:30:21 +03:00
# include "lib/util/dlinklist.h"
2012-03-27 17:00:01 +04:00
# include "lib/util/util_net.h"
2012-05-24 15:49:41 +04:00
# include "lib/util/tevent_werror.h"
2012-08-30 11:04:07 +04:00
# include "auth/auth.h"
# include "auth/credentials/credentials.h"
# include "auth/gensec/gensec.h"
2010-10-01 23:59:22 +04:00
2013-01-14 04:14:29 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_DNS
2018-10-23 07:25:51 +03:00
# define MAX_Q_RECURSION_DEPTH 20
2013-01-14 04:14:29 +04:00
2016-02-17 01:30:21 +03:00
struct forwarder_string {
const char * forwarder ;
struct forwarder_string * prev , * next ;
} ;
2015-08-08 07:49:16 +03:00
static WERROR add_response_rr ( const char * name ,
2015-08-07 09:27:19 +03:00
const struct dnsp_DnssrvRpcRecord * rec ,
2015-08-08 07:54:11 +03:00
struct dns_res_rec * * answers )
2011-09-28 04:36:42 +04:00
{
struct dns_res_rec * ans = * answers ;
2015-08-08 07:54:11 +03:00
uint16_t ai = talloc_array_length ( ans ) ;
2015-08-07 12:36:47 +03:00
enum ndr_err_code ndr_err ;
2011-09-28 04:36:42 +04:00
2015-08-07 09:27:19 +03:00
if ( ai = = UINT16_MAX ) {
return WERR_BUFFER_OVERFLOW ;
}
2015-08-08 07:49:16 +03:00
/*
* " ans " is always non - NULL and thus its own talloc context
*/
ans = talloc_realloc ( ans , ans , struct dns_res_rec , ai + 1 ) ;
2015-08-07 09:27:19 +03:00
if ( ans = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2015-08-07 09:27:19 +03:00
}
2011-09-28 04:36:42 +04:00
ZERO_STRUCT ( ans [ ai ] ) ;
switch ( rec - > wType ) {
case DNS_QTYPE_CNAME :
ans [ ai ] . rdata . cname_record = talloc_strdup ( ans , rec - > data . cname ) ;
2012-05-30 02:30:29 +04:00
W_ERROR_HAVE_NO_MEMORY ( ans [ ai ] . rdata . cname_record ) ;
2011-09-28 04:36:42 +04:00
break ;
case DNS_QTYPE_A :
ans [ ai ] . rdata . ipv4_record = talloc_strdup ( ans , rec - > data . ipv4 ) ;
2012-05-30 02:30:29 +04:00
W_ERROR_HAVE_NO_MEMORY ( ans [ ai ] . rdata . ipv4_record ) ;
2011-09-28 04:36:42 +04:00
break ;
case DNS_QTYPE_AAAA :
2012-05-30 02:23:14 +04:00
ans [ ai ] . rdata . ipv6_record = talloc_strdup ( ans , rec - > data . ipv6 ) ;
W_ERROR_HAVE_NO_MEMORY ( ans [ ai ] . rdata . ipv6_record ) ;
2011-09-28 04:36:42 +04:00
break ;
case DNS_TYPE_NS :
2012-05-30 02:23:33 +04:00
ans [ ai ] . rdata . ns_record = talloc_strdup ( ans , rec - > data . ns ) ;
W_ERROR_HAVE_NO_MEMORY ( ans [ ai ] . rdata . ns_record ) ;
2011-09-28 04:36:42 +04:00
break ;
case DNS_QTYPE_SRV :
ans [ ai ] . rdata . srv_record . priority = rec - > data . srv . wPriority ;
ans [ ai ] . rdata . srv_record . weight = rec - > data . srv . wWeight ;
ans [ ai ] . rdata . srv_record . port = rec - > data . srv . wPort ;
2012-05-29 17:20:21 +04:00
ans [ ai ] . rdata . srv_record . target = talloc_strdup (
ans , rec - > data . srv . nameTarget ) ;
2012-05-30 02:30:29 +04:00
W_ERROR_HAVE_NO_MEMORY ( ans [ ai ] . rdata . srv_record . target ) ;
2011-09-28 04:36:42 +04:00
break ;
case DNS_QTYPE_SOA :
2012-05-29 17:20:21 +04:00
ans [ ai ] . rdata . soa_record . mname = talloc_strdup (
ans , rec - > data . soa . mname ) ;
2012-05-30 02:30:29 +04:00
W_ERROR_HAVE_NO_MEMORY ( ans [ ai ] . rdata . soa_record . mname ) ;
2012-05-29 17:20:21 +04:00
ans [ ai ] . rdata . soa_record . rname = talloc_strdup (
ans , rec - > data . soa . rname ) ;
2012-05-30 02:30:29 +04:00
W_ERROR_HAVE_NO_MEMORY ( ans [ ai ] . rdata . soa_record . rname ) ;
2011-09-28 04:36:42 +04:00
ans [ ai ] . rdata . soa_record . serial = rec - > data . soa . serial ;
ans [ ai ] . rdata . soa_record . refresh = rec - > data . soa . refresh ;
ans [ ai ] . rdata . soa_record . retry = rec - > data . soa . retry ;
ans [ ai ] . rdata . soa_record . expire = rec - > data . soa . expire ;
ans [ ai ] . rdata . soa_record . minimum = rec - > data . soa . minimum ;
break ;
2012-03-09 13:43:27 +04:00
case DNS_QTYPE_PTR :
ans [ ai ] . rdata . ptr_record = talloc_strdup ( ans , rec - > data . ptr ) ;
2015-08-01 18:53:56 +03:00
W_ERROR_HAVE_NO_MEMORY ( ans [ ai ] . rdata . ptr_record ) ;
2012-03-09 13:43:27 +04:00
break ;
2012-12-09 23:50:05 +04:00
case DNS_QTYPE_MX :
ans [ ai ] . rdata . mx_record . preference = rec - > data . mx . wPriority ;
ans [ ai ] . rdata . mx_record . exchange = talloc_strdup (
ans , rec - > data . mx . nameTarget ) ;
if ( ans [ ai ] . rdata . mx_record . exchange = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-12-09 23:50:05 +04:00
}
break ;
2012-03-11 02:47:29 +04:00
case DNS_QTYPE_TXT :
2015-08-07 12:36:47 +03:00
ndr_err = ndr_dnsp_string_list_copy ( ans ,
& rec - > data . txt ,
& ans [ ai ] . rdata . txt_record . txt ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-03-11 02:47:29 +04:00
}
break ;
2011-09-28 04:36:42 +04:00
default :
2012-03-11 02:47:29 +04:00
DEBUG ( 0 , ( " Got unhandled type %u query. \n " , rec - > wType ) ) ;
2011-09-28 04:36:42 +04:00
return DNS_ERR ( NOT_IMPLEMENTED ) ;
}
2014-10-29 15:36:58 +03:00
ans [ ai ] . name = talloc_strdup ( ans , name ) ;
2012-05-30 02:30:29 +04:00
W_ERROR_HAVE_NO_MEMORY ( ans [ ai ] . name ) ;
2017-11-19 19:49:46 +03:00
ans [ ai ] . rr_type = ( enum dns_qtype ) rec - > wType ;
2011-09-28 04:36:42 +04:00
ans [ ai ] . rr_class = DNS_QCLASS_IN ;
ans [ ai ] . ttl = rec - > dwTtlSeconds ;
ans [ ai ] . length = UINT16_MAX ;
* answers = ans ;
return WERR_OK ;
}
2015-08-08 15:36:43 +03:00
static WERROR add_dns_res_rec ( struct dns_res_rec * * pdst ,
const struct dns_res_rec * src )
{
struct dns_res_rec * dst = * pdst ;
uint16_t di = talloc_array_length ( dst ) ;
2015-08-07 12:36:47 +03:00
enum ndr_err_code ndr_err ;
2015-08-08 15:36:43 +03:00
if ( di = = UINT16_MAX ) {
return WERR_BUFFER_OVERFLOW ;
}
dst = talloc_realloc ( dst , dst , struct dns_res_rec , di + 1 ) ;
if ( dst = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2015-08-08 15:36:43 +03:00
}
ZERO_STRUCT ( dst [ di ] ) ;
dst [ di ] = ( struct dns_res_rec ) {
. name = talloc_strdup ( dst , src - > name ) ,
. rr_type = src - > rr_type ,
. rr_class = src - > rr_class ,
. ttl = src - > ttl ,
. length = src - > length
} ;
if ( dst [ di ] . name = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2015-08-08 15:36:43 +03:00
}
switch ( src - > rr_type ) {
case DNS_QTYPE_CNAME :
dst [ di ] . rdata . cname_record = talloc_strdup (
dst , src - > rdata . cname_record ) ;
if ( dst [ di ] . rdata . cname_record = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2015-08-08 15:36:43 +03:00
}
break ;
case DNS_QTYPE_A :
dst [ di ] . rdata . ipv4_record = talloc_strdup (
dst , src - > rdata . ipv4_record ) ;
if ( dst [ di ] . rdata . ipv4_record = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2015-08-08 15:36:43 +03:00
}
break ;
case DNS_QTYPE_AAAA :
dst [ di ] . rdata . ipv6_record = talloc_strdup (
dst , src - > rdata . ipv6_record ) ;
if ( dst [ di ] . rdata . ipv6_record = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2015-08-08 15:36:43 +03:00
}
break ;
case DNS_TYPE_NS :
dst [ di ] . rdata . ns_record = talloc_strdup (
dst , src - > rdata . ns_record ) ;
if ( dst [ di ] . rdata . ns_record = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2015-08-08 15:36:43 +03:00
}
break ;
case DNS_QTYPE_SRV :
dst [ di ] . rdata . srv_record = ( struct dns_srv_record ) {
. priority = src - > rdata . srv_record . priority ,
. weight = src - > rdata . srv_record . weight ,
. port = src - > rdata . srv_record . port ,
. target = talloc_strdup (
dst , src - > rdata . srv_record . target )
} ;
if ( dst [ di ] . rdata . srv_record . target = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2015-08-08 15:36:43 +03:00
}
break ;
case DNS_QTYPE_SOA :
dst [ di ] . rdata . soa_record = ( struct dns_soa_record ) {
. mname = talloc_strdup (
dst , src - > rdata . soa_record . mname ) ,
. rname = talloc_strdup (
dst , src - > rdata . soa_record . rname ) ,
. serial = src - > rdata . soa_record . serial ,
. refresh = src - > rdata . soa_record . refresh ,
. retry = src - > rdata . soa_record . retry ,
. expire = src - > rdata . soa_record . expire ,
. minimum = src - > rdata . soa_record . minimum
} ;
if ( ( dst [ di ] . rdata . soa_record . mname = = NULL ) | |
( dst [ di ] . rdata . soa_record . rname = = NULL ) ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2015-08-08 15:36:43 +03:00
}
break ;
case DNS_QTYPE_PTR :
dst [ di ] . rdata . ptr_record = talloc_strdup (
dst , src - > rdata . ptr_record ) ;
if ( dst [ di ] . rdata . ptr_record = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2015-08-08 15:36:43 +03:00
}
break ;
case DNS_QTYPE_MX :
dst [ di ] . rdata . mx_record = ( struct dns_mx_record ) {
. preference = src - > rdata . mx_record . preference ,
. exchange = talloc_strdup (
src , src - > rdata . mx_record . exchange )
} ;
if ( dst [ di ] . rdata . mx_record . exchange = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2015-08-08 15:36:43 +03:00
}
break ;
case DNS_QTYPE_TXT :
2015-08-07 12:36:47 +03:00
ndr_err = ndr_dnsp_string_list_copy ( dst ,
& src - > rdata . txt_record . txt ,
& dst [ di ] . rdata . txt_record . txt ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2015-08-08 15:36:43 +03:00
}
break ;
default :
DBG_WARNING ( " Got unhandled type %u query. \n " , src - > rr_type ) ;
return DNS_ERR ( NOT_IMPLEMENTED ) ;
}
* pdst = dst ;
return WERR_OK ;
}
2012-05-24 15:49:41 +04:00
struct ask_forwarder_state {
2017-12-29 13:11:59 +03:00
struct dns_name_packet * reply ;
2012-05-24 15:49:41 +04:00
} ;
static void ask_forwarder_done ( struct tevent_req * subreq ) ;
static struct tevent_req * ask_forwarder_send (
TALLOC_CTX * mem_ctx , struct tevent_context * ev ,
const char * forwarder , struct dns_name_question * question )
2012-03-27 10:42:22 +04:00
{
2012-05-24 15:49:41 +04:00
struct tevent_req * req , * subreq ;
struct ask_forwarder_state * state ;
req = tevent_req_create ( mem_ctx , & state , struct ask_forwarder_state ) ;
if ( req = = NULL ) {
return NULL ;
}
2013-05-25 15:21:33 +04:00
2017-12-29 13:11:59 +03:00
subreq = dns_cli_request_send ( state , ev , forwarder ,
question - > name , question - > question_class ,
question - > question_type ) ;
2012-05-24 15:49:41 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
2012-03-27 10:42:22 +04:00
}
2012-05-24 15:49:41 +04:00
tevent_req_set_callback ( subreq , ask_forwarder_done , req ) ;
return req ;
}
2012-03-27 10:42:22 +04:00
2012-05-24 15:49:41 +04:00
static void ask_forwarder_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct ask_forwarder_state * state = tevent_req_data (
req , struct ask_forwarder_state ) ;
2015-12-06 13:31:23 +03:00
int ret ;
2012-03-27 10:42:22 +04:00
2017-12-29 13:11:59 +03:00
ret = dns_cli_request_recv ( subreq , state , & state - > reply ) ;
2012-05-24 15:49:41 +04:00
TALLOC_FREE ( subreq ) ;
2015-12-06 13:31:23 +03:00
if ( ret ! = 0 ) {
tevent_req_werror ( req , unix_to_werror ( ret ) ) ;
2012-05-24 15:49:41 +04:00
return ;
}
2012-03-27 10:42:22 +04:00
2012-05-24 15:49:41 +04:00
tevent_req_done ( req ) ;
}
2012-03-27 10:42:22 +04:00
2012-05-24 15:49:41 +04:00
static WERROR ask_forwarder_recv (
struct tevent_req * req , TALLOC_CTX * mem_ctx ,
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 ask_forwarder_state * state = tevent_req_data (
req , struct ask_forwarder_state ) ;
2017-12-29 13:11:59 +03:00
struct dns_name_packet * in_packet = state - > reply ;
2012-05-24 15:49:41 +04:00
WERROR err ;
if ( tevent_req_is_werror ( req , & err ) ) {
return err ;
2012-03-27 10:42:22 +04:00
}
* ancount = in_packet - > ancount ;
* answers = talloc_move ( mem_ctx , & in_packet - > answers ) ;
* nscount = in_packet - > nscount ;
* nsrecs = talloc_move ( mem_ctx , & in_packet - > nsrecs ) ;
* arcount = in_packet - > arcount ;
* additional = talloc_move ( mem_ctx , & in_packet - > additional ) ;
2012-05-24 15:49:41 +04:00
return WERR_OK ;
}
2014-10-29 15:41:53 +03:00
static WERROR add_zone_authority_record ( struct dns_server * dns ,
TALLOC_CTX * mem_ctx ,
const struct dns_name_question * question ,
2015-08-08 07:54:11 +03:00
struct dns_res_rec * * nsrecs )
2014-10-29 15:41:53 +03:00
{
const char * zone = NULL ;
struct dnsp_DnssrvRpcRecord * recs ;
struct dns_res_rec * ns = * nsrecs ;
2015-08-08 07:54:11 +03:00
uint16_t rec_count ;
2014-10-29 15:41:53 +03:00
struct ldb_dn * dn = NULL ;
unsigned int ri ;
WERROR werror ;
zone = dns_get_authoritative_zone ( dns , question - > name ) ;
DEBUG ( 10 , ( " Creating zone authority record for '%s' \n " , zone ) ) ;
werror = dns_name2dn ( dns , mem_ctx , zone , & dn ) ;
if ( ! W_ERROR_IS_OK ( werror ) ) {
return werror ;
}
werror = dns_lookup_records ( dns , mem_ctx , dn , & recs , & rec_count ) ;
if ( ! W_ERROR_IS_OK ( werror ) ) {
return werror ;
}
for ( ri = 0 ; ri < rec_count ; ri + + ) {
if ( recs [ ri ] . wType = = DNS_TYPE_SOA ) {
2015-08-08 07:54:11 +03:00
werror = add_response_rr ( zone , & recs [ ri ] , & ns ) ;
2014-10-29 15:41:53 +03:00
if ( ! W_ERROR_IS_OK ( werror ) ) {
return werror ;
}
}
}
* nsrecs = ns ;
return WERR_OK ;
}
2015-08-11 08:39:31 +03:00
static struct tevent_req * handle_authoritative_send (
TALLOC_CTX * mem_ctx , struct tevent_context * ev ,
struct dns_server * dns , const char * forwarder ,
struct dns_name_question * question ,
2018-11-28 17:21:56 +03:00
struct dns_res_rec * * answers , struct dns_res_rec * * nsrecs ,
size_t cname_depth ) ;
2015-08-11 08:39:31 +03:00
static WERROR handle_authoritative_recv ( struct tevent_req * req ) ;
struct handle_dnsrpcrec_state {
struct dns_res_rec * * answers ;
struct dns_res_rec * * nsrecs ;
} ;
static void handle_dnsrpcrec_gotauth ( struct tevent_req * subreq ) ;
static void handle_dnsrpcrec_gotforwarded ( struct tevent_req * subreq ) ;
static struct tevent_req * handle_dnsrpcrec_send (
TALLOC_CTX * mem_ctx , struct tevent_context * ev ,
struct dns_server * dns , const char * forwarder ,
const struct dns_name_question * question ,
struct dnsp_DnssrvRpcRecord * rec ,
2018-11-28 17:21:56 +03:00
struct dns_res_rec * * answers , struct dns_res_rec * * nsrecs ,
size_t cname_depth )
2015-08-11 08:39:31 +03:00
{
struct tevent_req * req , * subreq ;
struct handle_dnsrpcrec_state * state ;
struct dns_name_question * new_q ;
bool resolve_cname ;
WERROR werr ;
req = tevent_req_create ( mem_ctx , & state ,
struct handle_dnsrpcrec_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > answers = answers ;
state - > nsrecs = nsrecs ;
2018-11-28 17:21:56 +03:00
if ( cname_depth > = MAX_Q_RECURSION_DEPTH ) {
2018-10-23 07:25:51 +03:00
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
2015-08-11 08:39:31 +03:00
resolve_cname = ( ( rec - > wType = = DNS_TYPE_CNAME ) & &
( ( question - > question_type = = DNS_QTYPE_A ) | |
( question - > question_type = = DNS_QTYPE_AAAA ) ) ) ;
if ( ! resolve_cname ) {
if ( ( question - > question_type ! = DNS_QTYPE_ALL ) & &
( rec - > wType ! =
( enum dns_record_type ) question - > question_type ) ) {
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
werr = add_response_rr ( question - > name , rec , state - > answers ) ;
if ( tevent_req_werror ( req , werr ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
werr = add_response_rr ( question - > name , rec , state - > answers ) ;
if ( tevent_req_werror ( req , werr ) ) {
return tevent_req_post ( req , ev ) ;
}
new_q = talloc ( state , struct dns_name_question ) ;
if ( tevent_req_nomem ( new_q , req ) ) {
return tevent_req_post ( req , ev ) ;
}
* new_q = ( struct dns_name_question ) {
. question_type = question - > question_type ,
. question_class = question - > question_class ,
. name = rec - > data . cname
} ;
2016-05-31 01:48:15 +03:00
if ( dns_authoritative_for_zone ( dns , new_q - > name ) ) {
2015-08-11 08:39:31 +03:00
subreq = handle_authoritative_send (
state , ev , dns , forwarder , new_q ,
2018-11-28 17:21:56 +03:00
state - > answers , state - > nsrecs ,
cname_depth + 1 ) ;
2015-08-11 08:39:31 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , handle_dnsrpcrec_gotauth , req ) ;
return req ;
}
2017-12-31 12:59:40 +03:00
subreq = ask_forwarder_send ( state , ev , forwarder , new_q ) ;
2015-08-11 08:39:31 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , handle_dnsrpcrec_gotforwarded , req ) ;
return req ;
}
static void handle_dnsrpcrec_gotauth ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
WERROR werr ;
werr = handle_authoritative_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_werror ( req , werr ) ) {
return ;
}
tevent_req_done ( req ) ;
}
static void handle_dnsrpcrec_gotforwarded ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct handle_dnsrpcrec_state * state = tevent_req_data (
req , struct handle_dnsrpcrec_state ) ;
struct dns_res_rec * answers , * nsrecs , * additional ;
uint16_t ancount = 0 ;
uint16_t nscount = 0 ;
uint16_t arcount = 0 ;
uint16_t i ;
WERROR werr ;
werr = ask_forwarder_recv ( subreq , state , & answers , & ancount ,
& nsrecs , & nscount , & additional , & arcount ) ;
if ( tevent_req_werror ( req , werr ) ) {
return ;
}
for ( i = 0 ; i < ancount ; i + + ) {
werr = add_dns_res_rec ( state - > answers , & answers [ i ] ) ;
if ( tevent_req_werror ( req , werr ) ) {
return ;
}
}
for ( i = 0 ; i < nscount ; i + + ) {
werr = add_dns_res_rec ( state - > nsrecs , & nsrecs [ i ] ) ;
if ( tevent_req_werror ( req , werr ) ) {
return ;
}
}
tevent_req_done ( req ) ;
}
static WERROR handle_dnsrpcrec_recv ( struct tevent_req * req )
{
return tevent_req_simple_recv_werror ( req ) ;
}
struct handle_authoritative_state {
struct tevent_context * ev ;
struct dns_server * dns ;
struct dns_name_question * question ;
const char * forwarder ;
struct dnsp_DnssrvRpcRecord * recs ;
uint16_t rec_count ;
uint16_t recs_done ;
struct dns_res_rec * * answers ;
struct dns_res_rec * * nsrecs ;
2018-11-28 17:21:56 +03:00
size_t cname_depth ;
2015-08-11 08:39:31 +03:00
} ;
static void handle_authoritative_done ( struct tevent_req * subreq ) ;
static struct tevent_req * handle_authoritative_send (
TALLOC_CTX * mem_ctx , struct tevent_context * ev ,
struct dns_server * dns , const char * forwarder ,
struct dns_name_question * question ,
2018-11-28 17:21:56 +03:00
struct dns_res_rec * * answers , struct dns_res_rec * * nsrecs ,
size_t cname_depth )
2015-08-11 08:39:31 +03:00
{
struct tevent_req * req , * subreq ;
struct handle_authoritative_state * state ;
struct ldb_dn * dn = NULL ;
WERROR werr ;
req = tevent_req_create ( mem_ctx , & state ,
struct handle_authoritative_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > dns = dns ;
state - > question = question ;
state - > forwarder = forwarder ;
state - > answers = answers ;
state - > nsrecs = nsrecs ;
2018-11-28 17:21:56 +03:00
state - > cname_depth = cname_depth ;
2015-08-11 08:39:31 +03:00
werr = dns_name2dn ( dns , state , question - > name , & dn ) ;
if ( tevent_req_werror ( req , werr ) ) {
return tevent_req_post ( req , ev ) ;
}
2017-08-03 06:12:02 +03:00
werr = dns_lookup_records_wildcard ( dns , state , dn , & state - > recs ,
& state - > rec_count ) ;
2015-08-11 08:39:31 +03:00
TALLOC_FREE ( dn ) ;
if ( tevent_req_werror ( req , werr ) ) {
return tevent_req_post ( req , ev ) ;
}
if ( state - > rec_count = = 0 ) {
tevent_req_werror ( req , DNS_ERR ( NAME_ERROR ) ) ;
return tevent_req_post ( req , ev ) ;
}
subreq = handle_dnsrpcrec_send (
state , state - > ev , state - > dns , state - > forwarder ,
state - > question , & state - > recs [ state - > recs_done ] ,
2018-11-28 17:21:56 +03:00
state - > answers , state - > nsrecs ,
state - > cname_depth ) ;
2015-08-11 08:39:31 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , handle_authoritative_done , req ) ;
return req ;
}
static void handle_authoritative_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct handle_authoritative_state * state = tevent_req_data (
req , struct handle_authoritative_state ) ;
WERROR werr ;
werr = handle_dnsrpcrec_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_werror ( req , werr ) ) {
return ;
}
state - > recs_done + = 1 ;
if ( state - > recs_done = = state - > rec_count ) {
tevent_req_done ( req ) ;
return ;
}
subreq = handle_dnsrpcrec_send (
state , state - > ev , state - > dns , state - > forwarder ,
state - > question , & state - > recs [ state - > recs_done ] ,
2018-11-28 17:21:56 +03:00
state - > answers , state - > nsrecs ,
state - > cname_depth ) ;
2015-08-11 08:39:31 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , handle_authoritative_done , req ) ;
}
static WERROR handle_authoritative_recv ( struct tevent_req * req )
{
struct handle_authoritative_state * state = tevent_req_data (
req , struct handle_authoritative_state ) ;
WERROR werr ;
if ( tevent_req_is_werror ( req , & werr ) ) {
return werr ;
}
werr = add_zone_authority_record ( state - > dns , state , state - > question ,
state - > nsrecs ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
}
return WERR_OK ;
}
2012-08-31 15:41:19 +04:00
static NTSTATUS create_tkey ( struct dns_server * dns ,
const char * name ,
2012-09-05 10:27:28 +04:00
const char * algorithm ,
2017-03-01 04:19:50 +03:00
const struct tsocket_address * remote_address ,
const struct tsocket_address * local_address ,
2012-08-31 15:41:19 +04:00
struct dns_server_tkey * * tkey )
2012-08-30 11:04:07 +04:00
{
NTSTATUS status ;
2012-08-31 15:41:19 +04:00
struct dns_server_tkey_store * store = dns - > tkeys ;
struct dns_server_tkey * k = talloc_zero ( store , struct dns_server_tkey ) ;
2012-08-30 11:04:07 +04:00
if ( k = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2012-08-31 15:41:19 +04:00
k - > name = talloc_strdup ( k , name ) ;
2012-08-30 11:04:07 +04:00
if ( k - > name = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2012-09-05 10:27:28 +04:00
k - > algorithm = talloc_strdup ( k , algorithm ) ;
if ( k - > algorithm = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2017-05-15 08:30:14 +03:00
/*
* We only allow SPNEGO / KRB5 currently
* and rely on the backend to be RPC / IPC free .
*
* It allows gensec_update ( ) not to block .
*/
status = samba_server_gensec_krb5_start ( k ,
dns - > task - > event_ctx ,
dns - > task - > msg_ctx ,
dns - > task - > lp_ctx ,
dns - > server_credentials ,
" dns " ,
& k - > gensec ) ;
2012-08-30 11:04:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Failed to start GENSEC server code: %s \n " , nt_errstr ( status ) ) ) ;
* tkey = NULL ;
return status ;
}
gensec_want_feature ( k - > gensec , GENSEC_FEATURE_SIGN ) ;
2017-03-01 04:19:50 +03:00
status = gensec_set_remote_address ( k - > gensec ,
remote_address ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Failed to set remote address into GENSEC: %s \n " ,
nt_errstr ( status ) ) ) ;
* tkey = NULL ;
return status ;
}
status = gensec_set_local_address ( k - > gensec ,
local_address ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Failed to set local address into GENSEC: %s \n " ,
nt_errstr ( status ) ) ) ;
* tkey = NULL ;
return status ;
}
2012-08-30 11:04:07 +04:00
status = gensec_start_mech_by_oid ( k - > gensec , GENSEC_OID_SPNEGO ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Failed to start GENSEC server code: %s \n " ,
nt_errstr ( status ) ) ) ;
* tkey = NULL ;
return status ;
}
2018-05-31 22:11:16 +03:00
TALLOC_FREE ( store - > tkeys [ store - > next_idx ] ) ;
2012-08-30 11:04:07 +04:00
2012-08-31 15:41:19 +04:00
store - > tkeys [ store - > next_idx ] = k ;
( store - > next_idx ) + + ;
store - > next_idx % = store - > size ;
2012-08-30 11:04:07 +04:00
2012-08-31 15:41:19 +04:00
* tkey = k ;
return NT_STATUS_OK ;
2012-08-30 11:04:07 +04:00
}
2012-09-05 10:24:52 +04:00
static NTSTATUS accept_gss_ticket ( TALLOC_CTX * mem_ctx ,
struct dns_server * dns ,
struct dns_server_tkey * tkey ,
const DATA_BLOB * key ,
DATA_BLOB * reply ,
uint16_t * dns_auth_error )
{
NTSTATUS status ;
2017-05-15 08:30:14 +03:00
/*
* We use samba_server_gensec_krb5_start ( ) ,
* which only allows SPNEGO / KRB5 currently
* and makes sure the backend to be RPC / IPC free .
*
* See gensec_gssapi_update_internal ( ) as
* GENSEC_SERVER .
*
* It allows gensec_update ( ) not to block .
*
* If that changes in future we need to use
* gensec_update_send / recv here !
*/
status = gensec_update ( tkey - > gensec , mem_ctx ,
* key , reply ) ;
2012-09-05 10:24:52 +04:00
if ( NT_STATUS_EQUAL ( NT_STATUS_MORE_PROCESSING_REQUIRED , status ) ) {
* dns_auth_error = DNS_RCODE_OK ;
return status ;
}
if ( NT_STATUS_IS_OK ( status ) ) {
status = gensec_session_info ( tkey - > gensec , tkey , & tkey - > session_info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
* dns_auth_error = DNS_RCODE_BADKEY ;
return status ;
}
* dns_auth_error = DNS_RCODE_OK ;
}
return status ;
}
2012-08-30 11:04:07 +04:00
static WERROR handle_tkey ( struct dns_server * dns ,
TALLOC_CTX * mem_ctx ,
const struct dns_name_packet * in ,
2012-09-05 10:29:38 +04:00
struct dns_request_state * state ,
2012-08-30 11:04:07 +04:00
struct dns_res_rec * * answers ,
uint16_t * ancount )
{
struct dns_res_rec * in_tkey = NULL ;
struct dns_res_rec * ret_tkey ;
uint16_t i ;
for ( i = 0 ; i < in - > arcount ; i + + ) {
if ( in - > additional [ i ] . rr_type = = DNS_QTYPE_TKEY ) {
in_tkey = & in - > additional [ i ] ;
break ;
}
}
/* If this is a TKEY query, it should have a TKEY RR.
* Behaviour is not really specified in RFC 2930 or RFC 3645 , but
* FORMAT_ERROR seems to be what BIND uses . */
if ( in_tkey = = NULL ) {
return DNS_ERR ( FORMAT_ERROR ) ;
}
ret_tkey = talloc_zero ( mem_ctx , struct dns_res_rec ) ;
if ( ret_tkey = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-08-30 11:04:07 +04:00
}
ret_tkey - > name = talloc_strdup ( ret_tkey , in_tkey - > name ) ;
if ( ret_tkey - > name = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-08-30 11:04:07 +04:00
}
ret_tkey - > rr_type = DNS_QTYPE_TKEY ;
ret_tkey - > rr_class = DNS_QCLASS_ANY ;
ret_tkey - > length = UINT16_MAX ;
2012-09-05 10:27:28 +04:00
ret_tkey - > rdata . tkey_record . algorithm = talloc_strdup ( ret_tkey ,
in_tkey - > rdata . tkey_record . algorithm ) ;
2012-08-30 11:04:07 +04:00
if ( ret_tkey - > rdata . tkey_record . algorithm = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-08-30 11:04:07 +04:00
}
ret_tkey - > rdata . tkey_record . inception = in_tkey - > rdata . tkey_record . inception ;
ret_tkey - > rdata . tkey_record . expiration = in_tkey - > rdata . tkey_record . expiration ;
ret_tkey - > rdata . tkey_record . mode = in_tkey - > rdata . tkey_record . mode ;
switch ( in_tkey - > rdata . tkey_record . mode ) {
case DNS_TKEY_MODE_DH :
/* FIXME: According to RFC 2930, we MUST support this, but we don't.
* Still , claim it ' s a bad key instead of a bad mode */
ret_tkey - > rdata . tkey_record . error = DNS_RCODE_BADKEY ;
break ;
case DNS_TKEY_MODE_GSSAPI : {
NTSTATUS status ;
struct dns_server_tkey * tkey ;
DATA_BLOB key ;
DATA_BLOB reply ;
2012-09-05 10:24:52 +04:00
tkey = dns_find_tkey ( dns - > tkeys , in - > questions [ 0 ] . name ) ;
2012-08-30 11:04:07 +04:00
if ( tkey ! = NULL & & tkey - > complete ) {
/* TODO: check if the key is still valid */
DEBUG ( 1 , ( " Rejecting tkey negotiation for already established key \n " ) ) ;
ret_tkey - > rdata . tkey_record . error = DNS_RCODE_BADNAME ;
break ;
}
if ( tkey = = NULL ) {
2012-08-31 15:41:19 +04:00
status = create_tkey ( dns , in - > questions [ 0 ] . name ,
2012-09-05 10:27:28 +04:00
in_tkey - > rdata . tkey_record . algorithm ,
2017-03-01 04:19:50 +03:00
state - > remote_address ,
state - > local_address ,
2012-08-31 15:41:19 +04:00
& tkey ) ;
2012-08-30 11:04:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
ret_tkey - > rdata . tkey_record . error = DNS_RCODE_BADKEY ;
return ntstatus_to_werror ( status ) ;
}
}
key . data = in_tkey - > rdata . tkey_record . key_data ;
key . length = in_tkey - > rdata . tkey_record . key_size ;
status = accept_gss_ticket ( ret_tkey , dns , tkey , & key , & reply ,
& ret_tkey - > rdata . tkey_record . error ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_MORE_PROCESSING_REQUIRED ) ) {
DEBUG ( 1 , ( " More processing required \n " ) ) ;
ret_tkey - > rdata . tkey_record . error = DNS_RCODE_BADKEY ;
} else if ( NT_STATUS_IS_OK ( status ) ) {
2016-11-11 10:48:04 +03:00
DBG_DEBUG ( " Tkey handshake completed \n " ) ;
2012-09-05 10:29:38 +04:00
ret_tkey - > rdata . tkey_record . key_size = reply . length ;
ret_tkey - > rdata . tkey_record . key_data = talloc_memdup ( ret_tkey ,
reply . data ,
reply . length ) ;
2018-05-31 22:16:21 +03:00
if ( ret_tkey - > rdata . tkey_record . key_data = = NULL ) {
return WERR_NOT_ENOUGH_MEMORY ;
}
2012-09-05 10:29:38 +04:00
state - > sign = true ;
2014-10-14 11:34:29 +04:00
state - > key_name = talloc_strdup ( state - > mem_ctx , tkey - > name ) ;
2012-09-05 10:29:38 +04:00
if ( state - > key_name = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-09-05 10:29:38 +04:00
}
2012-08-30 11:04:07 +04:00
} else {
2012-09-07 00:53:32 +04:00
DEBUG ( 1 , ( " GSS key negotiation returned %s \n " , nt_errstr ( status ) ) ) ;
2012-08-30 11:04:07 +04:00
ret_tkey - > rdata . tkey_record . error = DNS_RCODE_BADKEY ;
}
break ;
}
case DNS_TKEY_MODE_DELETE :
/* TODO: implement me */
DEBUG ( 1 , ( " Should delete tkey here \n " ) ) ;
ret_tkey - > rdata . tkey_record . error = DNS_RCODE_OK ;
break ;
case DNS_TKEY_MODE_NULL :
case DNS_TKEY_MODE_SERVER :
case DNS_TKEY_MODE_CLIENT :
case DNS_TKEY_MODE_LAST :
/* We don't have to implement these, return a mode error */
ret_tkey - > rdata . tkey_record . error = DNS_RCODE_BADMODE ;
break ;
default :
DEBUG ( 1 , ( " Unsupported TKEY mode %d \n " ,
in_tkey - > rdata . tkey_record . mode ) ) ;
}
* answers = ret_tkey ;
* ancount = 1 ;
return WERR_OK ;
}
2012-05-24 16:53:47 +04:00
struct dns_server_process_query_state {
2016-02-17 01:30:21 +03:00
struct tevent_context * ev ;
struct dns_server * dns ;
struct dns_name_question * question ;
2012-05-24 16:53:47 +04:00
struct dns_res_rec * answers ;
uint16_t ancount ;
struct dns_res_rec * nsrecs ;
uint16_t nscount ;
struct dns_res_rec * additional ;
uint16_t arcount ;
2016-02-17 01:30:21 +03:00
struct forwarder_string * forwarders ;
2012-05-24 16:53:47 +04:00
} ;
2015-08-11 08:39:31 +03:00
static void dns_server_process_query_got_auth ( struct tevent_req * subreq ) ;
2012-05-24 16:53:47 +04:00
static void dns_server_process_query_got_response ( struct tevent_req * subreq ) ;
2012-05-24 19:02:57 +04:00
struct tevent_req * dns_server_process_query_send (
2012-05-24 16:53:47 +04:00
TALLOC_CTX * mem_ctx , struct tevent_context * ev ,
struct dns_server * dns , struct dns_request_state * req_state ,
const struct dns_name_packet * in )
2010-10-01 23:59:22 +04:00
{
2012-05-24 16:53:47 +04:00
struct tevent_req * req , * subreq ;
struct dns_server_process_query_state * state ;
2016-02-17 01:30:21 +03:00
const char * * forwarders = NULL ;
unsigned int i ;
2010-10-01 23:59:22 +04:00
2012-05-24 16:53:47 +04:00
req = tevent_req_create ( mem_ctx , & state ,
struct dns_server_process_query_state ) ;
if ( req = = NULL ) {
return NULL ;
}
2011-09-27 09:31:46 +04:00
if ( in - > qdcount ! = 1 ) {
2012-05-24 16:53:47 +04:00
tevent_req_werror ( req , DNS_ERR ( FORMAT_ERROR ) ) ;
return tevent_req_post ( req , ev ) ;
2011-09-27 09:31:46 +04:00
}
2011-09-28 05:05:38 +04:00
/* Windows returns NOT_IMPLEMENTED on this as well */
if ( in - > questions [ 0 ] . question_class = = DNS_QCLASS_NONE ) {
2012-05-24 16:53:47 +04:00
tevent_req_werror ( req , DNS_ERR ( NOT_IMPLEMENTED ) ) ;
return tevent_req_post ( req , ev ) ;
2011-09-28 05:05:38 +04:00
}
2012-08-30 11:04:07 +04:00
if ( in - > questions [ 0 ] . question_type = = DNS_QTYPE_TKEY ) {
WERROR err ;
2012-09-05 10:29:38 +04:00
err = handle_tkey ( dns , state , in , req_state ,
& state - > answers , & state - > ancount ) ;
2012-08-30 11:04:07 +04:00
if ( tevent_req_werror ( req , err ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
2016-02-17 01:30:21 +03:00
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 ) ;
}
2016-05-31 01:48:15 +03:00
if ( dns_authoritative_for_zone ( dns , in - > questions [ 0 ] . name ) ) {
2012-05-24 16:53:47 +04:00
req_state - > flags | = DNS_FLAG_AUTHORITATIVE ;
2015-08-08 07:49:16 +03:00
/*
* Initialize the response arrays , so that we can use
* them as their own talloc contexts when doing the
* realloc
*/
state - > answers = talloc_array ( state , struct dns_res_rec , 0 ) ;
if ( tevent_req_nomem ( state - > answers , req ) ) {
return tevent_req_post ( req , ev ) ;
}
state - > nsrecs = talloc_array ( state , struct dns_res_rec , 0 ) ;
if ( tevent_req_nomem ( state - > nsrecs , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2015-08-11 08:39:31 +03:00
subreq = handle_authoritative_send (
2016-02-17 01:30:21 +03:00
state , ev , dns , ( forwarders = = NULL ? NULL : forwarders [ 0 ] ) ,
2018-11-28 17:21:56 +03:00
& in - > questions [ 0 ] , & state - > answers , & state - > nsrecs ,
0 ) ; /* cname_depth */
2015-08-11 08:39:31 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
2015-08-07 08:58:20 +03:00
return tevent_req_post ( req , ev ) ;
2012-03-27 17:00:01 +04:00
}
2015-08-11 08:39:31 +03:00
tevent_req_set_callback (
subreq , dns_server_process_query_got_auth , req ) ;
return req ;
2012-03-27 10:42:22 +04:00
}
2010-10-01 23:59:22 +04:00
2012-05-24 16:53:47 +04:00
if ( ( req_state - > flags & DNS_FLAG_RECURSION_DESIRED ) & &
( req_state - > flags & DNS_FLAG_RECURSION_AVAIL ) ) {
2017-07-26 09:00:24 +03:00
DEBUG ( 5 , ( " Not authoritative for '%s', forwarding \n " ,
2012-05-24 16:53:47 +04:00
in - > questions [ 0 ] . name ) ) ;
2017-12-31 12:59:40 +03:00
subreq = ask_forwarder_send ( state , ev ,
2016-02-17 01:30:21 +03:00
( forwarders = = NULL ? NULL : forwarders [ 0 ] ) ,
& in - > questions [ 0 ] ) ;
2012-05-24 16:53:47 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback (
subreq , dns_server_process_query_got_response , req ) ;
return req ;
}
tevent_req_werror ( req , DNS_ERR ( NAME_ERROR ) ) ;
return tevent_req_post ( req , ev ) ;
}
2010-10-01 23:59:22 +04:00
2012-05-24 16:53:47 +04:00
static void dns_server_process_query_got_response ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct dns_server_process_query_state * state = tevent_req_data (
req , struct dns_server_process_query_state ) ;
2016-02-17 01:30:21 +03:00
WERROR werr ;
2012-05-24 16:53:47 +04:00
2016-02-17 01:30:21 +03:00
werr = ask_forwarder_recv ( subreq , state ,
& state - > answers , & state - > ancount ,
& state - > nsrecs , & state - > nscount ,
& state - > additional , & state - > arcount ) ;
2012-05-24 16:53:47 +04:00
TALLOC_FREE ( subreq ) ;
2016-02-17 01:30:21 +03:00
/* 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 ) ) ) ;
2017-12-31 12:59:40 +03:00
subreq = ask_forwarder_send ( state , state - > ev ,
2016-02-17 01:30:21 +03:00
state - > forwarders - > forwarder ,
state - > question ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq ,
dns_server_process_query_got_response ,
req ) ;
2012-05-24 16:53:47 +04:00
return ;
}
2016-02-17 01:30:21 +03:00
2012-05-24 16:53:47 +04:00
tevent_req_done ( req ) ;
}
2010-10-01 23:59:22 +04:00
2015-08-11 08:39:31 +03:00
static void dns_server_process_query_got_auth ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct dns_server_process_query_state * state = tevent_req_data (
req , struct dns_server_process_query_state ) ;
WERROR werr ;
werr = handle_authoritative_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
2016-02-17 01:30:21 +03:00
/* 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 ,
2018-11-28 17:21:56 +03:00
& state - > nsrecs ,
0 ) ; /* cname_depth */
2016-02-17 01:30:21 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq ,
dns_server_process_query_got_auth ,
req ) ;
2015-08-11 08:39:31 +03:00
return ;
}
2016-02-17 01:30:21 +03:00
2015-08-11 08:39:31 +03:00
state - > ancount = talloc_array_length ( state - > answers ) ;
state - > nscount = talloc_array_length ( state - > nsrecs ) ;
state - > arcount = talloc_array_length ( state - > additional ) ;
tevent_req_done ( req ) ;
}
2012-05-24 19:02:57 +04:00
WERROR dns_server_process_query_recv (
2012-05-24 16:53:47 +04:00
struct tevent_req * req , TALLOC_CTX * mem_ctx ,
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 dns_server_process_query_state * state = tevent_req_data (
req , struct dns_server_process_query_state ) ;
2015-07-17 16:27:51 +03:00
WERROR err = WERR_OK ;
2010-10-01 23:59:22 +04:00
2012-05-24 16:53:47 +04:00
if ( tevent_req_is_werror ( req , & err ) ) {
2015-07-17 16:27:51 +03:00
if ( ( ! W_ERROR_EQUAL ( err , DNS_ERR ( NAME_ERROR ) ) ) & &
( ! W_ERROR_EQUAL ( err , WERR_DNS_ERROR_NAME_DOES_NOT_EXIST ) ) ) {
return err ;
}
2012-05-24 16:53:47 +04:00
}
* answers = talloc_move ( mem_ctx , & state - > answers ) ;
* ancount = state - > ancount ;
* nsrecs = talloc_move ( mem_ctx , & state - > nsrecs ) ;
* nscount = state - > nscount ;
* additional = talloc_move ( mem_ctx , & state - > additional ) ;
* arcount = state - > arcount ;
2015-07-17 16:27:51 +03:00
return err ;
2012-05-24 16:53:47 +04:00
}