1997-10-22 15:02:00 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1997-10-22 15:02:00 +04:00
a async DNS handler
1998-01-22 16:27:43 +03:00
Copyright ( C ) Andrew Tridgell 1997 - 1998
2011-12-13 19:21:37 +04:00
1997-10-22 15:02:00 +04:00
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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
1997-10-22 15:02:00 +04:00
( at your option ) any later version .
2011-12-13 19:21:37 +04:00
1997-10-22 15:02:00 +04:00
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 .
2011-12-13 19:21:37 +04:00
1997-10-22 15:02:00 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1997-11-02 04:33:28 +03:00
*/
1997-10-22 15:02:00 +04:00
# include "includes.h"
2010-08-18 17:22:09 +04:00
# include "nmbd/nmbd.h"
2015-10-12 16:57:34 +03:00
# include "lib/util/sys_rw_data.h"
1997-10-22 15:02:00 +04:00
/***************************************************************************
1997-12-13 17:16:07 +03:00
Add a DNS result to the name cache .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-10-22 15:02:00 +04:00
static struct name_record * add_dns_result ( struct nmb_name * question , struct in_addr addr )
{
2003-08-27 05:25:01 +04:00
int name_type = question - > name_type ;
2004-03-16 00:45:45 +03:00
unstring qname ;
2003-08-27 05:25:01 +04:00
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( qname , sizeof ( qname ) , question - > name ) ;
2011-12-13 19:21:37 +04:00
2003-08-27 05:25:01 +04:00
if ( ! addr . s_addr ) {
/* add the fail to WINS cache of names. give it 1 hour in the cache */
DEBUG ( 3 , ( " add_dns_result: Negative DNS answer for %s \n " , qname ) ) ;
2005-12-07 02:06:38 +03:00
add_name_to_subnet ( wins_server_subnet , qname , name_type ,
2003-08-27 05:25:01 +04:00
NB_ACTIVE , 60 * 60 , DNSFAIL_NAME , 1 , & addr ) ;
2005-12-07 02:06:38 +03:00
return NULL ;
2003-08-27 05:25:01 +04:00
}
1997-10-22 15:02:00 +04:00
2003-08-27 05:25:01 +04:00
/* add it to our WINS cache of names. give it 2 hours in the cache */
DEBUG ( 3 , ( " add_dns_result: DNS gave answer for %s of %s \n " , qname , inet_ntoa ( addr ) ) ) ;
1997-10-22 15:02:00 +04:00
2005-12-07 02:06:38 +03:00
add_name_to_subnet ( wins_server_subnet , qname , name_type ,
NB_ACTIVE , 2 * 60 * 60 , DNS_NAME , 1 , & addr ) ;
return find_name_on_subnet ( wins_server_subnet , question , FIND_ANY_NAME ) ;
2003-08-27 05:25:01 +04:00
}
1997-10-22 15:02:00 +04:00
# ifndef SYNC_DNS
static int fd_in = - 1 , fd_out = - 1 ;
1999-12-13 16:27:58 +03:00
static pid_t child_pid = - 1 ;
1997-10-22 15:02:00 +04:00
static int in_dns ;
/* this is the structure that is passed between the parent and child */
struct query_record {
struct nmb_name name ;
struct in_addr result ;
} ;
1997-11-02 04:25:50 +03:00
/* a queue of pending requests waiting to be sent to the DNS child */
1997-10-22 15:02:00 +04:00
static struct packet_struct * dns_queue ;
1997-11-02 04:25:50 +03:00
/* the packet currently being processed by the dns child */
static struct packet_struct * dns_current ;
1997-10-22 15:02:00 +04:00
/***************************************************************************
return the fd used to gather async dns replies . This is added to the select
loop
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-08-27 05:25:01 +04:00
1997-10-22 15:02:00 +04:00
int asyncdns_fd ( void )
{
return fd_in ;
}
/***************************************************************************
handle DNS queries arriving from the parent
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void asyncdns_process ( void )
{
struct query_record r ;
2004-03-16 00:45:45 +03:00
unstring qname ;
1997-10-22 15:02:00 +04:00
2018-11-07 16:14:05 +03:00
debuglevel_set ( - 1 ) ;
1997-10-22 15:02:00 +04:00
while ( 1 ) {
2008-01-26 12:39:21 +03:00
NTSTATUS status ;
2014-11-19 17:06:49 +03:00
status = read_data_ntstatus ( fd_in , ( char * ) & r , sizeof ( r ) ) ;
2008-01-26 12:39:21 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
1997-10-22 15:02:00 +04:00
break ;
2008-01-26 12:39:21 +03:00
}
1997-10-22 15:02:00 +04:00
2004-03-16 00:45:45 +03:00
pull_ascii_nstring ( qname , sizeof ( qname ) , r . name . name ) ;
1997-10-22 15:02:00 +04:00
r . result . s_addr = interpret_addr ( qname ) ;
if ( write_data ( fd_out , ( char * ) & r , sizeof ( r ) ) ! = sizeof ( r ) )
break ;
}
1997-11-02 02:42:28 +03:00
_exit ( 0 ) ;
1997-10-22 15:02:00 +04:00
}
1997-12-13 17:16:07 +03:00
/**************************************************************************** **
1998-03-03 23:19:14 +03:00
catch a sigterm ( in the child process - the parent has a different handler
see nmbd . c for details ) .
1997-12-13 17:16:07 +03:00
We need a separate term handler here so we don ' t release any
names that our parent is going to release , or overwrite a
WINS db that our parent is going to write .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-15 05:19:26 +04:00
static void sig_term ( int sig )
1997-12-13 17:16:07 +03:00
{
2003-08-27 05:25:01 +04:00
_exit ( 0 ) ;
1997-12-13 17:16:07 +03:00
}
1997-10-22 15:02:00 +04:00
1998-03-03 23:19:14 +03:00
/***************************************************************************
Called by the parent process when it receives a SIGTERM - also kills the
child so we don ' t get child async dns processes lying around , causing trouble .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-04-13 23:24:06 +04:00
void kill_async_dns_child ( void )
1998-03-03 23:19:14 +03:00
{
2002-03-20 09:57:03 +03:00
if ( child_pid > 0 ) {
kill ( child_pid , SIGTERM ) ;
2002-08-17 21:00:51 +04:00
child_pid = - 1 ;
2002-03-20 09:57:03 +03:00
}
1998-03-03 23:19:14 +03:00
}
1997-10-22 15:02:00 +04:00
/***************************************************************************
create a child process to handle DNS lookups
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-12-13 19:48:11 +04:00
void start_async_dns ( struct messaging_context * msg )
1997-10-22 15:02:00 +04:00
{
int fd1 [ 2 ] , fd2 [ 2 ] ;
2010-07-04 18:28:13 +04:00
NTSTATUS status ;
1997-10-22 15:02:00 +04:00
1998-07-29 07:08:05 +04:00
CatchChild ( ) ;
1997-10-22 15:02:00 +04:00
if ( pipe ( fd1 ) | | pipe ( fd2 ) ) {
1998-08-30 20:33:48 +04:00
DEBUG ( 0 , ( " can't create asyncdns pipes \n " ) ) ;
1997-10-22 15:02:00 +04:00
return ;
}
2012-03-24 23:17:08 +04:00
child_pid = fork ( ) ;
1997-10-22 15:02:00 +04:00
if ( child_pid ) {
fd_in = fd1 [ 0 ] ;
fd_out = fd2 [ 1 ] ;
close ( fd1 [ 1 ] ) ;
close ( fd2 [ 0 ] ) ;
1999-12-13 16:27:58 +03:00
DEBUG ( 0 , ( " started asyncdns process %d \n " , ( int ) child_pid ) ) ;
1997-10-22 15:02:00 +04:00
return ;
}
fd_in = fd2 [ 0 ] ;
fd_out = fd1 [ 1 ] ;
1998-07-29 07:08:05 +04:00
CatchSignal ( SIGUSR2 , SIG_IGN ) ;
CatchSignal ( SIGUSR1 , SIG_IGN ) ;
CatchSignal ( SIGHUP , SIG_IGN ) ;
2010-02-19 17:28:11 +03:00
CatchSignal ( SIGTERM , sig_term ) ;
1997-12-04 13:58:40 +03:00
2015-09-23 21:14:05 +03:00
status = reinit_after_fork ( msg , nmbd_event_context ( ) , true , NULL ) ;
2010-07-04 18:28:13 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-04-15 12:38:21 +04:00
DEBUG ( 0 , ( " reinit_after_fork() failed \n " ) ) ;
smb_panic ( " reinit_after_fork() failed " ) ;
}
1997-10-22 15:02:00 +04:00
asyncdns_process ( ) ;
}
/***************************************************************************
check if a particular name is already being queried
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static bool query_current ( struct query_record * r )
1997-10-22 15:02:00 +04:00
{
1997-11-02 04:25:50 +03:00
return dns_current & &
1997-12-13 17:16:07 +03:00
nmb_name_equal ( & r - > name ,
1997-11-02 04:25:50 +03:00
& dns_current - > packet . nmb . question . question_name ) ;
1997-10-22 15:02:00 +04:00
}
1997-11-02 04:25:50 +03:00
/***************************************************************************
write a query to the child process
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static bool write_child ( struct packet_struct * p )
1997-11-02 04:25:50 +03:00
{
struct query_record r ;
r . name = p - > packet . nmb . question . question_name ;
return write_data ( fd_out , ( char * ) & r , sizeof ( r ) ) = = sizeof ( r ) ;
}
1997-10-22 15:02:00 +04:00
/***************************************************************************
check the DNS queue
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-12-13 19:48:11 +04:00
void run_dns_queue ( struct messaging_context * msg )
1997-10-22 15:02:00 +04:00
{
struct query_record r ;
struct packet_struct * p , * p2 ;
1997-12-13 17:16:07 +03:00
struct name_record * namerec ;
2008-01-26 12:39:21 +03:00
NTSTATUS status ;
1997-10-22 15:02:00 +04:00
if ( fd_in = = - 1 )
return ;
2005-09-30 21:13:37 +04:00
if ( ! process_exists_by_pid ( child_pid ) ) {
1997-12-04 13:58:40 +03:00
close ( fd_in ) ;
2006-08-25 00:42:31 +04:00
close ( fd_out ) ;
2011-12-13 19:48:11 +04:00
start_async_dns ( msg ) ;
1997-12-04 13:58:40 +03:00
}
2014-11-19 17:06:49 +03:00
status = read_data_ntstatus ( fd_in , ( char * ) & r , sizeof ( r ) ) ;
2008-01-26 12:39:21 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " read from child failed: %s \n " , nt_errstr ( status ) ) ) ;
fd_in = - 1 ;
1997-10-22 15:02:00 +04:00
return ;
}
1997-12-13 17:16:07 +03:00
namerec = add_dns_result ( & r . name , r . result ) ;
1997-10-22 15:02:00 +04:00
1997-11-02 04:25:50 +03:00
if ( dns_current ) {
if ( query_current ( & r ) ) {
1997-12-13 17:16:07 +03:00
DEBUG ( 3 , ( " DNS calling send_wins_name_query_response \n " ) ) ;
1997-11-02 04:25:50 +03:00
in_dns = 1 ;
2003-08-27 05:25:01 +04:00
if ( namerec = = NULL )
send_wins_name_query_response ( NAM_ERR , dns_current , NULL ) ;
else
send_wins_name_query_response ( 0 , dns_current , namerec ) ;
1997-11-02 04:25:50 +03:00
in_dns = 0 ;
}
dns_current - > locked = False ;
free_packet ( dns_current ) ;
dns_current = NULL ;
}
1997-10-22 15:02:00 +04:00
/* loop over the whole dns queue looking for entries that
match the result we just got */
for ( p = dns_queue ; p ; ) {
struct nmb_packet * nmb = & p - > packet . nmb ;
struct nmb_name * question = & nmb - > question . question_name ;
1997-12-13 17:16:07 +03:00
if ( nmb_name_equal ( question , & r . name ) ) {
DEBUG ( 3 , ( " DNS calling send_wins_name_query_response \n " ) ) ;
1997-10-22 15:02:00 +04:00
in_dns = 1 ;
2003-08-27 05:25:01 +04:00
if ( namerec = = NULL )
send_wins_name_query_response ( NAM_ERR , p , NULL ) ;
else
send_wins_name_query_response ( 0 , p , namerec ) ;
1997-10-22 15:02:00 +04:00
in_dns = 0 ;
p - > locked = False ;
p2 = p - > next ;
2010-02-06 04:38:24 +03:00
DLIST_REMOVE ( dns_queue , p ) ;
1997-10-22 15:02:00 +04:00
free_packet ( p ) ;
p = p2 ;
} else {
p = p - > next ;
}
}
1997-11-02 04:25:50 +03:00
if ( dns_queue ) {
dns_current = dns_queue ;
2010-02-06 04:38:24 +03:00
DLIST_REMOVE ( dns_queue , dns_queue ) ;
1997-11-02 04:25:50 +03:00
if ( ! write_child ( dns_current ) ) {
DEBUG ( 3 , ( " failed to send DNS query to child! \n " ) ) ;
return ;
}
}
1997-10-22 15:02:00 +04:00
}
/***************************************************************************
queue a DNS query
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-08-27 05:25:01 +04:00
2007-10-19 04:40:25 +04:00
bool queue_dns_query ( struct packet_struct * p , struct nmb_name * question )
1997-10-22 15:02:00 +04:00
{
if ( in_dns | | fd_in = = - 1 )
return False ;
1997-11-02 04:25:50 +03:00
if ( ! dns_current ) {
if ( ! write_child ( p ) ) {
DEBUG ( 3 , ( " failed to send DNS query to child! \n " ) ) ;
return False ;
}
dns_current = p ;
p - > locked = True ;
} else {
p - > locked = True ;
2010-02-06 04:38:24 +03:00
DLIST_ADD ( dns_queue , p ) ;
1997-10-22 15:02:00 +04:00
}
1998-11-14 04:04:13 +03:00
DEBUG ( 3 , ( " added DNS query for %s \n " , nmb_namestr ( question ) ) ) ;
1997-10-22 15:02:00 +04:00
return True ;
}
# else
/***************************************************************************
1998-09-17 23:16:12 +04:00
we use this when we can ' t do async DNS lookups
1997-10-22 15:02:00 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-08-27 05:25:01 +04:00
2007-10-19 04:40:25 +04:00
bool queue_dns_query ( struct packet_struct * p , struct nmb_name * question )
1997-10-22 15:02:00 +04:00
{
2005-12-07 02:06:38 +03:00
struct name_record * namerec = NULL ;
1997-10-22 15:02:00 +04:00
struct in_addr dns_ip ;
2004-03-16 00:45:45 +03:00
unstring qname ;
2003-08-27 05:25:01 +04:00
2005-12-13 22:37:05 +03:00
pull_ascii_nstring ( qname , sizeof ( qname ) , question - > name ) ;
1997-10-22 15:02:00 +04:00
1998-11-14 04:04:13 +03:00
DEBUG ( 3 , ( " DNS search for %s - " , nmb_namestr ( question ) ) ) ;
1997-10-22 15:02:00 +04:00
dns_ip . s_addr = interpret_addr ( qname ) ;
2005-12-07 02:06:38 +03:00
namerec = add_dns_result ( question , dns_ip ) ;
if ( namerec = = NULL ) {
2003-08-27 05:25:01 +04:00
send_wins_name_query_response ( NAM_ERR , p , NULL ) ;
2005-12-07 02:06:38 +03:00
} else {
send_wins_name_query_response ( 0 , p , namerec ) ;
}
1997-10-22 15:02:00 +04:00
return False ;
}
1998-03-03 23:19:14 +03:00
/***************************************************************************
With sync dns there is no child to kill on SIGTERM .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-08-27 05:25:01 +04:00
1998-04-13 23:24:06 +04:00
void kill_async_dns_child ( void )
1998-03-03 23:19:14 +03:00
{
2003-08-27 05:25:01 +04:00
return ;
1998-03-03 23:19:14 +03:00
}
1997-10-22 15:02:00 +04:00
# endif