2010-10-12 08:23:32 +04:00
/*
Unix SMB / CIFS implementation .
DNS server startup
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"
# include "smbd/service_task.h"
# include "smbd/service.h"
# include "smbd/service_stream.h"
# include "smbd/process_model.h"
# include "lib/events/events.h"
# include "lib/socket/socket.h"
# include "lib/tsocket/tsocket.h"
# include "libcli/util/tstream.h"
2010-09-30 04:24:53 +04:00
# include "libcli/util/ntstatus.h"
2010-10-12 08:23:32 +04:00
# include "system/network.h"
# include "lib/stream/packet.h"
# include "lib/socket/netif.h"
# include "dns_server/dns_server.h"
# include "param/param.h"
2010-10-22 11:37:38 +04:00
# include "librpc/ndr/libndr.h"
# include "librpc/gen_ndr/ndr_dns.h"
2010-10-12 00:32:25 +04:00
# include "librpc/gen_ndr/ndr_dnsp.h"
# include <ldb.h>
# include "dsdb/samdb/samdb.h"
2010-10-01 03:35:04 +04:00
# include "dsdb/common/util.h"
2010-10-12 00:32:25 +04:00
# include "auth/session.h"
2010-10-01 03:35:04 +04:00
# include "lib/util/dlinklist.h"
2010-10-12 08:23:32 +04:00
2011-03-19 02:45:45 +03:00
NTSTATUS server_service_dns_init ( void ) ;
2010-10-12 08:23:32 +04:00
/* hold information about one dns socket */
struct dns_socket {
struct dns_server * dns ;
struct tsocket_address * local_address ;
} ;
struct dns_udp_socket {
struct dns_socket * dns_socket ;
struct tdgram_context * dgram ;
struct tevent_queue * send_queue ;
} ;
/*
state of an open tcp connection
*/
struct dns_tcp_connection {
/* stream connection we belong to */
struct stream_connection * conn ;
/* the dns_server the connection belongs to */
struct dns_socket * dns_socket ;
struct tstream_context * tstream ;
struct tevent_queue * send_queue ;
} ;
static void dns_tcp_terminate_connection ( struct dns_tcp_connection * dnsconn , const char * reason )
{
stream_terminate_connection ( dnsconn - > conn , reason ) ;
}
static void dns_tcp_recv ( struct stream_connection * conn , uint16_t flags )
{
struct dns_tcp_connection * dnsconn = talloc_get_type ( conn - > private_data ,
struct dns_tcp_connection ) ;
/* this should never be triggered! */
dns_tcp_terminate_connection ( dnsconn , " dns_tcp_recv: called " ) ;
}
static void dns_tcp_send ( struct stream_connection * conn , uint16_t flags )
{
struct dns_tcp_connection * dnsconn = talloc_get_type ( conn - > private_data ,
struct dns_tcp_connection ) ;
/* this should never be triggered! */
dns_tcp_terminate_connection ( dnsconn , " dns_tcp_send: called " ) ;
}
2010-09-30 04:24:53 +04:00
static NTSTATUS dns_process ( struct dns_server * dns ,
TALLOC_CTX * mem_ctx ,
DATA_BLOB * in ,
DATA_BLOB * out )
2010-10-12 08:23:32 +04:00
{
2010-10-22 11:37:38 +04:00
enum ndr_err_code ndr_err ;
2010-10-12 01:39:44 +04:00
WERROR ret ;
2012-03-28 14:19:51 +04:00
uint16_t dns_err = DNS_RCODE_OK ;
2012-03-27 15:59:03 +04:00
struct dns_request_state * state ;
2010-10-01 07:35:00 +04:00
struct dns_name_packet * in_packet ;
struct dns_name_packet * out_packet ;
2010-10-01 05:21:53 +04:00
struct dns_res_rec * answers = NULL , * nsrecs = NULL , * additional = NULL ;
uint16_t num_answers = 0 , num_nsrecs = 0 , num_additional = 0 ;
2010-09-30 04:24:53 +04:00
2010-10-01 07:35:00 +04:00
if ( in - > length < 12 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2012-03-27 15:59:03 +04:00
state = talloc_zero ( mem_ctx , struct dns_request_state ) ;
in_packet = talloc_zero ( state , struct dns_name_packet ) ;
2010-10-01 07:35:00 +04:00
/* TODO: We don't really need an out_packet. */
2012-03-27 15:59:03 +04:00
out_packet = talloc_zero ( state , struct dns_name_packet ) ;
2010-10-01 07:35:00 +04:00
2012-05-24 17:59:32 +04:00
if ( ( state = = NULL ) | | ( in_packet = = NULL ) | | ( out_packet = = NULL ) ) {
TALLOC_FREE ( state ) ;
return NT_STATUS_NO_MEMORY ;
}
2010-10-22 11:37:38 +04:00
2012-04-29 02:53:41 +04:00
dump_data ( 8 , in - > data , in - > length ) ;
2010-10-22 11:37:38 +04:00
2010-09-30 04:24:53 +04:00
ndr_err = ndr_pull_struct_blob ( in , in_packet , in_packet ,
2010-10-22 11:37:38 +04:00
( ndr_pull_flags_fn_t ) ndr_pull_dns_name_packet ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2010-09-30 04:24:53 +04:00
TALLOC_FREE ( in_packet ) ;
2010-10-22 11:37:38 +04:00
DEBUG ( 0 , ( " Failed to parse packet %d! \n " , ndr_err ) ) ;
2012-03-28 14:19:51 +04:00
dns_err = DNS_RCODE_FORMERR ;
goto drop ;
2010-10-22 11:37:38 +04:00
}
2012-04-29 02:53:41 +04:00
if ( DEBUGLVL ( 8 ) ) {
2011-11-15 11:38:27 +04:00
NDR_PRINT_DEBUG ( dns_name_packet , in_packet ) ;
}
2010-10-01 05:21:53 +04:00
* out_packet = * in_packet ;
2012-03-27 15:59:03 +04:00
state - > flags | = in_packet - > operation | DNS_FLAG_REPLY ;
2012-03-27 16:42:15 +04:00
if ( lpcfg_dns_recursive_queries ( dns - > task - > lp_ctx ) ) {
state - > flags | = DNS_FLAG_RECURSION_AVAIL ;
}
2010-09-30 04:24:53 +04:00
2010-10-01 05:21:53 +04:00
switch ( in_packet - > operation & DNS_OPCODE ) {
case DNS_OPCODE_QUERY :
2010-09-30 04:24:53 +04:00
2012-03-27 15:59:03 +04:00
ret = dns_server_process_query ( dns , state ,
out_packet , in_packet ,
2010-10-01 05:21:53 +04:00
& answers , & num_answers ,
& nsrecs , & num_nsrecs ,
& additional , & num_additional ) ;
2010-09-30 04:24:53 +04:00
2010-10-01 05:21:53 +04:00
break ;
2011-09-28 06:51:55 +04:00
case DNS_OPCODE_UPDATE :
2012-03-27 15:59:03 +04:00
ret = dns_server_process_update ( dns , state ,
out_packet , in_packet ,
2011-12-16 16:45:22 +04:00
& answers , & num_answers ,
2010-10-01 05:21:53 +04:00
& nsrecs , & num_nsrecs ,
& additional , & num_additional ) ;
break ;
default :
2010-10-12 01:39:44 +04:00
ret = WERR_DNS_ERROR_RCODE_NOT_IMPLEMENTED ;
2010-10-01 05:21:53 +04:00
break ;
}
2010-09-30 04:24:53 +04:00
2010-10-12 01:39:44 +04:00
if ( W_ERROR_IS_OK ( ret ) ) {
2010-09-30 04:24:53 +04:00
out_packet - > ancount = num_answers ;
out_packet - > answers = answers ;
out_packet - > nscount = num_nsrecs ;
out_packet - > nsrecs = nsrecs ;
out_packet - > arcount = num_additional ;
out_packet - > additional = additional ;
2010-10-01 05:21:53 +04:00
} else {
2010-10-12 01:39:44 +04:00
out_packet - > operation | = werr_to_dns_err ( ret ) ;
2010-09-30 04:24:53 +04:00
}
2012-03-27 15:59:03 +04:00
out_packet - > operation | = state - > flags ;
2012-04-29 02:53:41 +04:00
if ( DEBUGLVL ( 8 ) ) {
2011-11-15 11:38:27 +04:00
NDR_PRINT_DEBUG ( dns_name_packet , out_packet ) ;
}
2010-09-30 04:24:53 +04:00
ndr_err = ndr_push_struct_blob ( out , out_packet , out_packet ,
( ndr_push_flags_fn_t ) ndr_push_dns_name_packet ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
TALLOC_FREE ( in_packet ) ;
TALLOC_FREE ( out_packet ) ;
DEBUG ( 0 , ( " Failed to push packet %d! \n " , ndr_err ) ) ;
2012-03-28 14:19:51 +04:00
dns_err = DNS_RCODE_SERVFAIL ;
goto drop ;
2010-09-30 04:24:53 +04:00
}
2012-04-29 02:53:41 +04:00
dump_data ( 8 , out - > data , out - > length ) ;
2010-09-30 04:24:53 +04:00
return NT_STATUS_OK ;
2012-03-28 14:19:51 +04:00
drop :
* out = * in ;
out - > data [ 2 ] | = 0x80 ; /* Toggle DNS_FLAG_REPLY */
out - > data [ 3 ] | = dns_err ;
return NT_STATUS_OK ;
2010-10-12 08:23:32 +04:00
}
struct dns_tcp_call {
struct dns_tcp_connection * dns_conn ;
DATA_BLOB in ;
DATA_BLOB out ;
uint8_t out_hdr [ 4 ] ;
struct iovec out_iov [ 2 ] ;
} ;
static void dns_tcp_call_writev_done ( struct tevent_req * subreq ) ;
static void dns_tcp_call_loop ( struct tevent_req * subreq )
{
struct dns_tcp_connection * dns_conn = tevent_req_callback_data ( subreq ,
struct dns_tcp_connection ) ;
struct dns_tcp_call * call ;
NTSTATUS status ;
call = talloc ( dns_conn , struct dns_tcp_call ) ;
if ( call = = NULL ) {
dns_tcp_terminate_connection ( dns_conn , " dns_tcp_call_loop: "
" no memory for dns_tcp_call " ) ;
return ;
}
call - > dns_conn = dns_conn ;
status = tstream_read_pdu_blob_recv ( subreq ,
call ,
& call - > in ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
const char * reason ;
reason = talloc_asprintf ( call , " dns_tcp_call_loop: "
" tstream_read_pdu_blob_recv() - %s " ,
nt_errstr ( status ) ) ;
if ( ! reason ) {
reason = nt_errstr ( status ) ;
}
dns_tcp_terminate_connection ( dns_conn , reason ) ;
return ;
}
2012-03-06 11:49:16 +04:00
DEBUG ( 10 , ( " Received DNS TCP packet of length %lu from %s \n " ,
2010-10-12 08:23:32 +04:00
( long ) call - > in . length ,
tsocket_address_string ( dns_conn - > conn - > remote_address , call ) ) ) ;
/* skip length header */
2012-03-06 11:49:16 +04:00
call - > in . data + = 2 ;
call - > in . length - = 2 ;
2010-10-12 08:23:32 +04:00
/* Call dns */
2010-09-30 04:24:53 +04:00
status = dns_process ( dns_conn - > dns_socket - > dns , call , & call - > in , & call - > out ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-10-12 00:32:25 +04:00
DEBUG ( 0 , ( " dns_process returned %s \n " , nt_errstr ( status ) ) ) ;
2010-10-12 08:23:32 +04:00
dns_tcp_terminate_connection ( dns_conn ,
" dns_tcp_call_loop: process function failed " ) ;
return ;
}
/* First add the length of the out buffer */
2012-03-06 11:49:16 +04:00
RSSVAL ( call - > out_hdr , 0 , call - > out . length ) ;
2010-10-12 08:23:32 +04:00
call - > out_iov [ 0 ] . iov_base = ( char * ) call - > out_hdr ;
2012-03-06 11:49:16 +04:00
call - > out_iov [ 0 ] . iov_len = 2 ;
2010-10-12 08:23:32 +04:00
call - > out_iov [ 1 ] . iov_base = ( char * ) call - > out . data ;
call - > out_iov [ 1 ] . iov_len = call - > out . length ;
subreq = tstream_writev_queue_send ( call ,
dns_conn - > conn - > event . ctx ,
dns_conn - > tstream ,
dns_conn - > send_queue ,
call - > out_iov , 2 ) ;
if ( subreq = = NULL ) {
dns_tcp_terminate_connection ( dns_conn , " dns_tcp_call_loop: "
" no memory for tstream_writev_queue_send " ) ;
return ;
}
tevent_req_set_callback ( subreq , dns_tcp_call_writev_done , call ) ;
/*
2012-03-06 11:49:16 +04:00
* The dns tcp pdu ' s has the length as 2 byte ( initial_read_size ) ,
* packet_full_request_u16 provides the pdu length then .
2010-10-12 08:23:32 +04:00
*/
subreq = tstream_read_pdu_blob_send ( dns_conn ,
dns_conn - > conn - > event . ctx ,
dns_conn - > tstream ,
2012-03-06 11:49:16 +04:00
2 , /* initial_read_size */
packet_full_request_u16 ,
2010-10-12 08:23:32 +04:00
dns_conn ) ;
if ( subreq = = NULL ) {
dns_tcp_terminate_connection ( dns_conn , " dns_tcp_call_loop: "
" no memory for tstream_read_pdu_blob_send " ) ;
return ;
}
tevent_req_set_callback ( subreq , dns_tcp_call_loop , dns_conn ) ;
}
static void dns_tcp_call_writev_done ( struct tevent_req * subreq )
{
struct dns_tcp_call * call = tevent_req_callback_data ( subreq ,
struct dns_tcp_call ) ;
int sys_errno ;
int rc ;
rc = tstream_writev_queue_recv ( subreq , & sys_errno ) ;
TALLOC_FREE ( subreq ) ;
if ( rc = = - 1 ) {
const char * reason ;
reason = talloc_asprintf ( call , " dns_tcp_call_writev_done: "
" tstream_writev_queue_recv() - %d:%s " ,
sys_errno , strerror ( sys_errno ) ) ;
if ( ! reason ) {
reason = " dns_tcp_call_writev_done: tstream_writev_queue_recv() failed " ;
}
dns_tcp_terminate_connection ( call - > dns_conn , reason ) ;
return ;
}
/* We don't care about errors */
talloc_free ( call ) ;
}
/*
called when we get a new connection
*/
static void dns_tcp_accept ( struct stream_connection * conn )
{
struct dns_socket * dns_socket ;
struct dns_tcp_connection * dns_conn ;
struct tevent_req * subreq ;
int rc ;
dns_conn = talloc_zero ( conn , struct dns_tcp_connection ) ;
if ( dns_conn = = NULL ) {
stream_terminate_connection ( conn ,
" dns_tcp_accept: out of memory " ) ;
return ;
}
dns_conn - > send_queue = tevent_queue_create ( conn , " dns_tcp_accept " ) ;
if ( dns_conn - > send_queue = = NULL ) {
stream_terminate_connection ( conn ,
" dns_tcp_accept: out of memory " ) ;
return ;
}
dns_socket = talloc_get_type ( conn - > private_data , struct dns_socket ) ;
TALLOC_FREE ( conn - > event . fde ) ;
rc = tstream_bsd_existing_socket ( dns_conn ,
socket_get_fd ( conn - > socket ) ,
& dns_conn - > tstream ) ;
if ( rc < 0 ) {
stream_terminate_connection ( conn ,
" dns_tcp_accept: out of memory " ) ;
return ;
}
dns_conn - > conn = conn ;
dns_conn - > dns_socket = dns_socket ;
conn - > private_data = dns_conn ;
/*
2012-03-06 11:49:16 +04:00
* The dns tcp pdu ' s has the length as 2 byte ( initial_read_size ) ,
* packet_full_request_u16 provides the pdu length then .
2010-10-12 08:23:32 +04:00
*/
subreq = tstream_read_pdu_blob_send ( dns_conn ,
dns_conn - > conn - > event . ctx ,
dns_conn - > tstream ,
2012-03-06 11:49:16 +04:00
2 , /* initial_read_size */
packet_full_request_u16 ,
2010-10-12 08:23:32 +04:00
dns_conn ) ;
if ( subreq = = NULL ) {
dns_tcp_terminate_connection ( dns_conn , " dns_tcp_accept: "
" no memory for tstream_read_pdu_blob_send " ) ;
return ;
}
tevent_req_set_callback ( subreq , dns_tcp_call_loop , dns_conn ) ;
}
static const struct stream_server_ops dns_tcp_stream_ops = {
. name = " dns_tcp " ,
. accept_connection = dns_tcp_accept ,
. recv_handler = dns_tcp_recv ,
. send_handler = dns_tcp_send
} ;
struct dns_udp_call {
struct tsocket_address * src ;
DATA_BLOB in ;
DATA_BLOB out ;
} ;
static void dns_udp_call_sendto_done ( struct tevent_req * subreq ) ;
static void dns_udp_call_loop ( struct tevent_req * subreq )
{
struct dns_udp_socket * sock = tevent_req_callback_data ( subreq ,
struct dns_udp_socket ) ;
struct dns_udp_call * call ;
uint8_t * buf ;
ssize_t len ;
int sys_errno ;
2010-09-30 04:24:53 +04:00
NTSTATUS status ;
2010-10-12 08:23:32 +04:00
call = talloc ( sock , struct dns_udp_call ) ;
if ( call = = NULL ) {
talloc_free ( call ) ;
goto done ;
}
len = tdgram_recvfrom_recv ( subreq , & sys_errno ,
call , & buf , & call - > src ) ;
TALLOC_FREE ( subreq ) ;
if ( len = = - 1 ) {
talloc_free ( call ) ;
goto done ;
}
call - > in . data = buf ;
call - > in . length = len ;
2011-12-16 12:13:31 +04:00
DEBUG ( 10 , ( " Received DNS UDP packet of length %lu from %s \n " ,
2010-10-12 08:23:32 +04:00
( long ) call - > in . length ,
tsocket_address_string ( call - > src , call ) ) ) ;
2011-12-16 12:13:31 +04:00
/* Call dns_process */
2010-09-30 04:24:53 +04:00
status = dns_process ( sock - > dns_socket - > dns , call , & call - > in , & call - > out ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-10-12 08:23:32 +04:00
talloc_free ( call ) ;
2010-10-12 00:32:25 +04:00
DEBUG ( 0 , ( " dns_process returned %s \n " , nt_errstr ( status ) ) ) ;
2010-10-12 08:23:32 +04:00
goto done ;
}
subreq = tdgram_sendto_queue_send ( call ,
sock - > dns_socket - > dns - > task - > event_ctx ,
sock - > dgram ,
sock - > send_queue ,
call - > out . data ,
call - > out . length ,
call - > src ) ;
if ( subreq = = NULL ) {
talloc_free ( call ) ;
goto done ;
}
tevent_req_set_callback ( subreq , dns_udp_call_sendto_done , call ) ;
done :
subreq = tdgram_recvfrom_send ( sock ,
sock - > dns_socket - > dns - > task - > event_ctx ,
sock - > dgram ) ;
if ( subreq = = NULL ) {
task_server_terminate ( sock - > dns_socket - > dns - > task ,
" no memory for tdgram_recvfrom_send " ,
true ) ;
return ;
}
tevent_req_set_callback ( subreq , dns_udp_call_loop , sock ) ;
}
static void dns_udp_call_sendto_done ( struct tevent_req * subreq )
{
struct dns_udp_call * call = tevent_req_callback_data ( subreq ,
struct dns_udp_call ) ;
ssize_t ret ;
int sys_errno ;
ret = tdgram_sendto_queue_recv ( subreq , & sys_errno ) ;
/* We don't care about errors */
talloc_free ( call ) ;
}
/*
start listening on the given address
*/
static NTSTATUS dns_add_socket ( struct dns_server * dns ,
const struct model_ops * model_ops ,
const char * name ,
const char * address ,
uint16_t port )
{
struct dns_socket * dns_socket ;
struct dns_udp_socket * dns_udp_socket ;
struct tevent_req * udpsubreq ;
NTSTATUS status ;
int ret ;
dns_socket = talloc ( dns , struct dns_socket ) ;
NT_STATUS_HAVE_NO_MEMORY ( dns_socket ) ;
dns_socket - > dns = dns ;
ret = tsocket_address_inet_from_strings ( dns_socket , " ip " ,
address , port ,
& dns_socket - > local_address ) ;
if ( ret ! = 0 ) {
2011-06-20 08:55:32 +04:00
status = map_nt_error_from_unix_common ( errno ) ;
2010-10-12 08:23:32 +04:00
return status ;
}
2010-11-15 02:12:22 +03:00
status = stream_setup_socket ( dns - > task ,
dns - > task - > event_ctx ,
2010-10-12 08:23:32 +04:00
dns - > task - > lp_ctx ,
model_ops ,
& dns_tcp_stream_ops ,
" ip " , address , & port ,
lpcfg_socket_options ( dns - > task - > lp_ctx ) ,
dns_socket ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Failed to bind to %s:%u TCP - %s \n " ,
address , port , nt_errstr ( status ) ) ) ;
talloc_free ( dns_socket ) ;
return status ;
}
dns_udp_socket = talloc ( dns_socket , struct dns_udp_socket ) ;
NT_STATUS_HAVE_NO_MEMORY ( dns_udp_socket ) ;
dns_udp_socket - > dns_socket = dns_socket ;
ret = tdgram_inet_udp_socket ( dns_socket - > local_address ,
NULL ,
dns_udp_socket ,
& dns_udp_socket - > dgram ) ;
if ( ret ! = 0 ) {
2011-06-20 08:55:32 +04:00
status = map_nt_error_from_unix_common ( errno ) ;
2010-10-12 08:23:32 +04:00
DEBUG ( 0 , ( " Failed to bind to %s:%u UDP - %s \n " ,
address , port , nt_errstr ( status ) ) ) ;
return status ;
}
dns_udp_socket - > send_queue = tevent_queue_create ( dns_udp_socket ,
" dns_udp_send_queue " ) ;
NT_STATUS_HAVE_NO_MEMORY ( dns_udp_socket - > send_queue ) ;
udpsubreq = tdgram_recvfrom_send ( dns_udp_socket ,
dns - > task - > event_ctx ,
dns_udp_socket - > dgram ) ;
NT_STATUS_HAVE_NO_MEMORY ( udpsubreq ) ;
tevent_req_set_callback ( udpsubreq , dns_udp_call_loop , dns_udp_socket ) ;
return NT_STATUS_OK ;
}
/*
setup our listening sockets on the configured network interfaces
*/
static NTSTATUS dns_startup_interfaces ( struct dns_server * dns , struct loadparm_context * lp_ctx ,
struct interface * ifaces )
{
const struct model_ops * model_ops ;
int num_interfaces ;
TALLOC_CTX * tmp_ctx = talloc_new ( dns ) ;
NTSTATUS status ;
int i ;
/* within the dns task we want to be a single process, so
ask for the single process model ops and pass these to the
stream_setup_socket ( ) call . */
2010-10-30 04:24:15 +04:00
model_ops = process_model_startup ( " single " ) ;
2010-10-12 08:23:32 +04:00
if ( ! model_ops ) {
DEBUG ( 0 , ( " Can't find 'single' process model_ops \n " ) ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
2011-05-02 09:57:19 +04:00
num_interfaces = iface_list_count ( ifaces ) ;
2010-10-12 08:23:32 +04:00
for ( i = 0 ; i < num_interfaces ; i + + ) {
2011-05-02 09:57:19 +04:00
const char * address = talloc_strdup ( tmp_ctx , iface_list_n_ip ( ifaces , i ) ) ;
2010-10-12 08:23:32 +04:00
status = dns_add_socket ( dns , model_ops , " dns " , address , DNS_SERVICE_PORT ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
}
talloc_free ( tmp_ctx ) ;
return NT_STATUS_OK ;
}
2010-10-01 03:35:04 +04:00
static int dns_server_sort_zones ( struct ldb_message * * m1 , struct ldb_message * * m2 )
{
const char * n1 , * n2 ;
size_t l1 , l2 ;
n1 = ldb_msg_find_attr_as_string ( * m1 , " name " , NULL ) ;
n2 = ldb_msg_find_attr_as_string ( * m2 , " name " , NULL ) ;
l1 = strlen ( n1 ) ;
l2 = strlen ( n2 ) ;
/* If the string lengths are not equal just sort by length */
if ( l1 ! = l2 ) {
/* If m1 is the larger zone name, return it first */
return l2 - l1 ;
}
/*TODO: We need to compare DNs here, we want the DomainDNSZones first */
return 0 ;
}
2010-10-12 08:23:32 +04:00
static void dns_task_init ( struct task_server * task )
{
struct dns_server * dns ;
NTSTATUS status ;
struct interface * ifaces ;
2010-10-01 03:35:04 +04:00
int ret ;
struct ldb_result * res ;
static const char * const attrs [ ] = { " name " , NULL } ;
2010-10-23 17:52:34 +04:00
unsigned int i ;
2010-10-12 08:23:32 +04:00
switch ( lpcfg_server_role ( task - > lp_ctx ) ) {
case ROLE_STANDALONE :
task_server_terminate ( task , " dns: no DNS required in standalone configuration " , false ) ;
return ;
case ROLE_DOMAIN_MEMBER :
task_server_terminate ( task , " dns: no DNS required in member server configuration " , false ) ;
return ;
case ROLE_DOMAIN_CONTROLLER :
/* Yes, we want a DNS */
break ;
}
2011-06-02 09:40:28 +04:00
load_interface_list ( task , task - > lp_ctx , & ifaces ) ;
2010-10-12 08:23:32 +04:00
2011-05-02 09:57:19 +04:00
if ( iface_list_count ( ifaces ) = = 0 ) {
2010-10-12 08:23:32 +04:00
task_server_terminate ( task , " dns: no network interfaces configured " , false ) ;
return ;
}
task_server_set_title ( task , " task[dns] " ) ;
2010-10-01 03:35:04 +04:00
dns = talloc_zero ( task , struct dns_server ) ;
2010-10-12 08:23:32 +04:00
if ( dns = = NULL ) {
task_server_terminate ( task , " dns: out of memory " , true ) ;
return ;
}
dns - > task = task ;
2010-10-12 00:32:25 +04:00
dns - > samdb = samdb_connect ( dns , dns - > task - > event_ctx , dns - > task - > lp_ctx ,
system_session ( dns - > task - > lp_ctx ) , 0 ) ;
if ( ! dns - > samdb ) {
task_server_terminate ( task , " dns: samdb_connect failed " , true ) ;
return ;
}
2010-10-01 03:35:04 +04:00
// TODO: this search does not work against windows
2011-08-19 11:27:55 +04:00
ret = dsdb_search ( dns - > samdb , dns , & res , NULL , LDB_SCOPE_SUBTREE ,
2010-10-01 03:35:04 +04:00
attrs , DSDB_SEARCH_SEARCH_ALL_PARTITIONS , " (objectClass=dnsZone) " ) ;
if ( ret ! = LDB_SUCCESS ) {
task_server_terminate ( task ,
" dns: failed to look up root DNS zones " ,
true ) ;
return ;
}
TYPESAFE_QSORT ( res - > msgs , res - > count , dns_server_sort_zones ) ;
for ( i = 0 ; i < res - > count ; i + + ) {
struct dns_server_zone * z ;
z = talloc_zero ( dns , struct dns_server_zone ) ;
if ( z = = NULL ) {
}
z - > name = ldb_msg_find_attr_as_string ( res - > msgs [ i ] , " name " , NULL ) ;
z - > dn = talloc_move ( z , & res - > msgs [ i ] - > dn ) ;
DLIST_ADD_END ( dns - > zones , z , NULL ) ;
}
2010-10-12 08:23:32 +04:00
status = dns_startup_interfaces ( dns , task - > lp_ctx , ifaces ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
task_server_terminate ( task , " dns failed to setup interfaces " , true ) ;
return ;
}
}
NTSTATUS server_service_dns_init ( void )
{
return register_server_service ( " dns " , dns_task_init ) ;
}