2004-04-06 20:35:56 +00:00
|
|
|
/*
|
2004-07-15 15:27:05 +00:00
|
|
|
* DNS plugin. $Id$
|
2004-04-06 20:35:56 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#define IN_PLUGIN
|
2004-04-09 13:05:16 +00:00
|
|
|
#include "../../echoping.h"
|
2004-07-15 15:27:05 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
2004-04-06 20:35:56 +00:00
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/nameser.h>
|
|
|
|
#include <resolv.h>
|
|
|
|
|
|
|
|
struct addrinfo name_server;
|
2004-07-25 20:04:47 +00:00
|
|
|
poptContext dns_poptcon;
|
|
|
|
char *request;
|
|
|
|
int type;
|
|
|
|
char *type_name = NULL;
|
|
|
|
boolean use_tcp = FALSE;
|
|
|
|
boolean no_recurse = FALSE;
|
2004-04-06 20:35:56 +00:00
|
|
|
|
|
|
|
/* 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. *
|
|
|
|
****************************************************************/
|
2004-06-07 09:21:26 +00:00
|
|
|
int
|
2004-07-25 20:04:47 +00:00
|
|
|
nsError (error, domain)
|
|
|
|
int error;
|
|
|
|
char *domain;
|
2004-04-06 20:35:56 +00:00
|
|
|
{
|
2004-07-25 20:04:47 +00:00
|
|
|
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;
|
|
|
|
}
|
2004-04-06 20:35:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2004-07-25 20:04:47 +00:00
|
|
|
dns_usage (const char *msg)
|
2004-04-06 20:35:56 +00:00
|
|
|
{
|
2004-07-27 14:27:37 +00:00
|
|
|
if (msg) {
|
|
|
|
fprintf(stderr, "Error: %s\n", msg);
|
|
|
|
}
|
|
|
|
poptPrintUsage(dns_poptcon, stderr, 0);
|
|
|
|
fprintf(stderr, " request\n");
|
|
|
|
exit(1);
|
2004-04-06 20:35:56 +00:00
|
|
|
}
|
|
|
|
|
2004-07-25 20:04:47 +00:00
|
|
|
char *
|
|
|
|
init (const int argc, const char **argv)
|
2004-04-06 20:35:56 +00:00
|
|
|
{
|
2004-07-25 20:04:47 +00:00
|
|
|
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
|
|
|
|
{
|
2004-07-27 14:27:37 +00:00
|
|
|
upper_type_name = (char *) to_upper (type_name);
|
2004-07-25 20:04:47 +00:00
|
|
|
/*
|
|
|
|
* 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";
|
2004-04-06 20:35:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2004-07-25 20:04:47 +00:00
|
|
|
start (struct addrinfo *res)
|
2004-04-06 20:35:56 +00:00
|
|
|
{
|
2004-07-25 20:04:47 +00:00
|
|
|
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 */
|
2004-07-15 15:27:05 +00:00
|
|
|
#ifdef HAVE_RES_EXT
|
2004-07-25 20:04:47 +00:00
|
|
|
/* Converts a generic sockaddr to an IPv6 sockaddr_in6 */
|
|
|
|
(void) memcpy ((void *) &name_server_sockaddr_in6,
|
|
|
|
&name_server_sockaddr, sizeof (struct sockaddr));
|
2004-07-15 15:27:05 +00:00
|
|
|
#else
|
2004-07-25 20:04:47 +00:00
|
|
|
err_quit
|
|
|
|
("IPv6 name servers not supported on this platform, may be you should use the -4 option");
|
2004-07-15 15:27:05 +00:00
|
|
|
#endif
|
2004-07-25 20:04:47 +00:00
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
2004-07-15 15:27:05 +00:00
|
|
|
#ifdef HAVE_RES_EXT
|
2004-07-27 14:27:37 +00:00
|
|
|
/* TODO: completely broken, dioes not work. Check in Stevens */
|
|
|
|
(void)memcpy(_res_ext.nsaddr_list, &name_server_sockaddr_in6, sizeof(struct sockaddr_in6));
|
2004-07-15 15:27:05 +00:00
|
|
|
#endif
|
2004-07-25 20:04:47 +00:00
|
|
|
}
|
|
|
|
_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;
|
|
|
|
}
|
2004-04-06 20:35:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2004-07-25 20:04:47 +00:00
|
|
|
execute ()
|
2004-04-06 20:35:56 +00:00
|
|
|
{
|
2004-07-25 20:04:47 +00:00
|
|
|
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;
|
2004-04-06 20:35:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2004-07-25 20:04:47 +00:00
|
|
|
terminate ()
|
2004-04-06 20:35:56 +00:00
|
|
|
{
|
|
|
|
}
|