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
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
the Free Software Foundation ; either version 2 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 , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
1997-11-02 04:33:28 +03:00
*/
1997-10-22 15:02:00 +04:00
# include "includes.h"
/***************************************************************************
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 )
{
1997-10-24 02:30:57 +04:00
int name_type = question - > name_type ;
char * qname = question - > name ;
1997-12-13 17:16:07 +03:00
1997-10-24 02:30:57 +04:00
if ( ! addr . s_addr ) {
/* add the fail to WINS cache of names. give it 1 hour in the cache */
1997-12-13 17:16:07 +03:00
DEBUG ( 3 , ( " add_dns_result: Negative DNS answer for %s \n " , qname ) ) ;
1998-06-08 07:44:13 +04:00
( void ) add_name_to_subnet ( wins_server_subnet , qname , name_type ,
NB_ACTIVE , 60 * 60 , DNSFAIL_NAME , 1 , & addr ) ;
return ( NULL ) ;
1997-10-24 02:30:57 +04:00
}
/* add it to our WINS cache of names. give it 2 hours in the cache */
1997-12-13 17:16:07 +03:00
DEBUG ( 3 , ( " add_dns_result: DNS gave answer for %s of %s \n " , qname , inet_ntoa ( addr ) ) ) ;
1997-10-24 02:30:57 +04:00
1998-06-08 07:44:13 +04:00
return ( add_name_to_subnet ( wins_server_subnet , qname , name_type ,
NB_ACTIVE , 2 * 60 * 60 , DNS_NAME , 1 , & addr ) ) ;
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int asyncdns_fd ( void )
{
return fd_in ;
}
/***************************************************************************
handle DNS queries arriving from the parent
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void asyncdns_process ( void )
{
struct query_record r ;
fstring qname ;
1997-11-02 02:42:28 +03:00
DEBUGLEVEL = - 1 ;
1997-10-22 15:02:00 +04:00
while ( 1 ) {
if ( read_data ( fd_in , ( char * ) & r , sizeof ( r ) ) ! = sizeof ( r ) )
break ;
fstrcpy ( qname , r . name . name ) ;
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
{
1997-12-26 12:57:40 +03: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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void start_async_dns ( void )
{
int fd1 [ 2 ] , fd2 [ 2 ] ;
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 ;
}
2000-05-02 06:23:41 +04:00
child_pid = sys_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 ) ;
CatchSignal ( SIGTERM , SIGNAL_CAST sig_term ) ;
1997-12-04 13:58:40 +03:00
1997-10-22 15:02:00 +04:00
asyncdns_process ( ) ;
}
/***************************************************************************
check if a particular name is already being queried
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-11-02 04:25:50 +03: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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL write_child ( struct packet_struct * p )
{
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void run_dns_queue ( void )
{
struct query_record r ;
struct packet_struct * p , * p2 ;
1997-12-13 17:16:07 +03:00
struct name_record * namerec ;
1997-12-04 11:10:49 +03:00
int size ;
1997-10-22 15:02:00 +04:00
if ( fd_in = = - 1 )
return ;
1998-01-29 11:25:46 +03:00
/* Allow SIGTERM to kill us. */
BlockSignals ( False , SIGTERM ) ;
1997-12-04 13:58:40 +03:00
if ( ! process_exists ( child_pid ) ) {
close ( fd_in ) ;
start_async_dns ( ) ;
}
1997-12-04 11:10:49 +03:00
if ( ( size = read_data ( fd_in , ( char * ) & r , sizeof ( r ) ) ) ! = sizeof ( r ) ) {
if ( size ) {
DEBUG ( 0 , ( " Incomplete DNS answer from child! \n " ) ) ;
fd_in = - 1 ;
}
1998-01-29 11:25:46 +03:00
BlockSignals ( True , SIGTERM ) ;
1997-10-22 15:02:00 +04:00
return ;
}
1998-01-29 11:25:46 +03:00
BlockSignals ( True , SIGTERM ) ;
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 ;
1997-12-13 17:16:07 +03: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 ;
1997-12-13 17:16:07 +03: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 ;
if ( p - > prev )
p - > prev - > next = p - > next ;
else
dns_queue = p - > next ;
if ( p - > next )
p - > next - > prev = p - > prev ;
p2 = p - > next ;
free_packet ( p ) ;
p = p2 ;
} else {
p = p - > next ;
}
}
1997-11-02 04:25:50 +03:00
if ( dns_queue ) {
dns_current = dns_queue ;
dns_queue = dns_queue - > next ;
if ( dns_queue ) dns_queue - > prev = NULL ;
dns_current - > next = NULL ;
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL queue_dns_query ( struct packet_struct * p , struct nmb_name * question ,
struct name_record * * n )
{
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 ;
p - > next = dns_queue ;
p - > prev = NULL ;
if ( p - > next )
p - > next - > prev = p ;
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL queue_dns_query ( struct packet_struct * p , struct nmb_name * question ,
struct name_record * * n )
{
char * qname = question - > name ;
struct in_addr dns_ip ;
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
1998-01-29 11:25:46 +03:00
/* Unblock TERM signal so we can be killed in DNS lookup. */
BlockSignals ( False , SIGTERM ) ;
1997-10-22 15:02:00 +04:00
dns_ip . s_addr = interpret_addr ( qname ) ;
1998-01-29 11:25:46 +03:00
/* Re-block TERM signal. */
BlockSignals ( True , SIGTERM ) ;
1997-10-22 15:02:00 +04:00
* n = add_dns_result ( question , dns_ip ) ;
1997-12-13 17:16:07 +03:00
if ( * n = = NULL )
send_wins_name_query_response ( NAM_ERR , p , NULL ) ;
else
send_wins_name_query_response ( 0 , p , * n ) ;
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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-04-13 23:24:06 +04:00
void kill_async_dns_child ( void )
1998-03-03 23:19:14 +03:00
{
return ;
}
1997-10-22 15:02:00 +04:00
# endif