1414 lines
33 KiB
C
1414 lines
33 KiB
C
#ifndef lint
|
|
static char rcsid[] = "$Id: host.c,v 1.4 1999/06/30 12:27:34 itojun Exp $";
|
|
#endif /* not lint */
|
|
|
|
/*
|
|
* Copyright (c) 1986
|
|
* The Regents of the University of California. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the University of
|
|
* California, Berkeley and its contributors.
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
/*
|
|
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies, and that
|
|
* the name of Digital Equipment Corporation not be used in advertising or
|
|
* publicity pertaining to distribution of the document or software without
|
|
* specific, written prior permission.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
|
|
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
|
|
* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
|
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
|
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
|
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
/*
|
|
* Portions Copyright (c) 1996 by Internet Software Consortium
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
|
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
|
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
|
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
|
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
|
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
#ifndef lint
|
|
static const char copyright[] =
|
|
"@(#) Copyright (c) 1986 Regents of the University of California.\n\
|
|
Portions Copyright (c) 1993 Digital Equipment Corporation.\n\
|
|
Portions Copyright (c) 1996 Internet Software Consortium.\n\
|
|
All rights reserved.\n";
|
|
#endif /* not lint */
|
|
|
|
/*
|
|
* Actually, this program is from Rutgers University, however it is
|
|
* based on nslookup and other pieces of named tools, so it needs
|
|
* the above copyright notices.
|
|
*/
|
|
|
|
/* Import. */
|
|
|
|
#include "port_before.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <arpa/nameser.h>
|
|
|
|
#include <ctype.h>
|
|
#include <netdb.h>
|
|
#include <resolv.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "port_after.h"
|
|
|
|
extern int h_errno;
|
|
extern char *_res_resultcodes[];
|
|
|
|
/* Global. */
|
|
|
|
#define NUMNS 8
|
|
#define NUMNSADDR 16
|
|
#define NUMMX 50
|
|
|
|
#define SUCCESS 0
|
|
#define TIME_OUT -1
|
|
#define NO_INFO -2
|
|
#define ERROR -3
|
|
#define NONAUTH -4
|
|
|
|
typedef union {
|
|
HEADER qb1;
|
|
u_char qb2[NS_PACKETSZ];
|
|
} querybuf;
|
|
|
|
static char cnamebuf[NS_MAXDNAME];
|
|
static u_char hostbuf[NS_MAXDNAME];
|
|
|
|
static int sockFD;
|
|
static FILE *filePtr;
|
|
|
|
static struct __res_state orig;
|
|
static char *cname = NULL;
|
|
static int getclass = ns_c_in, verbose = 0, list = 0;
|
|
static int server_specified = 0;
|
|
static int gettype;
|
|
|
|
/* Forward. */
|
|
|
|
static int parsetype(const char *s);
|
|
static int parseclass(const char *s);
|
|
static void printanswer(const struct hostent *hp);
|
|
static void hperror(int errnum);
|
|
static int get_addrinfo(struct in_addr addr);
|
|
static int gethostinfo(char *name);
|
|
static int getdomaininfo(const char *name, const char *domain);
|
|
static int getinfo(const char *name, const char *domain,
|
|
int type);
|
|
static int printinfo(const querybuf *answer, const u_char *eom,
|
|
int filter, int isls);
|
|
static const u_char * pr_rr(const u_char *cp, const u_char *msg, FILE *file,
|
|
int filter);
|
|
static const char * pr_type(int type);
|
|
static const char * pr_class(int class);
|
|
static const u_char * pr_cdname(const u_char *cp, const u_char *msg,
|
|
char *name, int namelen);
|
|
static int ListHosts(char *namePtr, int queryType);
|
|
static const char * DecodeError(int result);
|
|
|
|
/* Public. */
|
|
|
|
int
|
|
main(int c, char **v) {
|
|
struct in_addr addr;
|
|
struct hostent *hp;
|
|
char *s, *oldcname;
|
|
int inverse = 0, waitmode = 0;
|
|
int ncnames;
|
|
|
|
res_init();
|
|
_res.retrans = 5;
|
|
|
|
if (c < 2) {
|
|
fprintf(stderr, "Usage: host [-w] [-v] [-r] [-d] [-t querytype] [-c class] [-a] host [server]\n -w to wait forever until reply\n -v for verbose output\n -r to disable recursive processing\n -d to turn on debugging output\n -t querytype to look for a specific type of information\n -c class to look for non-Internet data\n -a is equivalent to '-v -t *'\n");
|
|
exit(1);
|
|
}
|
|
while (c > 2 && v[1][0] == '-') {
|
|
if (strcmp (v[1], "-w") == 0) {
|
|
_res.retry = 1;
|
|
_res.retrans = 15;
|
|
waitmode = 1;
|
|
v++;
|
|
c--;
|
|
}
|
|
else if (strcmp (v[1], "-r") == 0) {
|
|
_res.options &= ~RES_RECURSE;
|
|
v++;
|
|
c--;
|
|
}
|
|
else if (strcmp (v[1], "-d") == 0) {
|
|
_res.options |= RES_DEBUG;
|
|
v++;
|
|
c--;
|
|
}
|
|
else if (strcmp (v[1], "-v") == 0) {
|
|
verbose = 1;
|
|
v++;
|
|
c--;
|
|
}
|
|
else if (strcmp (v[1], "-l") == 0) {
|
|
list = 1;
|
|
v++;
|
|
c--;
|
|
}
|
|
else if (strncmp (v[1], "-t", 2) == 0) {
|
|
v++;
|
|
c--;
|
|
gettype = parsetype(v[1]);
|
|
v++;
|
|
c--;
|
|
}
|
|
else if (strncmp (v[1], "-c", 2) == 0) {
|
|
v++;
|
|
c--;
|
|
getclass = parseclass(v[1]);
|
|
v++;
|
|
c--;
|
|
}
|
|
else if (strcmp (v[1], "-a") == 0) {
|
|
verbose = 1;
|
|
gettype = ns_t_any;
|
|
v++;
|
|
c--;
|
|
}
|
|
}
|
|
if (c > 2) {
|
|
s = v[2];
|
|
server_specified++;
|
|
|
|
if (!inet_aton(s, &addr)) {
|
|
hp = gethostbyname(s);
|
|
if (hp == NULL) {
|
|
fprintf(stderr,
|
|
"Error in looking up server name:\n");
|
|
hperror(h_errno);
|
|
exit(1);
|
|
}
|
|
memcpy(&_res.nsaddr.sin_addr, hp->h_addr, NS_INADDRSZ);
|
|
printf("Using domain server:\n");
|
|
printanswer(hp);
|
|
} else {
|
|
_res.nsaddr.sin_family = AF_INET;
|
|
_res.nsaddr.sin_addr = addr;
|
|
_res.nsaddr.sin_port = htons(NAMESERVER_PORT);
|
|
printf("Using domain server %s:\n",
|
|
inet_ntoa(_res.nsaddr.sin_addr));
|
|
}
|
|
_res.nscount = 1;
|
|
_res.retry = 2;
|
|
}
|
|
if (strcmp(v[1], ".") == 0 || !inet_aton(v[1], &addr))
|
|
addr.s_addr = INADDR_NONE;
|
|
hp = NULL;
|
|
h_errno = TRY_AGAIN;
|
|
/*
|
|
* We handle default domains ourselves, thank you.
|
|
*/
|
|
_res.options &= ~RES_DEFNAMES;
|
|
|
|
if (list)
|
|
exit(ListHosts(v[1], gettype ? gettype : ns_t_a));
|
|
oldcname = NULL;
|
|
ncnames = 5;
|
|
while (hp == NULL && h_errno == TRY_AGAIN) {
|
|
if (addr.s_addr == INADDR_NONE) {
|
|
typedef unsigned long uL;
|
|
|
|
cname = NULL;
|
|
if (oldcname == NULL)
|
|
hp = (struct hostent *)(uL)gethostinfo(v[1]);
|
|
else
|
|
hp = (struct hostent *)(uL)gethostinfo(oldcname);
|
|
if (cname) {
|
|
if (ncnames-- == 0) {
|
|
printf("Too many cnames. Loop?\n");
|
|
exit(1);
|
|
}
|
|
strcat(cname, ".");
|
|
oldcname = cname;
|
|
hp = NULL;
|
|
h_errno = TRY_AGAIN;
|
|
continue;
|
|
}
|
|
} else {
|
|
if (get_addrinfo(addr) == 0)
|
|
hp = NULL;
|
|
else
|
|
hp = (struct hostent *)1; /* XXX */
|
|
}
|
|
if (!waitmode)
|
|
break;
|
|
}
|
|
|
|
if (hp == NULL) {
|
|
hperror(h_errno);
|
|
exit(1);
|
|
}
|
|
|
|
exit(0);
|
|
}
|
|
|
|
/* Private. */
|
|
|
|
static int
|
|
parsetype(const char *s) {
|
|
int type, success;
|
|
|
|
type = sym_ston(__p_type_syms, s, &success);
|
|
if (success)
|
|
return (type);
|
|
if (strcmp(s, "*") == 0)
|
|
return (ns_t_any);
|
|
if (atoi(s))
|
|
return (atoi(s));
|
|
fprintf(stderr, "Invalid query type: %s\n", s);
|
|
exit(2);
|
|
}
|
|
|
|
static int
|
|
parseclass(const char *s) {
|
|
int class, success;
|
|
|
|
class = sym_ston(__p_class_syms, s, &success);
|
|
if (success)
|
|
return (class);
|
|
if (atoi(s))
|
|
return (atoi(s));
|
|
fprintf(stderr, "Invalid query class: %s\n", s);
|
|
exit(2);
|
|
}
|
|
|
|
static void
|
|
printanswer(const struct hostent *hp) {
|
|
struct in_addr **hptr;
|
|
char **cp;
|
|
|
|
printf("Name: %s\n", hp->h_name);
|
|
printf("Address:");
|
|
for (hptr = (struct in_addr **)hp->h_addr_list; *hptr; hptr++)
|
|
printf(" %s", inet_ntoa(**hptr));
|
|
printf("\nAliases:");
|
|
for (cp = hp->h_aliases; cp && *cp && **cp; cp++)
|
|
printf(" %s", *cp);
|
|
printf("\n\n");
|
|
}
|
|
|
|
static void
|
|
hperror(int errnum) {
|
|
switch(errnum) {
|
|
case HOST_NOT_FOUND:
|
|
fprintf(stderr, "Host not found.\n");
|
|
break;
|
|
case TRY_AGAIN:
|
|
fprintf(stderr, "Host not found, try again.\n");
|
|
break;
|
|
case NO_RECOVERY:
|
|
fprintf(stderr, "No recovery, Host not found.\n");
|
|
break;
|
|
case NO_ADDRESS:
|
|
fprintf(stderr,
|
|
"There is an entry for this host, but it doesn't have "
|
|
);
|
|
switch (gettype) {
|
|
case ns_t_a:
|
|
fprintf(stderr, "an Internet address.\n");
|
|
break;
|
|
case ns_t_ns:
|
|
fprintf(stderr, "a Name Server.\n");
|
|
break;
|
|
case ns_t_md:
|
|
fprintf(stderr, "a Mail Destination.\n");
|
|
break;
|
|
case ns_t_mf:
|
|
fprintf(stderr, "a Mail Forwarder.\n");
|
|
break;
|
|
case ns_t_cname:
|
|
fprintf(stderr, "a Canonical Name.\n");
|
|
break;
|
|
case ns_t_soa:
|
|
fprintf(stderr, "a Start of Authority record.\n");
|
|
break;
|
|
case ns_t_mb:
|
|
fprintf(stderr, "a Mailbox Domain Name.\n");
|
|
break;
|
|
case ns_t_mg:
|
|
fprintf(stderr, "a Mail Group Member.\n");
|
|
break;
|
|
case ns_t_mr:
|
|
fprintf(stderr, "a Mail Rename Name.\n");
|
|
break;
|
|
case ns_t_null:
|
|
fprintf(stderr, "a Null Resource record.\n");
|
|
break;
|
|
case ns_t_wks:
|
|
fprintf(stderr, "any Well Known Service information.\n");
|
|
break;
|
|
case ns_t_ptr:
|
|
fprintf(stderr, "a Pointer record.\n");
|
|
break;
|
|
case ns_t_hinfo:
|
|
fprintf(stderr, "any Host Information.\n");
|
|
break;
|
|
case ns_t_minfo:
|
|
fprintf(stderr, "any Mailbox Information.\n");
|
|
break;
|
|
case ns_t_mx:
|
|
fprintf(stderr, "a Mail Exchanger record.\n");
|
|
break;
|
|
case ns_t_txt:
|
|
fprintf(stderr, "a Text record.\n");
|
|
break;
|
|
case ns_t_rp:
|
|
fprintf(stderr, "a Responsible Person.\n");
|
|
break;
|
|
case ns_t_srv:
|
|
fprintf(stderr, "a Server Selector.\n");
|
|
break;
|
|
case ns_t_naptr:
|
|
fprintf(stderr, "a URN Naming Authority.\n");
|
|
break;
|
|
default:
|
|
fprintf(stderr, "the information you requested.\n");
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int
|
|
get_addrinfo(struct in_addr addr) {
|
|
u_int32_t ha = ntohl(addr.s_addr);
|
|
char name[NS_MAXDNAME];
|
|
|
|
sprintf(name, "%u.%u.%u.%u.IN-ADDR.ARPA.",
|
|
(ha) & 0xff,
|
|
(ha >> 8) & 0xff,
|
|
(ha >> 16) & 0xff,
|
|
(ha >> 24) & 0xff);
|
|
return (getinfo(name, NULL, ns_t_ptr));
|
|
}
|
|
|
|
static int
|
|
gethostinfo(char *name) {
|
|
char *cp, **domain;
|
|
const char *tp;
|
|
int hp, nDomain;
|
|
int asis = 0;
|
|
u_int n;
|
|
|
|
if (strcmp(name, ".") == 0)
|
|
return (getdomaininfo(name, NULL));
|
|
for (cp = name, n = 0; *cp; cp++)
|
|
if (*cp == '.')
|
|
n++;
|
|
if (n && cp[-1] == '.') {
|
|
if (cp[-1] == '.')
|
|
cp[-1] = 0;
|
|
hp = getdomaininfo(name, (char *)NULL);
|
|
if (cp[-1] == 0)
|
|
cp[-1] = '.';
|
|
return (hp);
|
|
}
|
|
if (n == 0 && (tp = hostalias(name))) {
|
|
if (verbose)
|
|
printf("Aliased to \"%s\"\n", tp);
|
|
_res.options |= RES_DEFNAMES;
|
|
return (getdomaininfo(tp, (char *)NULL));
|
|
}
|
|
if (n >= _res.ndots) {
|
|
asis = 1;
|
|
if (verbose)
|
|
printf("Trying null domain\n");
|
|
hp = getdomaininfo(name, (char*)NULL);
|
|
if (hp)
|
|
return (hp);
|
|
}
|
|
for (domain = _res.dnsrch; *domain; domain++) {
|
|
if (verbose)
|
|
printf("Trying domain \"%s\"\n", *domain);
|
|
hp = getdomaininfo(name, *domain);
|
|
if (hp)
|
|
return (hp);
|
|
}
|
|
if (h_errno != HOST_NOT_FOUND || (_res.options & RES_DNSRCH) == 0)
|
|
return (0);
|
|
if (!asis)
|
|
return (0);
|
|
if (verbose)
|
|
printf("Trying null domain\n");
|
|
return (getdomaininfo(name, (char *)NULL));
|
|
}
|
|
|
|
static int
|
|
getdomaininfo(const char *name, const char *domain) {
|
|
int val1, val2;
|
|
|
|
if (gettype)
|
|
return (getinfo(name, domain, gettype));
|
|
else {
|
|
val1 = getinfo(name, domain, ns_t_a);
|
|
if (cname || verbose)
|
|
return (val1);
|
|
val2 = getinfo(name, domain, ns_t_mx);
|
|
return (val1 || val2);
|
|
}
|
|
}
|
|
|
|
static int
|
|
getinfo(const char *name, const char *domain, int type) {
|
|
HEADER *hp;
|
|
u_char *eom, *bp, *cp;
|
|
querybuf buf, answer;
|
|
int n, n1, i, j, nmx, ancount, nscount, arcount, qdcount, buflen;
|
|
u_short pref, class;
|
|
char host[NS_MAXDNAME];
|
|
|
|
if (domain == NULL)
|
|
sprintf(host, "%.*s", NS_MAXDNAME, name);
|
|
else
|
|
sprintf(host, "%.*s.%.*s",
|
|
NS_MAXDNAME, name, NS_MAXDNAME, domain);
|
|
|
|
n = res_mkquery(QUERY, host, getclass, type, NULL, 0, NULL,
|
|
buf.qb2, sizeof buf);
|
|
if (n < 0) {
|
|
if (_res.options & RES_DEBUG)
|
|
printf("res_mkquery failed\n");
|
|
h_errno = NO_RECOVERY;
|
|
return (0);
|
|
}
|
|
n = res_send(buf.qb2, n, answer.qb2, sizeof answer);
|
|
if (n < 0) {
|
|
if (_res.options & RES_DEBUG)
|
|
printf("res_send failed\n");
|
|
h_errno = TRY_AGAIN;
|
|
return (0);
|
|
}
|
|
eom = answer.qb2 + n;
|
|
return (printinfo(&answer, eom, ns_t_any, 0));
|
|
}
|
|
|
|
static int
|
|
printinfo(const querybuf *answer, const u_char *eom, int filter, int isls) {
|
|
int n, n1, i, j, nmx, ancount, nscount, arcount, qdcount, buflen;
|
|
u_short pref, class;
|
|
const u_char *bp, *cp;
|
|
const HEADER *hp;
|
|
|
|
/*
|
|
* Find first satisfactory answer.
|
|
*/
|
|
hp = (HEADER *) answer;
|
|
ancount = ntohs(hp->ancount);
|
|
qdcount = ntohs(hp->qdcount);
|
|
nscount = ntohs(hp->nscount);
|
|
arcount = ntohs(hp->arcount);
|
|
if (_res.options & RES_DEBUG || (verbose && isls == 0))
|
|
printf("rcode = %d (%s), ancount=%d\n",
|
|
hp->rcode, DecodeError(hp->rcode), ancount);
|
|
if (hp->rcode != NOERROR || (ancount+nscount+arcount) == 0) {
|
|
switch (hp->rcode) {
|
|
case NXDOMAIN:
|
|
h_errno = HOST_NOT_FOUND;
|
|
return (0);
|
|
case SERVFAIL:
|
|
h_errno = TRY_AGAIN;
|
|
return (0);
|
|
case NOERROR:
|
|
h_errno = NO_DATA;
|
|
return (0);
|
|
case FORMERR:
|
|
case NOTIMP:
|
|
case REFUSED:
|
|
h_errno = NO_RECOVERY;
|
|
return (0);
|
|
}
|
|
return (0);
|
|
}
|
|
bp = hostbuf;
|
|
nmx = 0;
|
|
buflen = sizeof(hostbuf);
|
|
cp = answer->qb2 + HFIXEDSZ;
|
|
if (qdcount > 0) {
|
|
while (qdcount-- > 0) {
|
|
n = dn_skipname(cp, eom);
|
|
if (n < 0) {
|
|
printf("Form error.\n");
|
|
return (0);
|
|
}
|
|
cp += n + QFIXEDSZ;
|
|
if (cp > eom) {
|
|
printf("Form error.\n");
|
|
return (0);
|
|
}
|
|
}
|
|
}
|
|
if (ancount) {
|
|
if (!hp->aa)
|
|
if (verbose && isls == 0)
|
|
printf(
|
|
"The following answer is not authoritative:\n"
|
|
);
|
|
while (--ancount >= 0 && cp && cp < eom) {
|
|
cp = pr_rr(cp, answer->qb2, stdout, filter);
|
|
/*
|
|
* When we ask for address and there is a CNAME, it
|
|
* seems to return both the CNAME and the address.
|
|
* Since we trace down the CNAME chain ourselves, we
|
|
* don't really want to print the address at this
|
|
* point.
|
|
*/
|
|
if (cname && ! verbose)
|
|
return (1);
|
|
}
|
|
}
|
|
if (!verbose)
|
|
return (1);
|
|
if (nscount) {
|
|
printf("For authoritative answers, see:\n");
|
|
while (--nscount >= 0 && cp && cp < eom)
|
|
cp = (u_char *)pr_rr(cp, answer->qb2, stdout, filter);
|
|
}
|
|
if (arcount) {
|
|
printf("Additional information:\n");
|
|
while (--arcount >= 0 && cp && cp < eom)
|
|
cp = (u_char *)pr_rr(cp, answer->qb2, stdout, filter);
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* Print resource record fields in human readable form.
|
|
*/
|
|
static const u_char *
|
|
pr_rr(const u_char *cp, const u_char *msg, FILE *file, int filter) {
|
|
int type, class, dlen, n, c, proto, ttl;
|
|
struct in_addr inaddr;
|
|
u_char in6addr[NS_IN6ADDRSZ];
|
|
const u_char *cp1;
|
|
struct protoent *protop;
|
|
struct servent *servp;
|
|
char punc = ' ';
|
|
int doprint;
|
|
char name[NS_MAXDNAME];
|
|
char tmpbuf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
|
|
|
|
if ((cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name))) == NULL)
|
|
return (NULL); /* compression error */
|
|
|
|
type = ns_get16(cp);
|
|
cp += INT16SZ;
|
|
|
|
class = ns_get16(cp);
|
|
cp += INT16SZ;
|
|
|
|
ttl = ns_get32(cp);
|
|
cp += INT32SZ;
|
|
|
|
if (filter == type || filter == ns_t_any ||
|
|
(filter == ns_t_a && (type == ns_t_ptr || type == ns_t_ns)))
|
|
doprint = 1;
|
|
else
|
|
doprint = 0;
|
|
|
|
if (doprint) {
|
|
if (verbose)
|
|
fprintf(file, "%s\t%d%s\t%s",
|
|
name, ttl, pr_class(class), pr_type(type));
|
|
else
|
|
fprintf(file, "%s%s %s",
|
|
name, pr_class(class), pr_type(type));
|
|
if (verbose)
|
|
punc = '\t';
|
|
else
|
|
punc = ' ';
|
|
}
|
|
dlen = ns_get16(cp);
|
|
cp += INT16SZ;
|
|
cp1 = cp;
|
|
|
|
/*
|
|
* Print type specific data, if appropriate.
|
|
*/
|
|
switch (type) {
|
|
case ns_t_a:
|
|
memcpy(&inaddr, cp, NS_INADDRSZ);
|
|
if (doprint)
|
|
fprintf(file,"%c%s", punc, inet_ntoa(inaddr));
|
|
cp += dlen;
|
|
break;
|
|
case ns_t_aaaa:
|
|
memcpy(in6addr, cp, NS_IN6ADDRSZ);
|
|
if (doprint) {
|
|
if (inet_ntop(AF_INET6, in6addr, tmpbuf,
|
|
sizeof tmpbuf) != NULL)
|
|
fprintf(file,"%c%s", punc, tmpbuf);
|
|
else
|
|
fprintf(file,"%c???", punc);
|
|
}
|
|
cp += dlen;
|
|
break;
|
|
case ns_t_cname:
|
|
if (dn_expand(msg, msg + 512, cp, cnamebuf,
|
|
sizeof(cnamebuf)) >= 0)
|
|
cname = cnamebuf;
|
|
case ns_t_mb:
|
|
case ns_t_mg:
|
|
case ns_t_mr:
|
|
case ns_t_ns:
|
|
case ns_t_ptr:
|
|
cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name));
|
|
if (doprint)
|
|
fprintf(file,"%c%s",punc, name);
|
|
break;
|
|
|
|
case ns_t_hinfo:
|
|
case ns_t_isdn:
|
|
{
|
|
const u_char *cp2 = cp + dlen;
|
|
n = *cp++;
|
|
if (n != 0) {
|
|
if (doprint)
|
|
fprintf(file,"%c%.*s", punc, n, cp);
|
|
cp += n;
|
|
}
|
|
if ((cp < cp2) && (n = *cp++)) {
|
|
if (doprint)
|
|
fprintf(file,"%c%.*s", punc, n, cp);
|
|
cp += n;
|
|
} else if (type == ns_t_hinfo)
|
|
if (doprint)
|
|
fprintf(file,
|
|
"\n; *** Warning *** OS-type missing"
|
|
);
|
|
}
|
|
break;
|
|
|
|
case ns_t_soa:
|
|
cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name));
|
|
if (doprint)
|
|
fprintf(file, "\t%s", name);
|
|
cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name));
|
|
if (doprint)
|
|
fprintf(file, " %s", name);
|
|
if (doprint)
|
|
fprintf(file, "(\n\t\t\t%ld\t;serial (version)",
|
|
ns_get32(cp));
|
|
cp += INT32SZ;
|
|
if (doprint)
|
|
fprintf(file, "\n\t\t\t%ld\t;refresh period",
|
|
ns_get32(cp));
|
|
cp += INT32SZ;
|
|
if (doprint)
|
|
fprintf(file,
|
|
"\n\t\t\t%ld\t;retry refresh this often",
|
|
ns_get32(cp));
|
|
cp += INT32SZ;
|
|
if (doprint)
|
|
fprintf(file, "\n\t\t\t%ld\t;expiration period",
|
|
ns_get32(cp));
|
|
cp += INT32SZ;
|
|
if (doprint)
|
|
fprintf(file, "\n\t\t\t%ld\t;minimum TTL\n\t\t\t)",
|
|
ns_get32(cp));
|
|
cp += INT32SZ;
|
|
break;
|
|
|
|
case ns_t_mx:
|
|
case ns_t_afsdb:
|
|
case ns_t_rt:
|
|
if (doprint) {
|
|
if (type == ns_t_mx && !verbose)
|
|
fprintf(file," (pri=%d) by ", ns_get16(cp));
|
|
else if (verbose)
|
|
fprintf(file,"\t%d ", ns_get16(cp));
|
|
else
|
|
fprintf(file," ");
|
|
}
|
|
cp += sizeof(u_short);
|
|
cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name));
|
|
if (doprint)
|
|
fprintf(file, "%s", name);
|
|
break;
|
|
|
|
case ns_t_srv:
|
|
if (doprint)
|
|
fprintf(file," %d", ns_get16(cp));
|
|
cp += sizeof(u_short);
|
|
if (doprint)
|
|
fprintf(file," %d", ns_get16(cp));
|
|
cp += sizeof(u_short);
|
|
if (doprint)
|
|
fprintf(file," %d", ns_get16(cp));
|
|
cp += sizeof(u_short);
|
|
cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name));
|
|
if (doprint)
|
|
fprintf(file,"%s",name);
|
|
break;
|
|
|
|
case ns_t_naptr:
|
|
/* order */
|
|
if (doprint)
|
|
fprintf(file, " %d", ns_get16(cp));
|
|
cp += sizeof(u_short);
|
|
/* preference */
|
|
if (doprint)
|
|
fprintf(file, " %d", ns_get16(cp));
|
|
cp += NS_INT16SZ;
|
|
/* Flags */
|
|
n = *cp++;
|
|
if (doprint) {
|
|
if (n)
|
|
fprintf(file, "%c%.*s", punc, n, cp);
|
|
else
|
|
fprintf(file, "%c\"\"",punc);
|
|
}
|
|
cp += n;
|
|
/* Service */
|
|
n = *cp++;
|
|
if (doprint) {
|
|
if (n)
|
|
fprintf(file, "%c%.*s", punc, n, cp);
|
|
else
|
|
fprintf(file,"%c\"\"",punc);
|
|
}
|
|
cp += n;
|
|
/* Regexp */
|
|
n = *cp++;
|
|
if (doprint) {
|
|
if (n)
|
|
fprintf(file, "%c%.*s", punc, n, cp);
|
|
else
|
|
fprintf(file, "%c\"\"",punc);
|
|
}
|
|
cp += n;
|
|
/* replacement */
|
|
cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name));
|
|
if (doprint)
|
|
fprintf(file, "%s", name);
|
|
break;
|
|
|
|
case ns_t_minfo:
|
|
case ns_t_rp:
|
|
cp = (u_char *)pr_cdname(cp, msg, name, sizeof name);
|
|
if (doprint) {
|
|
if (type == ns_t_rp) {
|
|
char *p;
|
|
|
|
p = strchr(name, '.');
|
|
if (p != NULL)
|
|
*p = '@';
|
|
}
|
|
fprintf(file, "%c%s", punc, name);
|
|
}
|
|
cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name));
|
|
if (doprint)
|
|
fprintf(file, " %s", name);
|
|
break;
|
|
|
|
case ns_t_x25:
|
|
n = *cp++;
|
|
if (n != 0) {
|
|
if (doprint)
|
|
fprintf(file, "%c%.*s", punc, n, cp);
|
|
cp += n;
|
|
}
|
|
break;
|
|
|
|
case ns_t_txt:
|
|
{
|
|
int n, j;
|
|
const u_char *end = cp + dlen;
|
|
|
|
while (cp < end) {
|
|
if (doprint)
|
|
(void) fputs(" \"", file);
|
|
n = *cp++;
|
|
if (n != 0)
|
|
for (j = n; j > 0 && cp < end ; j --) {
|
|
if (doprint) {
|
|
if (*cp == '\n' ||
|
|
*cp == '"' ||
|
|
*cp == '\\')
|
|
putc('\\',
|
|
file);
|
|
putc(*cp, file);
|
|
}
|
|
cp++;
|
|
}
|
|
if (doprint)
|
|
putc('"', file);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ns_t_wks:
|
|
if (dlen < INT32SZ + 1)
|
|
break;
|
|
memcpy(&inaddr, cp, INADDRSZ);
|
|
cp += INT32SZ;
|
|
proto = *cp++;
|
|
protop = getprotobynumber(proto);
|
|
if (doprint) {
|
|
if (protop)
|
|
fprintf(file, "%c%s %s", punc,
|
|
inet_ntoa(inaddr), protop->p_name);
|
|
else
|
|
fprintf(file, "%c%s %d", punc,
|
|
inet_ntoa(inaddr), proto);
|
|
}
|
|
n = 0;
|
|
while (cp < cp1 + dlen) {
|
|
c = *cp++;
|
|
do {
|
|
if (c & 0200) {
|
|
servp = NULL;
|
|
if (protop)
|
|
servp = getservbyport(htons(n),
|
|
protop->
|
|
p_name);
|
|
if (doprint) {
|
|
if (servp)
|
|
fprintf(file, " %s",
|
|
servp->s_name);
|
|
else
|
|
fprintf(file, " %d",
|
|
n);
|
|
}
|
|
}
|
|
c <<= 1;
|
|
} while (++n & 07);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if (doprint)
|
|
fprintf(file, "%c???", punc);
|
|
cp += dlen;
|
|
break;
|
|
}
|
|
if (cp != cp1 + dlen)
|
|
fprintf(file, "packet size error (%p != %p)\n",
|
|
cp, cp1 + dlen);
|
|
if (doprint)
|
|
fprintf(file, "\n");
|
|
return (cp);
|
|
}
|
|
|
|
/*
|
|
* Return a string for the type. A few get special treatment when
|
|
* not in verbose mode, to make the program more chatty and easier to
|
|
* understand.
|
|
*/
|
|
static const char *
|
|
pr_type(int type) {
|
|
if (!verbose) switch (type) {
|
|
case ns_t_a:
|
|
return ("has address");
|
|
case ns_t_cname:
|
|
return ("is a nickname for");
|
|
case ns_t_mx:
|
|
return ("mail is handled");
|
|
case ns_t_txt:
|
|
return ("descriptive text");
|
|
case ns_t_afsdb:
|
|
return ("DCE or AFS service from");
|
|
}
|
|
if (verbose)
|
|
return (sym_ntos(__p_type_syms, type, NULL));
|
|
else
|
|
return (sym_ntop(__p_type_syms, type, NULL));
|
|
}
|
|
|
|
/*
|
|
* Return a mnemonic for class
|
|
*/
|
|
static const char *
|
|
pr_class(int class) {
|
|
static char spacestr[20];
|
|
|
|
if (!verbose) switch (class) {
|
|
case ns_c_in: /* internet class */
|
|
return ("");
|
|
case ns_c_hs: /* hesiod class */
|
|
return ("");
|
|
}
|
|
|
|
spacestr[0] = ' ';
|
|
strcpy(&spacestr[1], p_class(class));
|
|
return (spacestr);
|
|
}
|
|
|
|
static const u_char *
|
|
pr_cdname(const u_char *cp, const u_char *msg, char *name, int namelen) {
|
|
int n = dn_expand(msg, msg + 512, cp, name, namelen - 2);
|
|
|
|
if (n < 0)
|
|
return (NULL);
|
|
if (name[0] == '\0') {
|
|
name[0] = '.';
|
|
name[1] = '\0';
|
|
}
|
|
return (cp + n);
|
|
}
|
|
|
|
static int
|
|
ListHosts(char *namePtr, int queryType) {
|
|
querybuf buf, answer;
|
|
struct sockaddr_in sin;
|
|
const HEADER *headerPtr;
|
|
const struct hostent *hp;
|
|
enum { NO_ERRORS, ERR_READING_LEN, ERR_READING_MSG, ERR_PRINTING }
|
|
error = NO_ERRORS;
|
|
|
|
int msglen, amtToRead, numRead, i, len, dlen, type, nscount, n;
|
|
int numAnswers = 0, soacnt = 0, result = 0;
|
|
u_char tmp[NS_INT16SZ];
|
|
char name[NS_MAXDNAME], dname[2][NS_MAXDNAME], domain[NS_MAXDNAME];
|
|
u_char *cp, *nmp, *eom;
|
|
|
|
/* Names and addresses of name servers to try. */
|
|
char nsname[NUMNS][NS_MAXDNAME];
|
|
int nshaveaddr[NUMNS];
|
|
struct in_addr nsipaddr[NUMNSADDR];
|
|
int numns, numnsaddr, thisns;
|
|
|
|
/*
|
|
* Normalize to not have trailing dot. We do string compares below
|
|
* of info from name server, and it won't have trailing dots.
|
|
*/
|
|
i = strlen(namePtr);
|
|
if (namePtr[i-1] == '.')
|
|
namePtr[i-1] = 0;
|
|
|
|
if (server_specified) {
|
|
memcpy(&nsipaddr[0], &_res.nsaddr.sin_addr, NS_INADDRSZ);
|
|
numnsaddr = 1;
|
|
} else {
|
|
/*
|
|
* First we have to find out where to look. This needs a NS
|
|
* query, possibly followed by looking up addresses for some
|
|
* of the names.
|
|
*/
|
|
msglen = res_mkquery(ns_o_query, namePtr, ns_c_in, ns_t_ns,
|
|
NULL, 0, NULL, buf.qb2, sizeof buf);
|
|
if (msglen < 0) {
|
|
printf("res_mkquery failed\n");
|
|
return (ERROR);
|
|
}
|
|
|
|
msglen = res_send(buf.qb2, msglen, answer.qb2, sizeof answer);
|
|
if (msglen < 0) {
|
|
printf("Cannot find nameserver -- try again later\n");
|
|
return (ERROR);
|
|
}
|
|
if (_res.options & RES_DEBUG || verbose)
|
|
printf("rcode = %d (%s), ancount=%d\n",
|
|
answer.qb1.rcode, DecodeError(answer.qb1.rcode),
|
|
ntohs(answer.qb1.ancount));
|
|
|
|
/*
|
|
* Analyze response to our NS lookup.
|
|
*/
|
|
|
|
nscount = ntohs(answer.qb1.ancount) +
|
|
ntohs(answer.qb1.nscount) +
|
|
ntohs(answer.qb1.arcount);
|
|
|
|
if (answer.qb1.rcode != NOERROR || nscount == 0) {
|
|
switch (answer.qb1.rcode) {
|
|
case NXDOMAIN:
|
|
/* Check if it's an authoritive answer */
|
|
if (answer.qb1.aa)
|
|
printf("No such domain\n");
|
|
else
|
|
printf("Unable to get information about domain -- try again later.\n");
|
|
break;
|
|
case SERVFAIL:
|
|
printf("Unable to get information about that domain -- try again later.\n");
|
|
break;
|
|
case NOERROR:
|
|
printf("That domain exists, but seems to be a leaf node.\n");
|
|
break;
|
|
case FORMERR:
|
|
case NOTIMP:
|
|
case REFUSED:
|
|
printf("Unrecoverable error looking up domain name.\n");
|
|
break;
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
cp = answer.qb2 + HFIXEDSZ;
|
|
eom = answer.qb2 + msglen;
|
|
if (ntohs(answer.qb1.qdcount) > 0) {
|
|
n = dn_skipname(cp, eom);
|
|
if (n < 0) {
|
|
printf("Form error.\n");
|
|
return (ERROR);
|
|
}
|
|
cp += n + QFIXEDSZ;
|
|
if (cp > eom) {
|
|
printf("Form error.\n");
|
|
return (ERROR);
|
|
}
|
|
}
|
|
|
|
numns = 0;
|
|
numnsaddr = 0;
|
|
|
|
/*
|
|
* Look at response from NS lookup for NS and A records.
|
|
*/
|
|
|
|
for ((void)NULL; nscount; nscount--) {
|
|
cp += dn_expand(answer.qb2, answer.qb2 + msglen, cp,
|
|
domain, sizeof(domain));
|
|
if (cp + 3 * INT16SZ + INT32SZ > eom) {
|
|
printf("Form error.\n");
|
|
return (ERROR);
|
|
}
|
|
type = ns_get16(cp);
|
|
cp += INT16SZ + INT16SZ + INT32SZ;
|
|
dlen = ns_get16(cp);
|
|
cp += INT16SZ;
|
|
if (cp + dlen > eom) {
|
|
printf("Form error.\n");
|
|
return (ERROR);
|
|
}
|
|
if (type == ns_t_ns) {
|
|
if (dn_expand(answer.qb2, eom,
|
|
cp, name, sizeof(name)) >= 0) {
|
|
if (numns < NUMNS &&
|
|
strcasecmp((char *)domain,
|
|
namePtr) == 0) {
|
|
for (i = 0; i < numns; i++)
|
|
if (strcasecmp(
|
|
nsname[i],
|
|
(char *)name
|
|
) == 0)
|
|
/* duplicate */
|
|
break;
|
|
if (i >= numns) {
|
|
strncpy(nsname[numns],
|
|
(char *)name,
|
|
sizeof(name));
|
|
nshaveaddr[numns] = 0;
|
|
numns++;
|
|
}
|
|
}
|
|
}
|
|
} else if (type == ns_t_a) {
|
|
if (numnsaddr < NUMNSADDR)
|
|
for (i = 0; i < numns; i++) {
|
|
if (strcasecmp(nsname[i],
|
|
(char *)domain)
|
|
== 0) {
|
|
nshaveaddr[i]++;
|
|
memcpy(
|
|
&nsipaddr[numnsaddr],
|
|
cp, NS_INADDRSZ);
|
|
numnsaddr++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
cp += dlen;
|
|
}
|
|
|
|
/*
|
|
* Usually we'll get addresses for all the servers in the
|
|
* additional info section. But in case we don't, look up
|
|
* their addresses.
|
|
*/
|
|
|
|
for (i = 0; i < numns; i++) {
|
|
if (nshaveaddr[i] == 0) {
|
|
struct in_addr **hptr;
|
|
int numaddrs = 0;
|
|
|
|
hp = gethostbyname(nsname[i]);
|
|
if (hp) {
|
|
for (hptr = (struct in_addr **)
|
|
hp->h_addr_list;
|
|
*hptr != NULL;
|
|
hptr++)
|
|
if (numnsaddr < NUMNSADDR) {
|
|
memcpy(
|
|
&nsipaddr[numnsaddr],
|
|
*hptr, NS_INADDRSZ);
|
|
numnsaddr++;
|
|
numaddrs++;
|
|
}
|
|
}
|
|
if (_res.options & RES_DEBUG || verbose)
|
|
printf(
|
|
"Found %d addresses for %s by extra query\n",
|
|
numaddrs, nsname[i]);
|
|
} else if (_res.options & RES_DEBUG || verbose)
|
|
printf("Found %d addresses for %s\n",
|
|
nshaveaddr[i], nsname[i]);
|
|
}
|
|
}
|
|
/*
|
|
* Now nsipaddr has numnsaddr addresses for name servers that
|
|
* serve the requested domain. Now try to find one that will
|
|
* accept a zone transfer.
|
|
*/
|
|
thisns = 0;
|
|
|
|
again:
|
|
numAnswers = 0;
|
|
soacnt = 0;
|
|
|
|
/*
|
|
* Create a query packet for the requested domain name.
|
|
*/
|
|
msglen = res_mkquery(QUERY, namePtr, getclass, ns_t_axfr, NULL,
|
|
0, NULL, buf.qb2, sizeof buf);
|
|
if (msglen < 0) {
|
|
if (_res.options & RES_DEBUG)
|
|
fprintf(stderr, "ListHosts: Res_mkquery failed\n");
|
|
return (ERROR);
|
|
}
|
|
|
|
memset(&sin, 0, sizeof sin);
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_port = htons(NAMESERVER_PORT);
|
|
|
|
/*
|
|
* Set up a virtual circuit to the server.
|
|
*/
|
|
|
|
for ((void)NULL; thisns < numnsaddr; thisns++) {
|
|
if ((sockFD = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
|
perror("ListHosts");
|
|
return (ERROR);
|
|
}
|
|
memcpy(&sin.sin_addr, &nsipaddr[thisns], NS_INADDRSZ);
|
|
if (_res.options & RES_DEBUG || verbose)
|
|
printf("Trying %s\n", inet_ntoa(sin.sin_addr));
|
|
if (connect(sockFD, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
|
|
break;
|
|
if (verbose)
|
|
perror("Connection failed, trying next server");
|
|
close(sockFD);
|
|
sockFD = -1;
|
|
}
|
|
if (thisns >= numnsaddr) {
|
|
printf("No server for that domain responded\n");
|
|
if (!verbose)
|
|
perror("Error from the last server was");
|
|
return (ERROR);
|
|
}
|
|
|
|
/*
|
|
* Send length & message for zone transfer
|
|
*/
|
|
|
|
ns_put16(msglen, tmp);
|
|
if (write(sockFD, (char *)tmp, INT16SZ) != INT16SZ ||
|
|
write(sockFD, (char *)buf.qb2, msglen) != msglen) {
|
|
perror("ListHosts");
|
|
(void) close(sockFD);
|
|
sockFD = -1;
|
|
return (ERROR);
|
|
}
|
|
|
|
filePtr = stdout;
|
|
|
|
for (;;) {
|
|
/*
|
|
* Read the length of the response.
|
|
*/
|
|
cp = buf.qb2;
|
|
amtToRead = INT16SZ;
|
|
while (amtToRead > 0 &&
|
|
(numRead = read(sockFD, cp, amtToRead)) > 0) {
|
|
cp += numRead;
|
|
amtToRead -= numRead;
|
|
}
|
|
if (numRead <= 0) {
|
|
error = ERR_READING_LEN;
|
|
break;
|
|
}
|
|
|
|
if ((len = ns_get16(buf.qb2)) == 0)
|
|
break; /* Protocol violation. */
|
|
|
|
/*
|
|
* Read the response.
|
|
*/
|
|
|
|
amtToRead = len;
|
|
cp = buf.qb2;
|
|
while (amtToRead > 0 &&
|
|
(numRead = read(sockFD, cp, amtToRead)) > 0) {
|
|
cp += numRead;
|
|
amtToRead -= numRead;
|
|
}
|
|
if (numRead <= 0) {
|
|
error = ERR_READING_MSG;
|
|
break;
|
|
}
|
|
|
|
i = buf.qb1.rcode;
|
|
if (i != NOERROR || ntohs(buf.qb1.ancount) == 0) {
|
|
if (thisns + 1 < numnsaddr &&
|
|
(i == SERVFAIL || i == NOTIMP || i == REFUSED)) {
|
|
if (_res.options & RES_DEBUG || verbose)
|
|
printf(
|
|
"Server failed, trying next server: %s\n",
|
|
i != NOERROR
|
|
? DecodeError(i)
|
|
: "Premature end of data");
|
|
(void) close(sockFD);
|
|
sockFD = -1;
|
|
thisns++;
|
|
goto again;
|
|
}
|
|
printf("Server failed: %s\n", i != NOERROR
|
|
? DecodeError(i) : "Premature end of data");
|
|
break;
|
|
}
|
|
|
|
result = printinfo(&buf, cp, queryType, 1);
|
|
if (! result) {
|
|
error = ERR_PRINTING;
|
|
break;
|
|
}
|
|
numAnswers++;
|
|
cp = buf.qb2 + HFIXEDSZ;
|
|
if (ntohs(buf.qb1.qdcount) > 0) {
|
|
n = dn_skipname(cp, buf.qb2 + len);
|
|
if (n < 0) {
|
|
error = ERR_PRINTING;
|
|
break;
|
|
}
|
|
cp += n + QFIXEDSZ;
|
|
}
|
|
nmp = cp;
|
|
n = dn_skipname(cp, buf.qb2 + len);
|
|
if (n < 0) {
|
|
error = ERR_PRINTING;
|
|
break;
|
|
}
|
|
cp += n;
|
|
if (cp + INT16SZ > buf.qb2 + len) {
|
|
error = ERR_PRINTING;
|
|
break;
|
|
}
|
|
if ((ns_get16(cp) == ns_t_soa)) {
|
|
(void) dn_expand(buf.qb2, buf.qb2 + len, nmp,
|
|
dname[soacnt], sizeof dname[0]);
|
|
if (soacnt) {
|
|
if (strcmp(dname[0], dname[1]) == 0)
|
|
break;
|
|
} else
|
|
soacnt++;
|
|
}
|
|
}
|
|
|
|
(void) close(sockFD);
|
|
sockFD = -1;
|
|
|
|
switch (error) {
|
|
case NO_ERRORS:
|
|
return (SUCCESS);
|
|
|
|
case ERR_READING_LEN:
|
|
return (ERROR);
|
|
|
|
case ERR_PRINTING:
|
|
fprintf(stderr,"*** Error during listing of %s: %s\n",
|
|
namePtr, DecodeError(result));
|
|
return (result);
|
|
|
|
case ERR_READING_MSG:
|
|
headerPtr = (HEADER *) &buf;
|
|
fprintf(stderr,"ListHosts: error receiving zone transfer:\n");
|
|
fprintf(stderr,
|
|
" result: %s, answers = %d, authority = %d, additional = %d\n",
|
|
_res_resultcodes[headerPtr->rcode],
|
|
ntohs(headerPtr->ancount), ntohs(headerPtr->nscount),
|
|
ntohs(headerPtr->arcount));
|
|
return (ERROR);
|
|
default:
|
|
return (ERROR);
|
|
}
|
|
}
|
|
|
|
static const char *
|
|
DecodeError(int result) {
|
|
switch(result) {
|
|
case NOERROR: return ("Success"); break;
|
|
case FORMERR: return ("Format error"); break;
|
|
case SERVFAIL: return ("Server failed"); break;
|
|
case NXDOMAIN: return ("Non-existent domain"); break;
|
|
case NOTIMP: return ("Not implemented"); break;
|
|
case REFUSED: return ("Query refused"); break;
|
|
case NO_INFO: return ("No information"); break;
|
|
case ERROR: return ("Unspecified error"); break;
|
|
case TIME_OUT: return ("Timed out"); break;
|
|
case NONAUTH: return ("Non-authoritative answer"); break;
|
|
default: return ("BAD ERROR VALUE");
|
|
}
|
|
/* NOTREACHED */
|
|
}
|