NetBSD/lib/libc/net/res_debug.c
1994-04-07 06:58:29 +00:00

745 lines
17 KiB
C

/*
* Copyright (c) 1985, 1990, 1993
* 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93";
static char rcsid[] = "$Id: res_debug.c,v 1.5 1994/04/07 07:00:18 deraadt Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <stdio.h>
#include <string.h>
void __fp_query();
char *__p_class(), *__p_time(), *__p_type();
char *p_cdname(), *p_fqname(), *p_rr();
static char *p_option __P((u_long));
char *_res_opcodes[] = {
"QUERY",
"IQUERY",
"CQUERYM",
"CQUERYU",
"4",
"5",
"6",
"7",
"8",
"UPDATEA",
"UPDATED",
"UPDATEDA",
"UPDATEM",
"UPDATEMA",
"ZONEINIT",
"ZONEREF",
};
char *_res_resultcodes[] = {
"NOERROR",
"FORMERR",
"SERVFAIL",
"NXDOMAIN",
"NOTIMP",
"REFUSED",
"6",
"7",
"8",
"9",
"10",
"11",
"12",
"13",
"14",
"NOCHANGE",
};
static char retbuf[16];
static char *
dewks(wks)
int wks;
{
switch (wks) {
case 5: return("rje");
case 7: return("echo");
case 9: return("discard");
case 11: return("systat");
case 13: return("daytime");
case 15: return("netstat");
case 17: return("qotd");
case 19: return("chargen");
case 20: return("ftp-data");
case 21: return("ftp");
case 23: return("telnet");
case 25: return("smtp");
case 37: return("time");
case 39: return("rlp");
case 42: return("name");
case 43: return("whois");
case 53: return("domain");
case 57: return("apts");
case 59: return("apfs");
case 67: return("bootps");
case 68: return("bootpc");
case 69: return("tftp");
case 77: return("rje");
case 79: return("finger");
case 87: return("link");
case 95: return("supdup");
case 100: return("newacct");
case 101: return("hostnames");
case 102: return("iso-tsap");
case 103: return("x400");
case 104: return("x400-snd");
case 105: return("csnet-ns");
case 109: return("pop-2");
case 111: return("sunrpc");
case 113: return("auth");
case 115: return("sftp");
case 117: return("uucp-path");
case 119: return("nntp");
case 121: return("erpc");
case 123: return("ntp");
case 133: return("statsrv");
case 136: return("profile");
case 144: return("NeWS");
case 161: return("snmp");
case 162: return("snmp-trap");
case 170: return("print-srv");
default: (void) sprintf(retbuf, "%d", wks); return(retbuf);
}
}
static char *
deproto(protonum)
int protonum;
{
switch (protonum) {
case 1: return("icmp");
case 2: return("igmp");
case 3: return("ggp");
case 5: return("st");
case 6: return("tcp");
case 7: return("ucl");
case 8: return("egp");
case 9: return("igp");
case 11: return("nvp-II");
case 12: return("pup");
case 16: return("chaos");
case 17: return("udp");
default: (void) sprintf(retbuf, "%d", protonum); return(retbuf);
}
}
static char *
do_rrset(msg, cp, cnt, pflag, file, hs)
int cnt, pflag;
char *cp,*msg, *hs;
FILE *file;
{
int n;
int sflag;
/*
* Print answer records
*/
sflag = (_res.pfcode & pflag);
if (n = ntohs(cnt)) {
if ((!_res.pfcode) || ((sflag) && (_res.pfcode & RES_PRF_HEAD1)))
fprintf(file, hs);
while (--n >= 0) {
cp = p_rr(cp, msg, file);
if ((cp-msg) > PACKETSZ)
return (NULL);
}
if ((!_res.pfcode) || ((sflag) && (_res.pfcode & RES_PRF_HEAD1)))
putc('\n', file);
}
return(cp);
}
__p_query(msg)
char *msg;
{
__fp_query(msg, stdout);
}
/*
* Print the current options.
* This is intended to be primarily a debugging routine.
*/
void
__fp_resstat(statp, file)
struct __res_state *statp;
FILE *file;
{
int bit;
fprintf(file, ";; res options:");
if (!statp)
statp = &_res;
for (bit = 0; bit < 32; bit++) { /* XXX 32 - bad assumption! */
if (statp->options & (1<<bit))
fprintf(file, " %s", p_option(1<<bit));
}
putc('\n', file);
}
/*
* Print the contents of a query.
* This is intended to be primarily a debugging routine.
*/
void
__fp_query(msg,file)
char *msg;
FILE *file;
{
register char *cp;
register HEADER *hp;
register int n;
/*
* Print header fields.
*/
hp = (HEADER *)msg;
cp = msg + sizeof(HEADER);
if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX) || hp->rcode) {
fprintf(file,";; ->>HEADER<<- opcode: %s, status: %s, id: %d",
_res_opcodes[hp->opcode],
_res_resultcodes[hp->rcode],
ntohs(hp->id));
putc('\n', file);
}
putc(';', file);
if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD2)) {
fprintf(file,"; flags:");
if (hp->qr)
fprintf(file," qr");
if (hp->aa)
fprintf(file," aa");
if (hp->tc)
fprintf(file," tc");
if (hp->rd)
fprintf(file," rd");
if (hp->ra)
fprintf(file," ra");
if (hp->pr)
fprintf(file," pr");
}
if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD1)) {
fprintf(file,"; Ques: %d", ntohs(hp->qdcount));
fprintf(file,", Ans: %d", ntohs(hp->ancount));
fprintf(file,", Auth: %d", ntohs(hp->nscount));
fprintf(file,", Addit: %d", ntohs(hp->arcount));
}
#if 1
if ((!_res.pfcode) || (_res.pfcode &
(RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) {
putc('\n',file);
}
#endif
/*
* Print question records.
*/
if (n = ntohs(hp->qdcount)) {
if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
fprintf(file,";; QUESTIONS:\n");
while (--n >= 0) {
fprintf(file,";;\t");
cp = p_cdname(cp, msg, file);
if (cp == NULL)
return;
if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
fprintf(file, ", type = %s",
__p_type(_getshort(cp)));
cp += sizeof(u_short);
if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
fprintf(file, ", class = %s\n",
__p_class(_getshort(cp)));
cp += sizeof(u_short);
putc('\n', file);
}
}
/*
* Print authoritative answer records
*/
cp = do_rrset(msg, cp, hp->ancount, RES_PRF_ANS, file,
";; ANSWERS:\n");
if (cp == NULL)
return;
/*
* print name server records
*/
cp = do_rrset(msg, cp, hp->nscount, RES_PRF_AUTH, file,
";; AUTHORITY RECORDS:\n");
if (!cp)
return;
/*
* print additional records
*/
cp = do_rrset(msg, cp, hp->arcount, RES_PRF_ADD, file,
";; ADDITIONAL RECORDS:\n");
if (!cp)
return;
}
char *
p_cdname(cp, msg, file)
char *cp, *msg;
FILE *file;
{
char name[MAXDNAME];
int n;
if ((n = dn_expand((u_char *)msg, (u_char *)cp + MAXCDNAME,
(u_char *)cp, (u_char *)name, sizeof(name))) < 0)
return (NULL);
if (name[0] == '\0')
putc('.', file);
else
fputs(name, file);
return (cp + n);
}
char *
p_fqname(cp, msg, file)
char *cp, *msg;
FILE *file;
{
char name[MAXDNAME];
int n, len;
if ((n = dn_expand((u_char *)msg, (u_char *)cp + MAXCDNAME,
(u_char *)cp, (u_char *)name, sizeof(name))) < 0)
return (NULL);
if (name[0] == '\0') {
putc('.', file);
} else {
fputs(name, file);
if (name[strlen(name) - 1] != '.')
putc('.', file);
}
return (cp + n);
}
/*
* Print resource record fields in human readable form.
*/
char *
p_rr(cp, msg, file)
char *cp, *msg;
FILE *file;
{
int type, class, dlen, n, c;
struct in_addr inaddr;
char *cp1, *cp2;
u_long tmpttl, t;
int lcnt;
if ((cp = p_fqname(cp, msg, file)) == NULL)
return (NULL); /* compression error */
type = _getshort(cp);
cp += sizeof(u_short);
class = _getshort(cp);
cp += sizeof(u_short);
tmpttl = _getlong(cp);
cp += sizeof(u_long);
dlen = _getshort(cp);
cp += sizeof(u_short);
cp1 = cp;
if ((!_res.pfcode) || (_res.pfcode & RES_PRF_TTLID))
fprintf(file, "\t%lu", tmpttl);
if ((!_res.pfcode) || (_res.pfcode & RES_PRF_CLASS))
fprintf(file, "\t%s", __p_class(class));
fprintf(file, "\t%s", __p_type(type));
/*
* Print type specific data, if appropriate
*/
switch (type) {
case T_A:
switch (class) {
case C_IN:
case C_HS:
bcopy(cp, (char *)&inaddr, sizeof(inaddr));
if (dlen == 4) {
fprintf(file,"\t%s", inet_ntoa(inaddr));
cp += dlen;
} else if (dlen == 7) {
char *address;
u_char protocol;
u_short port;
address = inet_ntoa(inaddr);
cp += sizeof(inaddr);
protocol = *(u_char*)cp;
cp += sizeof(u_char);
port = _getshort(cp);
cp += sizeof(u_short);
fprintf(file, "\t%s\t; proto %d, port %d",
address, protocol, port);
}
break;
default:
cp += dlen;
}
break;
case T_CNAME:
case T_MB:
case T_MG:
case T_MR:
case T_NS:
case T_PTR:
putc('\t', file);
cp = p_fqname(cp, msg, file);
break;
case T_HINFO:
if (n = *cp++) {
fprintf(file,"\t%.*s", n, cp);
cp += n;
}
if (n = *cp++) {
fprintf(file,"\t%.*s", n, cp);
cp += n;
}
break;
case T_SOA:
putc('\t', file);
cp = p_fqname(cp, msg, file); /* origin */
putc(' ', file);
cp = p_fqname(cp, msg, file); /* mail addr */
fputs(" (\n", file);
t = _getlong(cp); cp += sizeof(u_long);
fprintf(file,"\t\t\t%lu\t; serial\n", t);
t = _getlong(cp); cp += sizeof(u_long);
fprintf(file,"\t\t\t%lu\t; refresh (%s)\n", t, __p_time(t));
t = _getlong(cp); cp += sizeof(u_long);
fprintf(file,"\t\t\t%lu\t; retry (%s)\n", t, __p_time(t));
t = _getlong(cp); cp += sizeof(u_long);
fprintf(file,"\t\t\t%lu\t; expire (%s)\n", t, __p_time(t));
t = _getlong(cp); cp += sizeof(u_long);
fprintf(file,"\t\t\t%lu )\t; minimum (%s)", t, __p_time(t));
break;
case T_MX:
case T_AFSDB:
fprintf(file,"\t%d ", _getshort(cp));
cp += sizeof(u_short);
cp = p_fqname(cp, msg, file);
break;
case T_TXT:
(void) fputs("\t\"", file);
cp2 = cp1 + dlen;
while (cp < cp2) {
if (n = (unsigned char) *cp++) {
for (c = n; c > 0 && cp < cp2; c--)
if (*cp == '\n') {
(void) putc('\\', file);
(void) putc(*cp++, file);
} else
(void) putc(*cp++, file);
}
}
putc('"', file);
break;
case T_MINFO:
case T_RP:
putc('\t', file);
cp = p_fqname(cp, msg, file);
putc(' ', file);
cp = p_fqname(cp, msg, file);
break;
case T_UINFO:
putc('\t', file);
fputs(cp, file);
cp += dlen;
break;
case T_UID:
case T_GID:
if (dlen == 4) {
fprintf(file,"\t%u", _getlong(cp));
cp += sizeof(long);
}
break;
case T_WKS:
if (dlen < sizeof(u_long) + 1)
break;
bcopy(cp, (char *)&inaddr, sizeof(inaddr));
cp += sizeof(u_long);
fprintf(file, "\t%s %s ( ",
inet_ntoa(inaddr),
deproto((int) *cp));
cp += sizeof(u_char);
n = 0;
lcnt = 0;
while (cp < cp1 + dlen) {
c = *cp++;
do {
if (c & 0200) {
if (lcnt == 0) {
fputs("\n\t\t\t", file);
lcnt = 5;
}
fputs(dewks(n), file);
putc(' ', file);
lcnt--;
}
c <<= 1;
} while (++n & 07);
}
putc(')', file);
break;
#ifdef ALLOW_T_UNSPEC
case T_UNSPEC:
{
int NumBytes = 8;
char *DataPtr;
int i;
if (dlen < NumBytes) NumBytes = dlen;
fprintf(file, "\tFirst %d bytes of hex data:",
NumBytes);
for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++)
fprintf(file, " %x", *DataPtr);
cp += dlen;
}
break;
#endif /* ALLOW_T_UNSPEC */
default:
fprintf(file,"\t?%d?", type);
cp += dlen;
}
#if 0
fprintf(file, "\t; dlen=%d, ttl %s\n", dlen, __p_time(tmpttl));
#else
putc('\n', file);
#endif
if (cp - cp1 != dlen) {
fprintf(file,";; packet size error (found %d, dlen was %d)\n",
cp - cp1, dlen);
cp = NULL;
}
return (cp);
}
static char nbuf[40];
/*
* Return a string for the type
*/
char *
__p_type(type)
int type;
{
switch (type) {
case T_A:
return("A");
case T_NS: /* authoritative server */
return("NS");
case T_CNAME: /* canonical name */
return("CNAME");
case T_SOA: /* start of authority zone */
return("SOA");
case T_MB: /* mailbox domain name */
return("MB");
case T_MG: /* mail group member */
return("MG");
case T_MR: /* mail rename name */
return("MR");
case T_NULL: /* null resource record */
return("NULL");
case T_WKS: /* well known service */
return("WKS");
case T_PTR: /* domain name pointer */
return("PTR");
case T_HINFO: /* host information */
return("HINFO");
case T_MINFO: /* mailbox information */
return("MINFO");
case T_MX: /* mail routing info */
return("MX");
case T_TXT: /* text */
return("TXT");
case T_RP: /* responsible person */
return("RP");
case T_AFSDB: /* AFS cell database */
return("AFSDB");
case T_AXFR: /* zone transfer */
return("AXFR");
case T_MAILB: /* mail box */
return("MAILB");
case T_MAILA: /* mail address */
return("MAILA");
case T_ANY: /* matches any type */
return("ANY");
case T_UINFO:
return("UINFO");
case T_UID:
return("UID");
case T_GID:
return("GID");
#ifdef ALLOW_T_UNSPEC
case T_UNSPEC:
return("UNSPEC");
#endif /* ALLOW_T_UNSPEC */
default:
(void)sprintf(nbuf, "%d", type);
return(nbuf);
}
}
/*
* Return a mnemonic for class
*/
char *
__p_class(class)
int class;
{
switch (class) {
case C_IN: /* internet class */
return("IN");
case C_HS: /* hesiod class */
return("HS");
case C_ANY: /* matches any class */
return("ANY");
default:
(void)sprintf(nbuf, "%d", class);
return(nbuf);
}
}
/*
* Return a mnemonic for an option
*/
static char *
p_option(option)
u_long option;
{
switch (option) {
case RES_INIT: return "init";
case RES_DEBUG: return "debug";
case RES_AAONLY: return "aaonly";
case RES_USEVC: return "usevc";
case RES_PRIMARY: return "primry";
case RES_IGNTC: return "igntc";
case RES_RECURSE: return "recurs";
case RES_DEFNAMES: return "defnam";
case RES_STAYOPEN: return "styopn";
case RES_DNSRCH: return "dnsrch";
default: sprintf(nbuf, "?0x%x?", option); return nbuf;
}
}
/*
* Return a mnemonic for a time to live
*/
char *
__p_time(value)
u_long value;
{
int secs, mins, hours, days;
register char *p;
if (value == 0) {
strcpy(nbuf, "0 secs");
return(nbuf);
}
secs = value % 60;
value /= 60;
mins = value % 60;
value /= 60;
hours = value % 24;
value /= 24;
days = value;
value = 0;
#define PLURALIZE(x) x, (x == 1) ? "" : "s"
p = nbuf;
if (days) {
(void)sprintf(p, "%d day%s", PLURALIZE(days));
while (*++p);
}
if (hours) {
if (days)
*p++ = ' ';
(void)sprintf(p, "%d hour%s", PLURALIZE(hours));
while (*++p);
}
if (mins) {
if (days || hours)
*p++ = ' ';
(void)sprintf(p, "%d min%s", PLURALIZE(mins));
while (*++p);
}
if (secs || ! (days || hours || mins)) {
if (days || hours || mins)
*p++ = ' ';
(void)sprintf(p, "%d sec%s", PLURALIZE(secs));
}
return(nbuf);
}