/*
* DNS plugin . $ Id $
*/
# define IN_PLUGIN
# include "../../echoping.h"
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
# include <netinet/in.h>
# include <arpa/nameser.h>
# include <resolv.h>
struct addrinfo name_server ;
poptContext dns_poptcon ;
char * request ;
int type ;
char * type_name = NULL ;
boolean use_tcp = FALSE ;
boolean no_recurse = FALSE ;
/* nsError stolen from Liu & Albitz check_soa (in their book "DNS and BIND") */
/****************************************************************
* nsError - - Print an error message from h_errno for a failure *
* looking up NS records . res_query ( ) converts the DNS *
* packet return code to a smaller list of errors and *
* places the error value in h_errno . There is a routine *
* called herror ( ) for printing out strings from h_errno *
* like perror ( ) does for errno . Unfortunately , the *
* herror ( ) messages assume you are looking up address *
* records for hosts . In this program , we are looking up *
* NS records for domains , so we need our own list of error *
* strings . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int
nsError ( error , domain )
int error ;
char * domain ;
{
switch ( error )
{
case HOST_NOT_FOUND :
err_ret ( " Unknown domain: %s \n " , domain ) ;
return - 1 ;
case NO_DATA :
err_ret ( " No records of type %s for %s in the Answer section \n " ,
to_upper ( type_name ) , domain ) ;
return - 1 ;
case TRY_AGAIN :
err_ret ( " No response for query \n " ) ;
return - 2 ;
default :
err_ret ( " Unexpected error \n " ) ;
return - 1 ;
}
}
void
dns_usage ( const char * msg )
{
if ( msg ) {
fprintf ( stderr , " Error: %s \n " , msg ) ;
}
poptPrintUsage ( dns_poptcon , stderr , 0 ) ;
fprintf ( stderr , " request \n " ) ;
exit ( 1 ) ;
}
char *
init ( const int argc , const char * * argv )
{
int value ;
char * hostname ;
char * msg = malloc ( 256 ) ;
char * upper_type_name = NULL ;
/* popt variables */
struct poptOption options [ ] = {
{ " type " , ' t ' , POPT_ARG_STRING , & type_name , 0 ,
" Type of resources queried (A, MX, SOA, etc) " ,
" type " } ,
{ " tcp " , NULL , POPT_ARG_NONE , & use_tcp , 0 ,
" Use TCP for the request (virtual circuit) " ,
" tcp " } ,
{ " no-recurse " , NULL , POPT_ARG_NONE , & no_recurse , 0 ,
" Do not ask recursion " ,
" no-recurse " } ,
POPT_AUTOHELP POPT_TABLEEND
} ;
dns_poptcon = poptGetContext ( NULL , argc ,
argv , options , POPT_CONTEXT_KEEP_FIRST ) ;
while ( ( value = poptGetNextOpt ( dns_poptcon ) ) > 0 )
{
}
if ( value < - 1 )
{
sprintf ( msg , " %s: %s " ,
poptBadOption ( dns_poptcon , POPT_BADOPTION_NOALIAS ) ,
poptStrerror ( value ) ) ;
dns_usage ( msg ) ;
}
hostname = ( char * ) poptGetArg ( dns_poptcon ) ; /* Not used */
request = ( char * ) poptGetArg ( dns_poptcon ) ;
if ( request = = NULL )
dns_usage ( " Mandatory request missing " ) ;
if ( ( type_name = = NULL ) | | ! strcmp ( type_name , " " ) )
{
type = T_A ;
type_name = " A " ;
}
else
{
upper_type_name = ( char * ) to_upper ( type_name ) ;
/*
* TODO : a better algorithm . Use dns_rdatatype_fromtext in
* BIND ?
*/
if ( ! strcmp ( upper_type_name , " A " ) )
type = T_A ;
else if ( ! strcmp ( upper_type_name , " AAAA " ) )
type = T_AAAA ;
else if ( ! strcmp ( upper_type_name , " NS " ) )
type = T_NS ;
else if ( ! strcmp ( upper_type_name , " SOA " ) )
type = T_SOA ;
else if ( ! strcmp ( upper_type_name , " MX " ) )
type = T_MX ;
else if ( ! strcmp ( upper_type_name , " SRV " ) )
type = T_SRV ;
else if ( ! strcmp ( upper_type_name , " CNAME " ) )
type = T_CNAME ;
else if ( ! strcmp ( upper_type_name , " PTR " ) )
type = T_PTR ;
else if ( ! strcmp ( upper_type_name , " TXT " ) )
type = T_TXT ;
else if ( ! strcmp ( upper_type_name , " ANY " ) )
type = T_ANY ;
else
dns_usage ( " Unknown type " ) ;
}
return " domain " ;
}
void
start ( struct addrinfo * res )
{
struct sockaddr name_server_sockaddr ;
struct sockaddr_in name_server_sockaddr_in ;
struct sockaddr_in6 name_server_sockaddr_in6 ;
name_server = * res ;
name_server_sockaddr = * name_server . ai_addr ;
if ( name_server_sockaddr . sa_family = = AF_INET )
{
/* Converts a generic sockaddr to an IPv4 sockaddr_in */
( void ) memcpy ( ( void * ) & name_server_sockaddr_in , & name_server_sockaddr ,
sizeof ( struct sockaddr ) ) ;
}
else if ( name_server_sockaddr . sa_family = = AF_INET6 )
{
/* TODO: the code for IPv6 servers is hopelessly broken. Start again */
fprintf ( stderr , " WARNING: IPv6 nameservers not really supported yet (experts may apply). Falling back to IPv4 and the default server. You may use -4, too \n " ) ;
# ifdef HAVE_RES_EXT
/* Converts a generic sockaddr to an IPv6 sockaddr_in6 */
( void ) memcpy ( ( void * ) & name_server_sockaddr_in6 ,
& name_server_sockaddr , sizeof ( struct sockaddr ) ) ;
# else
err_quit
( " IPv6 name servers not supported on this platform, may be you should use the -4 option " ) ;
# endif
}
else
{
err_quit ( " Unknown family for address of the server " ) ;
}
if ( res_init ( ) < 0 )
err_sys ( " res_init " ) ;
if ( name_server_sockaddr . sa_family = = AF_INET )
{
_res . nsaddr_list [ 0 ] = name_server_sockaddr_in ;
}
else if ( name_server_sockaddr . sa_family = = AF_INET6 )
{
# ifdef HAVE_RES_EXT
/* TODO: completely broken, dioes not work. Check in Stevens */
( void ) memcpy ( _res_ext . nsaddr_list , & name_server_sockaddr_in6 , sizeof ( struct sockaddr_in6 ) ) ;
# endif
}
_res . nscount = 1 ;
_res . options & = ~ ( RES_DNSRCH | RES_DEFNAMES | RES_NOALIASES ) ;
if ( use_tcp )
{
_res . options | = RES_USEVC ;
}
if ( no_recurse )
{
_res . options & = ~ RES_RECURSE ;
}
}
int
execute ( )
{
union
{
HEADER hdr ; /* defined in resolv.h */
u_char buf [ PACKETSZ ] ; /* defined in arpa/nameser.h */
} response ; /* response buffers */
int response_length ; /* buffer length */
if ( ( response_length = res_query ( request , /* the domain we care
* about */
C_IN , /* Internet class records */
type , ( u_char * ) & response , /* response buffer */
sizeof ( response ) ) ) /* buffer size */
< 0 )
{ /* If negative */
nsError ( h_errno , request ) ; /* report the error */
if ( h_errno = = TRY_AGAIN )
return - 1 ; /* More luck next time? */
else
return - 2 ; /* Give in */
}
/*
* TODO : better analysis of the replies . For instance , replies can be
* in the authority section ( delegation info )
*/
return 0 ;
}
void
terminate ( )
{
}