From 9d787f9aa1c452ec6cab0189916c28a8be771fa1 Mon Sep 17 00:00:00 2001 From: pst Date: Thu, 22 Sep 1994 21:36:02 +0000 Subject: nslookup(8) from BIND 4.9.3BETA9pl1 --- usr.sbin/nslookup/commands.l | 219 ++++++++ usr.sbin/nslookup/debug.c | 536 +++++++++++++++++++ usr.sbin/nslookup/getinfo.c | 828 +++++++++++++++++++++++++++++ usr.sbin/nslookup/list.c | 991 ++++++++++++++++++++++++++++++++++ usr.sbin/nslookup/main.c | 1112 +++++++++++++++++++++++++++++++++++++++ usr.sbin/nslookup/nslookup.8 | 387 ++++++++++++++ usr.sbin/nslookup/nslookup.help | 33 ++ usr.sbin/nslookup/pathnames.h | 71 +++ usr.sbin/nslookup/res.h | 172 ++++++ usr.sbin/nslookup/send.c | 412 +++++++++++++++ usr.sbin/nslookup/skip.c | 211 ++++++++ usr.sbin/nslookup/subr.c | 559 ++++++++++++++++++++ 12 files changed, 5531 insertions(+) create mode 100644 usr.sbin/nslookup/commands.l create mode 100644 usr.sbin/nslookup/debug.c create mode 100644 usr.sbin/nslookup/getinfo.c create mode 100644 usr.sbin/nslookup/list.c create mode 100644 usr.sbin/nslookup/main.c create mode 100644 usr.sbin/nslookup/nslookup.8 create mode 100644 usr.sbin/nslookup/nslookup.help create mode 100644 usr.sbin/nslookup/pathnames.h create mode 100644 usr.sbin/nslookup/res.h create mode 100644 usr.sbin/nslookup/send.c create mode 100644 usr.sbin/nslookup/skip.c create mode 100644 usr.sbin/nslookup/subr.c (limited to 'usr.sbin') diff --git a/usr.sbin/nslookup/commands.l b/usr.sbin/nslookup/commands.l new file mode 100644 index 0000000..f70d1aa --- /dev/null +++ b/usr.sbin/nslookup/commands.l @@ -0,0 +1,219 @@ +%{ + +/* + * ++Copyright++ 1985 + * - + * Copyright (c) 1985 + * 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. + * - + * --Copyright-- + */ + +#ifndef lint +static char sccsid[] = "@(#)commands.l 5.13 (Berkeley) 7/24/90"; +#endif /* not lint */ + +/* + ******************************************************************************* + * + * commands.l + * + * Andrew Cherenson CS298-26 Fall 1985 + * + * Lex input file for the nslookup program command interpreter. + * When a sequence is recognized, the associated action + * routine is called. The action routine may need to + * parse the string for additional information. + * + * Recognized commands: (identifiers are shown in uppercase) + * + * server NAME - set default server to NAME, using default server + * lserver NAME - set default server to NAME, using initial server + * finger [NAME] - finger the optional NAME + * exit - exit the program + * root - set default server to the root + * ls NAME - list the domain NAME + * view FILE - sorts and view the file with more + * set OPTION - set an option + * help - print help information + * ? - print help information + * NAME - print info about the host/domain NAME + * using default server. + * NAME1 NAME2 - as above, but use NAME2 as server + * + * + * yylex Results: + * 0 upon end-of-file. + * 1 after each command. + * + ******************************************************************************* + */ + +#include "res.h" +extern char rootServerName[]; +extern void PrintHelp(); + +%} +WS [ \t] +FLET [A-Za-z0-9.*\\] +LET [A-Za-z0-9.*] +NAME [A-Za-z0-9.*=_/-] +%% +^{WS}*server{WS}+{LET}{NAME}*{WS}*$ { + /* + * 0 == use current server to find + * the new one. + * 1 == use original server to find + * the new one. + */ + SetDefaultServer(yytext, 0); + return(1); + } +^{WS}*lserver{WS}+{LET}{NAME}*{WS}*$ { + SetDefaultServer(yytext, 1); + return(1); + } +^{WS}*exit{WS}*$ { + return(0); + } +^{WS}*root{WS}*$ { + SetDefaultServer(rootServerName, 1); + return(1); + } +^{WS}*finger({WS}+{LET}{NAME}*)?{WS}+>>?{WS}*{NAME}+{WS}*$ { + /* + * 2nd arg. + * 0 == output to stdout + * 1 == output to file + */ + Finger(yytext, 1); + return(1); + } +^{WS}*finger({WS}+{LET}{NAME}*)?{WS}*$ { + Finger(yytext, 0); + return(1); + } +^{WS}*view{WS}+{NAME}+{WS}*$ { + ViewList(yytext); + return(1); + } +^{WS}*ls{WS}+(("-a"|"-d"|"-h"|"-m"|"-s"){WS}+)?{LET}{NAME}*{WS}+>>?{WS}+{NAME}+{WS}*$ { + /* + * 2nd arg. + * 0 == output to stdout + * 1 == output to file + */ + ListHosts(yytext, 1); + return(1); + } +^{WS}*ls{WS}+(("-a"|"-d"|"-h"|"-m"|"-s"){WS}+)?{LET}{NAME}*{WS}*$ { + ListHosts(yytext, 0); + return(1); + } +^{WS}*ls{WS}+-t{WS}+({LET}{NAME}*{WS}+)?{LET}{NAME}*{WS}+>>?{WS}+{NAME}+{WS}*$ { + /* + * 2nd arg. + * 0 == output to stdout + * 1 == output to file + */ + ListHostsByType(yytext, 1); + return(1); + } +^{WS}*ls{WS}+-t{WS}+({LET}{NAME}*{WS}+)?{LET}{NAME}*{WS}*$ { + ListHostsByType(yytext, 0); + return(1); + } +^{WS}*set{WS}+{NAME}+{WS}*$ { + SetOption(yytext); + return(1); + } +^{WS}*help{WS}*$ { + PrintHelp(); + return(1); + } +^{WS}*"?"{WS}*$ { + extern void PrintHelp(); + + PrintHelp(); + return(1); + } +^{WS}*{FLET}{NAME}*{WS}+>>?{WS}*{NAME}+{WS}*$ { + /* + * 0 == output to stdout + * 1 == output to file + */ + LookupHost(yytext, 1); + return(1); + } +^{WS}*{FLET}{NAME}*{WS}*$ { + LookupHost(yytext, 0); + return(1); + } +^{WS}*{FLET}{NAME}*{WS}+{LET}{NAME}*{WS}+>>?{WS}*{NAME}+{WS}*$ { + /* + * 0 == output to stdout + * 1 == output to file + */ + LookupHostWithServer(yytext, 1); + return(1); + } +^{WS}*{FLET}{NAME}*{WS}+{LET}{NAME}*{WS}*$ { + LookupHostWithServer(yytext, 0); + return(1); + } +^{WS}*\n { + return(1); + } +^.*\n { + printf("Unrecognized command: %s", + yytext); + return(1); + } +\n { ; } +%% diff --git a/usr.sbin/nslookup/debug.c b/usr.sbin/nslookup/debug.c new file mode 100644 index 0000000..d8af2fc --- /dev/null +++ b/usr.sbin/nslookup/debug.c @@ -0,0 +1,536 @@ +/* + * ++Copyright++ 1985, 1989 + * - + * Copyright (c) 1985, 1989 + * 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. + * - + * --Copyright-- + */ + +#ifndef lint +static char sccsid[] = "@(#)debug.c 5.26 (Berkeley) 3/21/91"; +static char rcsid[] = "$Id: debug.c,v 4.9.1.9 1994/06/06 09:08:43 vixie Exp $"; +#endif /* not lint */ + +/* + ******************************************************************************* + * + * debug.c -- + * + * Routines to print out packets received from a name server query. + * + * Modified version of 4.3BSD BIND res_debug.c 5.30 6/27/90 + * + ******************************************************************************* + */ + +#include +#include +#include +#include +#include +#include +#include +#include "res.h" +#include "../../conf/portability.h" + +/* + * Imported from res_debug.c + */ +extern char *_res_resultcodes[]; +extern char *_res_opcodes[]; + +/* + * Used to highlight the start of a record when printing it. + */ +#define INDENT " -> " + + + +/* + * Print the contents of a query. + * This is intended to be primarily a debugging routine. + */ + +Print_query(msg, eom, printHeader) + char *msg, *eom; + int printHeader; +{ + Fprint_query(msg, eom, printHeader,stdout); +} + +Fprint_query(msg, eom, printHeader,file) + u_char *msg, *eom; + int printHeader; + FILE *file; +{ + register u_char *cp; + register HEADER *hp; + register int n; + short class; + short type; + + /* + * Print header fields. + */ + hp = (HEADER *)msg; + cp = msg + HFIXEDSZ; + if (printHeader || (_res.options & RES_DEBUG2)) { + fprintf(file," HEADER:\n"); + fprintf(file,"\topcode = %s", _res_opcodes[hp->opcode]); + fprintf(file,", id = %d", ntohs(hp->id)); + fprintf(file,", rcode = %s\n", _res_resultcodes[hp->rcode]); + fprintf(file,"\theader flags: "); + if (hp->qr) { + fprintf(file," response"); + } else { + fprintf(file," query"); + } + if (hp->aa) + fprintf(file,", auth. answer"); + if (hp->tc) + fprintf(file,", truncation"); + if (hp->rd) + fprintf(file,", want recursion"); + if (hp->ra) + fprintf(file,", recursion avail."); + if (hp->pr) + fprintf(file,", primary"); + fprintf(file,"\n\tquestions = %d", ntohs(hp->qdcount)); + fprintf(file,", answers = %d", ntohs(hp->ancount)); + fprintf(file,", authority records = %d", ntohs(hp->nscount)); + fprintf(file,", additional = %d\n\n", ntohs(hp->arcount)); + } + + /* + * Print question records. + */ + if (n = ntohs(hp->qdcount)) { + fprintf(file," QUESTIONS:\n"); + while (--n >= 0) { + fprintf(file,"\t"); + cp = Print_cdname(cp, msg, eom, file); + if (cp == NULL) + return; + type = _getshort((u_char*)cp); + cp += INT16SZ; + class = _getshort((u_char*)cp); + cp += INT16SZ; + fprintf(file,", type = %s", p_type(type)); + fprintf(file,", class = %s\n", p_class(class)); + } + } + /* + * Print authoritative answer records + */ + if (n = ntohs(hp->ancount)) { + fprintf(file," ANSWERS:\n"); + while (--n >= 0) { + fprintf(file, INDENT); + cp = Print_rr(cp, msg, eom, file); + if (cp == NULL) + return; + } + } + /* + * print name server records + */ + if (n = ntohs(hp->nscount)) { + fprintf(file," AUTHORITY RECORDS:\n"); + while (--n >= 0) { + fprintf(file, INDENT); + cp = Print_rr(cp, msg, eom, file); + if (cp == NULL) + return; + } + } + /* + * print additional records + */ + if (n = ntohs(hp->arcount)) { + fprintf(file," ADDITIONAL RECORDS:\n"); + while (--n >= 0) { + fprintf(file, INDENT); + cp = Print_rr(cp, msg, eom, file); + if (cp == NULL) + return; + } + } + fprintf(file,"\n------------\n"); +} + + +u_char * +Print_cdname_sub(cp, msg, eom, file, format) + u_char *cp, *msg, *eom; + FILE *file; + int format; +{ + int n; + char name[MAXDNAME]; + + n = dn_expand(msg, eom, cp, name, sizeof name); + if (n < 0) + return (NULL); + if (name[0] == '\0') { + (void) strcpy(name, "(root)"); + } + if (format) { + fprintf(file, "%-30s", name); + } else { + fputs(name, file); + } + return (cp + n); +} + +u_char * +Print_cdname(cp, msg, eom, file) + u_char *cp, *msg, *eom; + FILE *file; +{ + return (Print_cdname_sub(cp, msg, eom, file, 0)); +} + +u_char * +Print_cdname2(cp, msg, eom, file) + u_char *cp, *msg, *eom; + FILE *file; +{ + return (Print_cdname_sub(cp, msg, eom, file, 1)); +} + +/* + * Print resource record fields in human readable form. + */ +u_char * +Print_rr(cp, msg, eom, file) + u_char *cp, *msg, *eom; + FILE *file; +{ + int type, class, dlen, n, c; + u_int32_t rrttl, ttl; + struct in_addr inaddr; + u_char *cp1, *cp2; + int debug; + + if ((cp = Print_cdname(cp, msg, eom, file)) == NULL) { + fprintf(file, "(name truncated?)\n"); + return (NULL); /* compression error */ + } + + type = _getshort((u_char*)cp); + cp += INT16SZ; + class = _getshort((u_char*)cp); + cp += INT16SZ; + rrttl = _getlong((u_char*)cp); + cp += INT32SZ; + dlen = _getshort((u_char*)cp); + cp += INT16SZ; + + debug = _res.options & (RES_DEBUG|RES_DEBUG2); + if (debug) { + if (_res.options & RES_DEBUG2) { + fprintf(file,"\n\ttype = %s, class = %s, dlen = %d", + p_type(type), p_class(class), dlen); + } + if (type == T_SOA) { + fprintf(file,"\n\tttl = %lu (%s)", rrttl, p_time(rrttl)); + } + (void) putc('\n', file); + } + + cp1 = cp; + + /* + * Print type specific data, if appropriate + */ + switch (type) { + case T_A: + switch (class) { + case C_IN: + case C_HS: + bcopy(cp, (char *)&inaddr, INADDRSZ); + if (dlen == 4) { + fprintf(file,"\tinternet address = %s\n", + inet_ntoa(inaddr)); + cp += dlen; + } else if (dlen == 7) { + fprintf(file,"\tinternet address = %s", + inet_ntoa(inaddr)); + fprintf(file,", protocol = %d", cp[4]); + fprintf(file,", port = %d\n", + (cp[5] << 8) + cp[6]); + cp += dlen; + } + break; + default: + fprintf(file,"\taddress, class = %d, len = %d\n", + class, dlen); + cp += dlen; + } + break; + + case T_CNAME: + fprintf(file,"\tcanonical name = "); + goto doname; + + case T_MG: + fprintf(file,"\tmail group member = "); + goto doname; + case T_MB: + fprintf(file,"\tmail box = "); + goto doname; + case T_MR: + fprintf(file,"\tmailbox rename = "); + goto doname; + case T_MX: + fprintf(file,"\tpreference = %u",_getshort((u_char*)cp)); + cp += INT16SZ; + fprintf(file,", mail exchanger = "); + goto doname; + case T_RT: + fprintf(file,"\tpreference = %u",_getshort((u_char*)cp)); + cp += INT16SZ; + fprintf(file,", router = "); + goto doname; + case T_AFSDB: + fprintf(file,"\tsubtype = %d",_getshort((u_char*)cp)); + cp += INT16SZ; + fprintf(file,", DCE/AFS server = "); + goto doname; + case T_NS: + fprintf(file,"\tnameserver = "); + goto doname; + case T_PTR: + fprintf(file,"\tname = "); +doname: + cp = Print_cdname(cp, msg, eom, file); + (void) putc('\n', file); + break; + + case T_HINFO: + if (n = *cp++) { + fprintf(file,"\tCPU = %.*s", n, cp); + cp += n; + } + if (n = *cp++) { + fprintf(file,"\tOS = %.*s\n", n, cp); + cp += n; + } + break; + + case T_ISDN: + if (n = *cp++) { + fprintf(file,"\tISDN = \"%.*s", n, cp); + cp += n; + } + if (n = *cp++) { + fprintf(file,"-%.*s\"\n", n, cp); + cp += n; + } else fprintf(file,"\"\n"); + break; + + + case T_SOA: + if (!debug) + (void) putc('\n', file); + fprintf(file,"\torigin = "); + cp = Print_cdname(cp, msg, eom, file); + fprintf(file,"\n\tmail addr = "); + cp = Print_cdname(cp, msg, eom, file); + fprintf(file,"\n\tserial = %lu", _getlong((u_char*)cp)); + cp += INT32SZ; + ttl = _getlong((u_char*)cp); + fprintf(file,"\n\trefresh = %lu (%s)", ttl, p_time(ttl)); + cp += INT32SZ; + ttl = _getlong((u_char*)cp); + fprintf(file,"\n\tretry = %lu (%s)", ttl, p_time(ttl)); + cp += INT32SZ; + ttl = _getlong((u_char*)cp); + fprintf(file,"\n\texpire = %lu (%s)", ttl, p_time(ttl)); + cp += INT32SZ; + ttl = _getlong((u_char*)cp); + fprintf(file, + "\n\tminimum ttl = %lu (%s)\n", ttl, p_time(ttl)); + cp += INT32SZ; + break; + + case T_MINFO: + if (!debug) + (void) putc('\n', file); + fprintf(file,"\trequests = "); + cp = Print_cdname(cp, msg, eom, file); + fprintf(file,"\n\terrors = "); + cp = Print_cdname(cp, msg, eom, file); + (void) putc('\n', file); + break; + case T_RP: + if (!debug) + (void) putc('\n', file); + fprintf(file,"\tmailbox = "); + cp = Print_cdname(cp, msg, eom, file); + fprintf(file,"\n\ttext = "); + cp = Print_cdname(cp, msg, eom, file); + (void) putc('\n', file); + break; + + case T_TXT: + (void) fputs("\ttext = \"", 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); + } + } + (void) fputs("\"\n", file); + break; + + case T_X25: + (void) fputs("\tX25 = \"", 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); + } + } + (void) fputs("\"\n", file); + break; + + case T_NSAP: + fprintf(file, "\tnsap = %s\n", inet_nsap_ntoa(dlen, cp, NULL)); + cp += dlen; + break; + + case T_UINFO: + fprintf(file,"\tuser info = %s\n", cp); + cp += dlen; + break; + + case T_UID: + case T_GID: + if (dlen == 4) { + fprintf(file,"\t%cid = %u\n",type == T_UID ? 'u' : 'g', + _getlong((u_char*)cp)); + cp += INT32SZ; + } else { + fprintf(file,"\t%cid of length %d?\n", + type == T_UID ? 'u' : 'g', dlen); + cp += dlen; + } + break; + + case T_WKS: { + struct protoent *protoPtr; + + if (dlen < INT32SZ + 1) + break; + if (!debug) + (void) putc('\n', file); + bcopy(cp, (char *)&inaddr, INADDRSZ); + cp += INT32SZ; + if ((protoPtr = getprotobynumber(*cp)) != NULL) { + fprintf(file,"\tinet address = %s, protocol = %s\n\t", + inet_ntoa(inaddr), protoPtr->p_name); + } else { + fprintf(file,"\tinet address = %s, protocol = %d\n\t", + inet_ntoa(inaddr), *cp); + } + cp++; + n = 0; + while (cp < cp1 + dlen) { + c = *cp++; + do { + struct servent *s; + + if (c & 0200) { + s = getservbyport((int)htons(n), + protoPtr ? protoPtr->p_name : NULL); + if (s != NULL) { + fprintf(file," %s", s->s_name); + } else { + fprintf(file," #%d", n); + } + } + c <<= 1; + } while (++n & 07); + } + putc('\n',file); + } + break; + + case T_NULL: + fprintf(file, "\tNULL (dlen %d)\n", dlen); + cp += dlen; + break; + + default: + fprintf(file,"\t??? unknown type %d ???\n", type); + cp += dlen; + } + if (_res.options & RES_DEBUG && type != T_SOA) { + fprintf(file,"\tttl = %lu (%s)\n", rrttl, p_time(rrttl)); + } + if (cp != cp1 + dlen) { + fprintf(file, + "\n*** Error: record size incorrect (%d != %d)\n\n", + cp - cp1, dlen); + cp = NULL; + } + return (cp); +} diff --git a/usr.sbin/nslookup/getinfo.c b/usr.sbin/nslookup/getinfo.c new file mode 100644 index 0000000..610d57ad --- /dev/null +++ b/usr.sbin/nslookup/getinfo.c @@ -0,0 +1,828 @@ +/* + * ++Copyright++ 1985, 1989 + * - + * Copyright (c) 1985, 1989 + * 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. + * - + * --Copyright-- + */ + +#ifndef lint +static char sccsid[] = "@(#)getinfo.c 5.26 (Berkeley) 3/21/91"; +static char rcsid[] = "$Id: getinfo.c,v 4.9.1.6 1994/06/01 21:10:16 vixie Exp $"; +#endif /* not lint */ + +/* + ****************************************************************************** + * + * getinfo.c -- + * + * Routines to create requests to name servers + * and interpret the answers. + * + * Adapted from 4.3BSD BIND gethostnamadr.c + * + ****************************************************************************** + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "res.h" +#include "../../conf/portability.h" + +extern char *_res_resultcodes[]; +extern char *res_skip(); + +#define MAXALIASES 35 +#define MAXADDRS 35 +#define MAXDOMAINS 35 +#define MAXSERVERS 10 + +static char *addr_list[MAXADDRS + 1]; + +static char *host_aliases[MAXALIASES]; +static int host_aliases_len[MAXALIASES]; +static u_char hostbuf[BUFSIZ+1]; + +typedef struct { + char *name; + char *domain[MAXDOMAINS]; + int numDomains; + char *address[MAXADDRS]; + int numAddresses; +} ServerTable; + +ServerTable server[MAXSERVERS]; + +typedef union { + HEADER qb1; + u_char qb2[PACKETSZ*2]; +} querybuf; + +typedef union { + int32_t al; + char ac; +} align; + +#define GetShort(cp) _getshort(cp); cp += INT16SZ; + + +/* + ****************************************************************************** + * + * GetAnswer -- + * + * Interprets an answer packet and retrieves the following + * information: + * + * Results: + * SUCCESS the info was retrieved. + * NO_INFO the packet did not contain an answer. + * NONAUTH non-authoritative information was found. + * ERROR the answer was malformed. + * Other errors returned in the packet header. + * + ****************************************************************************** + */ + +static int +GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr, isServer) + struct in_addr *nsAddrPtr; + char *msg; + int queryType; + int msglen; + Boolean iquery; + register HostInfo *hostPtr; + Boolean isServer; +{ + register HEADER *headerPtr; + register u_char *cp; + querybuf answer; + char **aliasPtr; + u_char *eom, *bp; + char **addrPtr; + char *namePtr; + char *dnamePtr; + int type, class; + int qdcount, ancount, arcount, nscount, buflen; + int origClass; + int numAliases = 0; + int numAddresses = 0; + int n, i, j; + int len; + int dlen; + int status; + int numServers; + Boolean haveAnswer; + Boolean printedAnswers = FALSE; + + + /* + * If the hostPtr was used before, free up the calloc'd areas. + */ + FreeHostInfoPtr(hostPtr); + + status = SendRequest(nsAddrPtr, msg, msglen, (char *) &answer, + sizeof(answer), &n); + + if (status != SUCCESS) { + if (_res.options & RES_DEBUG2) + printf("SendRequest failed\n"); + return (status); + } + eom = (u_char *) &answer + n; + + headerPtr = (HEADER *) &answer; + + if (headerPtr->rcode != NOERROR) { + return (headerPtr->rcode); + } + + qdcount = ntohs(headerPtr->qdcount); + ancount = ntohs(headerPtr->ancount); + arcount = ntohs(headerPtr->arcount); + nscount = ntohs(headerPtr->nscount); + + /* + * If there are no answer, n.s. or additional records + * then return with an error. + */ + if (ancount == 0 && nscount == 0 && arcount == 0) { + return (NO_INFO); + } + + + bp = hostbuf; + buflen = sizeof(hostbuf); + cp = (u_char *) &answer + HFIXEDSZ; + + /* Skip over question section. */ + while (qdcount-- > 0) { + cp += dn_skipname(cp, eom) + QFIXEDSZ; + } + + aliasPtr = host_aliases; + addrPtr = addr_list; + haveAnswer = FALSE; + + /* + * Scan through the answer resource records. + * Answers for address query types are saved. + * Other query type answers are just printed. + */ + if (ancount != 0) { + if (!isServer && !headerPtr->aa) { + printf("Non-authoritative answer:\n"); + } + + if (queryType != T_A && !(iquery && queryType == T_PTR)) { + while (--ancount >= 0 && cp < eom) { + if ((cp = (u_char *)Print_rr(cp, + (char *)&answer, eom, stdout)) == NULL) { + return(ERROR); + } + } + printedAnswers = TRUE; + } else { + while (--ancount >= 0 && cp < eom) { + n = dn_expand(answer.qb2, eom, cp, (char *)bp, buflen); + if (n < 0) { + return(ERROR); + } + cp += n; + type = GetShort(cp); + class = GetShort(cp); + cp += INT32SZ; /* skip TTL */ + dlen = GetShort(cp); + if (type == T_CNAME) { + /* + * Found an alias. + */ + cp += dlen; + if (aliasPtr >= &host_aliases[MAXALIASES-1]) { + continue; + } + *aliasPtr++ = (char *)bp; + n = strlen((char *)bp) + 1; + host_aliases_len[numAliases] = n; + numAliases++; + bp += n; + buflen -= n; + continue; + } else if (type == T_PTR) { + /* + * Found a "pointer" to the real name. + */ + n = dn_expand(answer.qb2, eom, cp, (char *)bp, buflen); + if (n < 0) { + cp += n; + continue; + } + cp += n; + len = strlen((char *)bp) + 1; + hostPtr->name = Calloc(1, len); + bcopy(bp, hostPtr->name, len); + haveAnswer = TRUE; + break; + } else if (type != T_A) { + cp += dlen; + continue; + } + if (haveAnswer) { + /* + * If we've already got 1 address, we aren't interested + * in addresses with a different length or class. + */ + if (dlen != hostPtr->addrLen) { + cp += dlen; + continue; + } + if (class != origClass) { + cp += dlen; + continue; + } + } else { + /* + * First address: record its length and class so we + * only save additonal ones with the same attributes. + */ + hostPtr->addrLen = dlen; + origClass = class; + hostPtr->addrType = (class == C_IN) ? AF_INET : AF_UNSPEC; + len = strlen((char *)bp) + 1; + hostPtr->name = Calloc(1, len); + bcopy(bp, hostPtr->name, len); + } + bp += (((u_int32_t)bp) % sizeof(align)); + + if (bp + dlen >= &hostbuf[sizeof(hostbuf)]) { + if (_res.options & RES_DEBUG) { + printf("Size (%d) too big\n", dlen); + } + break; + } + bcopy(cp, *addrPtr++ = (char *)bp, dlen); + bp +=dlen; + cp += dlen; + numAddresses++; + haveAnswer = TRUE; + } + } + } + + if ((queryType == T_A || queryType == T_PTR) && haveAnswer) { + + /* + * Go through the alias and address lists and return them + * in the hostPtr variable. + */ + + if (numAliases > 0) { + hostPtr->aliases = + (char **) Calloc(1 + numAliases, sizeof(char *)); + for (i = 0; i < numAliases; i++) { + hostPtr->aliases[i] = Calloc(1, host_aliases_len[i]); + bcopy(host_aliases[i], + hostPtr->aliases[i], + host_aliases_len[i]); + } + hostPtr->aliases[i] = NULL; + } + if (numAddresses > 0) { + hostPtr->addrList = + (char **)Calloc(1+numAddresses, sizeof(char *)); + for (i = 0; i < numAddresses; i++) { + hostPtr->addrList[i] = Calloc(1, hostPtr->addrLen); + bcopy(addr_list[i], hostPtr->addrList[i], hostPtr->addrLen); + } + hostPtr->addrList[i] = NULL; + } +#ifdef verbose + if (headerPtr->aa || nscount == 0) { + hostPtr->servers = NULL; + return (SUCCESS); + } +#else + hostPtr->servers = NULL; + return (SUCCESS); +#endif + } + + /* + * At this point, for the T_A query type, only empty answers remain. + * For other query types, additional information might be found + * in the additional resource records part. + */ + + if (!headerPtr->aa && (queryType != T_A) && (nscount > 0 || arcount > 0)) { + if (printedAnswers) { + putchar('\n'); + } + printf("Authoritative answers can be found from:\n"); + } + + cp = (u_char *)res_skip((char *) &answer, 2, eom); + + numServers = 0; + if (queryType != T_A) { + /* + * If we don't need to save the record, just print it. + */ + while (--nscount >= 0 && cp < eom) { + if ((cp = (u_char *)Print_rr(cp, + (char *) &answer, eom, stdout)) == NULL) { + return(ERROR); + } + } + } else { + while (--nscount >= 0 && cp < eom) { + /* + * Go through the NS records and retrieve the names of hosts + * that serve the requested domain. + */ + + n = dn_expand(answer.qb2, eom, cp, (char *)bp, buflen); + if (n < 0) { + return(ERROR); + } + cp += n; + len = strlen((char *)bp) + 1; + dnamePtr = Calloc(1, len); /* domain name */ + bcopy(bp, dnamePtr, len); + + type = GetShort(cp); + class = GetShort(cp); + cp += INT32SZ; /* skip TTL */ + dlen = GetShort(cp); + + if (type != T_NS) { + cp += dlen; + } else { + Boolean found; + + n = dn_expand(answer.qb2, eom, cp, (char *)bp, buflen); + if (n < 0) { + return(ERROR); + } + cp += n; + len = strlen((char *)bp) + 1; + namePtr = Calloc(1, len); /* server host name */ + bcopy(bp, namePtr, len); + + /* + * Store the information keyed by the server host name. + */ + found = FALSE; + for (j = 0; j < numServers; j++) { + if (strcmp(namePtr, server[j].name) == 0) { + found = TRUE; + free(namePtr); + break; + } + } + if (found) { + server[j].numDomains++; + if (server[j].numDomains <= MAXDOMAINS) { + server[j].domain[server[j].numDomains-1] = dnamePtr; + } + } else { + if (numServers >= MAXSERVERS) { + break; + } + server[numServers].name = namePtr; + server[numServers].domain[0] = dnamePtr; + server[numServers].numDomains = 1; + server[numServers].numAddresses = 0; + numServers++; + } + } + } + } + + /* + * Additional resource records contain addresses of servers. + */ + cp = (u_char *)res_skip((char *) &answer, 3, eom); + + if (queryType != T_A) { + /* + * If we don't need to save the record, just print it. + */ + while (--arcount >= 0 && cp < eom) { + if ((cp = (u_char *)Print_rr(cp, + (char *) &answer, eom, stdout)) == NULL) { + return(ERROR); + } + } + } else { + while (--arcount >= 0 && cp < eom) { + n = dn_expand(answer.qb2, eom, cp, (char *)bp, buflen); + if (n < 0) { + break; + } + cp += n; + type = GetShort(cp); + class = GetShort(cp); + cp += INT32SZ; /* skip TTL */ + dlen = GetShort(cp); + + if (type != T_A) { + cp += dlen; + continue; + } else { + for (j = 0; j < numServers; j++) { + if (strcmp((char *)bp, server[j].name) == 0) { + server[j].numAddresses++; + if (server[j].numAddresses <= MAXADDRS) { + server[j].address[server[j].numAddresses-1] = + Calloc(1,dlen); + bcopy(cp, + server[j].address[server[j].numAddresses-1],dlen); + break; + } + } + } + cp += dlen; + } + } + } + + /* + * If we are returning name server info, transfer it to the hostPtr. + */ + if (numServers > 0) { + hostPtr->servers = (ServerInfo **) + Calloc(numServers+1, sizeof(ServerInfo *)); + + for (i = 0; i < numServers; i++) { + hostPtr->servers[i] = (ServerInfo *) Calloc(1, sizeof(ServerInfo)); + hostPtr->servers[i]->name = server[i].name; + + + hostPtr->servers[i]->domains = (char **) + Calloc(server[i].numDomains+1,sizeof(char *)); + for (j = 0; j < server[i].numDomains; j++) { + hostPtr->servers[i]->domains[j] = server[i].domain[j]; + } + hostPtr->servers[i]->domains[j] = NULL; + + + hostPtr->servers[i]->addrList = (char **) + Calloc(server[i].numAddresses+1,sizeof(char *)); + for (j = 0; j < server[i].numAddresses; j++) { + hostPtr->servers[i]->addrList[j] = server[i].address[j]; + } + hostPtr->servers[i]->addrList[j] = NULL; + + } + hostPtr->servers[i] = NULL; + } + + switch (queryType) { + case T_A: + return NONAUTH; + case T_PTR: + if (iquery) + return NO_INFO; + /* fall through */ + default: + return SUCCESS; + } +} + +/* +******************************************************************************* +* +* GetHostInfo -- +* +* Retrieves host name, address and alias information +* for a domain. +* +* Algorithm from res_search(). +* +* Results: +* ERROR - res_mkquery failed. +* + return values from GetAnswer() +* +******************************************************************************* +*/ + +int +GetHostInfoByName(nsAddrPtr, queryClass, queryType, name, hostPtr, isServer) + struct in_addr *nsAddrPtr; + int queryClass; + int queryType; + char *name; + HostInfo *hostPtr; + Boolean isServer; +{ + int n; + register int result; + register char *cp, **domain; + Boolean got_nodata = FALSE; + struct in_addr ina; + + /* Catch explicit addresses */ + if ((queryType == T_A) && IsAddr(name, &ina)) { + hostPtr->name = Calloc(strlen(name)+3, 1); + (void)sprintf(hostPtr->name,"[%s]",name); + hostPtr->aliases = NULL; + hostPtr->servers = NULL; + hostPtr->addrType = AF_INET; + hostPtr->addrLen = INADDRSZ; + hostPtr->addrList = (char **)Calloc(2, sizeof(char *)); + hostPtr->addrList[0] = Calloc(INT32SZ, sizeof(char)); + bcopy((char *)&ina, hostPtr->addrList[0], INADDRSZ); + hostPtr->addrList[1] = NULL; + return(SUCCESS); + } + + result = NXDOMAIN; + for (cp = name, n = 0; *cp; cp++) + if (*cp == '.') + n++; + if (n == 0 && (cp = hostalias(name))) { + printf("Aliased to \"%s\"\n\n", cp); + return (GetHostDomain(nsAddrPtr, queryClass, queryType, + cp, (char *)NULL, hostPtr, isServer)); + } + /* + * We do at least one level of search if + * - there is no dot and RES_DEFNAME is set, or + * - there is at least one dot, there is no trailing dot, + * and RES_DNSRCH is set. + */ + if ((n == 0 && _res.options & RES_DEFNAMES) || + (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH)) + for (domain = _res.dnsrch; *domain; domain++) { + result = GetHostDomain(nsAddrPtr, queryClass, queryType, + name, *domain, hostPtr, isServer); + /* + * If no server present, give up. + * If name isn't found in this domain, + * keep trying higher domains in the search list + * (if that's enabled). + * On a NO_INFO error, keep trying, otherwise + * a wildcard entry of another type could keep us + * from finding this entry higher in the domain. + * If we get some other error (negative answer or + * server failure), then stop searching up, + * but try the input name below in case it's fully-qualified. + */ + if (result == SUCCESS || result == NO_RESPONSE) + return result; + if (result == NO_INFO) + got_nodata++; + if ((result != NXDOMAIN && result != NO_INFO) || + (_res.options & RES_DNSRCH) == 0) + break; + } + /* + * If the search/default failed, try the name as fully-qualified, + * but only if it contained at least one dot (even trailing). + * This is purely a heuristic; we assume that any reasonable query + * about a top-level domain (for servers, SOA, etc) will not use + * res_search. + */ + if (n && (result = GetHostDomain(nsAddrPtr, queryClass, queryType, + name, (char *)NULL, hostPtr, isServer)) == SUCCESS) + return result; + if (got_nodata) + result = NO_INFO; + return (result); +} + +/* + * Perform a query on the concatenation of name and domain, + * removing a trailing dot from name if domain is NULL. + */ +GetHostDomain(nsAddrPtr, queryClass, queryType, name, domain, hostPtr, isServer) + struct in_addr *nsAddrPtr; + int queryClass; + int queryType; + char *name, *domain; + HostInfo *hostPtr; + Boolean isServer; +{ + querybuf buf; + char nbuf[2*MAXDNAME+2]; + char *longname = nbuf; + int n; + + if (domain == NULL) { + /* + * Check for trailing '.'; + * copy without '.' if present. + */ + n = strlen(name) - 1; + if (name[n] == '.' && n < sizeof(nbuf) - 1) { + bcopy(name, nbuf, n); + nbuf[n] = '\0'; + } else + longname = name; + } else { + (void)sprintf(nbuf, "%.*s.%.*s", + MAXDNAME, name, MAXDNAME, domain); + longname = nbuf; + } + n = res_mkquery(QUERY, longname, queryClass, queryType, + NULL, 0, 0, buf.qb2, sizeof(buf)); + if (n < 0) { + if (_res.options & RES_DEBUG) { + printf("Res_mkquery failed\n"); + } + return (ERROR); + } + + n = GetAnswer(nsAddrPtr, queryType, (char *)&buf, n, 0, hostPtr, isServer); + + /* + * GetAnswer didn't find a name, so set it to the specified one. + */ + if (n == NONAUTH) { + if (hostPtr->name == NULL) { + int len = strlen(longname) + 1; + hostPtr->name = Calloc(len, sizeof(char)); + bcopy(longname, hostPtr->name, len); + } + } + return(n); +} + + +/* +******************************************************************************* +* +* GetHostInfoByAddr -- +* +* Performs a PTR lookup in in-addr.arpa to find the host name +* that corresponds to the given address. +* +* Results: +* ERROR - res_mkquery failed. +* + return values from GetAnswer() +* +******************************************************************************* +*/ + +int +GetHostInfoByAddr(nsAddrPtr, address, hostPtr) + struct in_addr *nsAddrPtr; + struct in_addr *address; + HostInfo *hostPtr; +{ + int n; + querybuf buf; + char qbuf[MAXDNAME]; + char *p = (char *) &address->s_addr; + + (void)sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa", + ((unsigned)p[3] & 0xff), + ((unsigned)p[2] & 0xff), + ((unsigned)p[1] & 0xff), + ((unsigned)p[0] & 0xff)); + n = res_mkquery(QUERY, qbuf, C_IN, T_PTR, NULL, 0, NULL, + buf.qb2, sizeof buf); + if (n < 0) { + if (_res.options & RES_DEBUG) { + printf("res_mkquery() failed\n"); + } + return (ERROR); + } + n = GetAnswer(nsAddrPtr, T_PTR, (char *) &buf, n, 1, hostPtr, 1); + if (n == SUCCESS) { + hostPtr->addrType = AF_INET; + hostPtr->addrLen = 4; + hostPtr->addrList = (char **)Calloc(2, sizeof(char *)); + hostPtr->addrList[0] = Calloc(INT32SZ, sizeof(char)); + bcopy((char *)p, hostPtr->addrList[0], INADDRSZ); + hostPtr->addrList[1] = NULL; + } + return n; +} + +/* +******************************************************************************* +* +* FreeHostInfoPtr -- +* +* Deallocates all the calloc'd areas for a HostInfo variable. +* +******************************************************************************* +*/ + +void +FreeHostInfoPtr(hostPtr) + register HostInfo *hostPtr; +{ + int i, j; + + if (hostPtr->name != NULL) { + free(hostPtr->name); + hostPtr->name = NULL; + } + + if (hostPtr->aliases != NULL) { + i = 0; + while (hostPtr->aliases[i] != NULL) { + free(hostPtr->aliases[i]); + i++; + } + free((char *)hostPtr->aliases); + hostPtr->aliases = NULL; + } + + if (hostPtr->addrList != NULL) { + i = 0; + while (hostPtr->addrList[i] != NULL) { + free(hostPtr->addrList[i]); + i++; + } + free((char *)hostPtr->addrList); + hostPtr->addrList = NULL; + } + + if (hostPtr->servers != NULL) { + i = 0; + while (hostPtr->servers[i] != NULL) { + + if (hostPtr->servers[i]->name != NULL) { + free(hostPtr->servers[i]->name); + } + + if (hostPtr->servers[i]->domains != NULL) { + j = 0; + while (hostPtr->servers[i]->domains[j] != NULL) { + free(hostPtr->servers[i]->domains[j]); + j++; + } + free((char *)hostPtr->servers[i]->domains); + } + + if (hostPtr->servers[i]->addrList != NULL) { + j = 0; + while (hostPtr->servers[i]->addrList[j] != NULL) { + free(hostPtr->servers[i]->addrList[j]); + j++; + } + free((char *)hostPtr->servers[i]->addrList); + } + free((char *)hostPtr->servers[i]); + i++; + } + free((char *)hostPtr->servers); + hostPtr->servers = NULL; + } +} diff --git a/usr.sbin/nslookup/list.c b/usr.sbin/nslookup/list.c new file mode 100644 index 0000000..e78d143 --- /dev/null +++ b/usr.sbin/nslookup/list.c @@ -0,0 +1,991 @@ +/* + * ++Copyright++ 1985, 1989 + * - + * Copyright (c) 1985, 1989 + * 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. + * - + * --Copyright-- + */ + +#ifndef lint +static char sccsid[] = "@(#)list.c 5.23 (Berkeley) 3/21/91"; +static char rcsid[] = "$Id: list.c,v 4.9.1.11 1994/06/06 09:08:43 vixie Exp $"; +#endif /* not lint */ + +/* + ******************************************************************************* + * + * list.c -- + * + * Routines to obtain info from name and finger servers. + * + * Adapted from 4.3BSD BIND ns_init.c and from finger.c. + * + ******************************************************************************* + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "res.h" +#include "../../conf/portability.h" + +extern char *_res_resultcodes[]; /* res_debug.c */ +extern char *pager; + +typedef union { + HEADER qb1; + u_char qb2[PACKETSZ]; +} querybuf; + +extern HostInfo *defaultPtr; +extern HostInfo curHostInfo; +extern int curHostValid; +extern int queryType; +extern int queryClass; + +static int sockFD = -1; +int ListSubr(); + +/* + * During a listing to a file, hash marks are printed + * every HASH_SIZE records. + */ + +#define HASH_SIZE 50 + + +/* + ******************************************************************************* + * + * ListHosts -- + * ListHostsByType -- + * + * Requests the name server to do a zone transfer so we + * find out what hosts it knows about. + * + * For ListHosts, there are five types of output: + * - Internet addresses (default) + * - cpu type and operating system (-h option) + * - canonical and alias names (-a option) + * - well-known service names (-s option) + * - ALL records (-d option) + * ListHostsByType prints records of the default type or of a speicific + * type. + * + * To see all types of information sorted by name, do the following: + * ls -d domain.edu > file + * view file + * + * Results: + * SUCCESS the listing was successful. + * ERROR the server could not be contacted because + * a socket could not be obtained or an error + * occured while receiving, or the output file + * could not be opened. + * + ******************************************************************************* + */ + +void +ListHostsByType(string, putToFile) + char *string; + int putToFile; +{ + int i, qtype, result; + char *namePtr; + char name[NAME_LEN]; + char option[NAME_LEN]; + + /* + * Parse the command line. It maybe of the form "ls -t domain" + * or "ls -t type domain". + */ + + i = sscanf(string, " ls -t %s %s", option, name); + if (putToFile && i == 2 && name[0] == '>') { + i--; + } + if (i == 2) { + qtype = StringToType(option, -1, stderr); + if (qtype == -1) + return; + namePtr = name; + } else if (i == 1) { + namePtr = option; + qtype = queryType; + } else { + fprintf(stderr, "*** ls: invalid request %s\n",string); + return; + } + result = ListSubr(qtype, namePtr, putToFile ? string : NULL); + if (result != SUCCESS) + fprintf(stderr, "*** Can't list domain %s: %s\n", + namePtr, DecodeError(result)); +} + +void +ListHosts(string, putToFile) + char *string; + int putToFile; +{ + int i, qtype, result; + char *namePtr; + char name[NAME_LEN]; + char option[NAME_LEN]; + + /* + * Parse the command line. It maybe of the form "ls domain", + * "ls -X domain". + */ + i = sscanf(string, " ls %s %s", option, name); + if (putToFile && i == 2 && name[0] == '>') { + i--; + } + if (i == 2) { + if (strcmp("-a", option) == 0) { + qtype = T_CNAME; + } else if (strcmp("-h", option) == 0) { + qtype = T_HINFO; + } else if (strcmp("-m", option) == 0) { + qtype = T_MX; + } else if (strcmp("-s", option) == 0) { + qtype = T_WKS; + } else if (strcmp("-d", option) == 0) { + qtype = T_ANY; + } else { + qtype = T_A; + } + namePtr = name; + } else if (i == 1) { + namePtr = option; + qtype = T_A; + } else { + fprintf(stderr, "*** ls: invalid request %s\n",string); + return; + } + result = ListSubr(qtype, namePtr, putToFile ? string : NULL); + if (result != SUCCESS) + fprintf(stderr, "*** Can't list domain %s: %s\n", + namePtr, DecodeError(result)); +} + +int +ListSubr(qtype, domain, cmd) + int qtype; + char *domain; + char *cmd; +{ + querybuf buf; + struct sockaddr_in sin; + HEADER *headerPtr; + int msglen; + int amtToRead; + int numRead; + int numAnswers = 0; + int result; + int soacnt = 0; + u_short len; + u_char *cp, *nmp; + char dname[2][NAME_LEN]; + char file[NAME_LEN]; + static u_char *answer = NULL; + static int answerLen = 0; + enum { + NO_ERRORS, + ERR_READING_LEN, + ERR_READING_MSG, + ERR_PRINTING + } error = NO_ERRORS; + + /* + * Create a query packet for the requested domain name. + */ + msglen = res_mkquery(QUERY, domain, queryClass, T_AXFR, + NULL, 0, 0, buf.qb2, sizeof buf); + if (msglen < 0) { + if (_res.options & RES_DEBUG) { + fprintf(stderr, "*** ls: res_mkquery failed\n"); + } + return (ERROR); + } + + bzero((char *)&sin, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons(nsport); + + /* + * Check to see if we have the address of the server or the + * address of a server who knows about this domain. + * + * For now, just use the first address in the list. + */ + + if (defaultPtr->addrList != NULL) { + sin.sin_addr = *(struct in_addr *) defaultPtr->addrList[0]; + } else { + sin.sin_addr = *(struct in_addr *)defaultPtr->servers[0]->addrList[0]; + } + + /* + * Set up a virtual circuit to the server. + */ + if ((sockFD = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("ls: socket"); + return(ERROR); + } + if (connect(sockFD, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + int e; + if (errno == ECONNREFUSED) { + e = NO_RESPONSE; + } else { + perror("ls: connect"); + e = ERROR; + } + (void) close(sockFD); + sockFD = -1; + return e; + } + + /* + * Send length & message for zone transfer + */ + + __putshort(msglen, (u_char *)&len); + + if (write(sockFD, (char *)&len, INT16SZ) != INT16SZ || + write(sockFD, (char *) &buf, msglen) != msglen) { + perror("ls: write"); + (void) close(sockFD); + sockFD = -1; + return(ERROR); + } + + fprintf(stdout,"[%s]\n", + (defaultPtr->addrList != NULL) ? defaultPtr->name : + defaultPtr->servers[0]->name); + + if (cmd == NULL) { + filePtr = stdout; + } else { + filePtr = OpenFile(cmd, file); + if (filePtr == NULL) { + fprintf(stderr, "*** Can't open %s for writing\n", file); + (void) close(sockFD); + sockFD = -1; + return(ERROR); + } + fprintf(filePtr, "> %s\n", cmd); + fprintf(filePtr,"[%s]\n", + (defaultPtr->addrList != NULL) ? defaultPtr->name : + defaultPtr->servers[0]->name); + } + +#if 0 + if (qtype == T_CNAME) { + fprintf(filePtr, "%-30s", "Alias"); + } else if (qtype == T_TXT) { + fprintf(filePtr, "%-30s", "Key"); + } else { + fprintf(filePtr, "%-30s", "Host or domain name"); + } + switch (qtype) { + case T_A: + fprintf(filePtr, " %-30s\n", "Internet Address"); + break; + case T_HINFO: + fprintf(filePtr, " %-30s\n", "CPU & OS"); + break; + case T_CNAME: + fprintf(filePtr, " %-30s\n", "Canonical Name"); + break; + case T_MX: + fprintf(filePtr, " %-30s\n", "Metric & Host"); + break; + case T_AFSDB: + fprintf(filePtr, " %-30s\n", "Subtype & Host"); + break; + case T_X25: + fprintf(filePtr, " %-30s\n", "X25 Address"); + break + case T_ISDN: + fprintf(filePtr, " %-30s\n", "ISDN Address"); + break + case T_WKS: + fprintf(filePtr, " %-4s %s\n", "Protocol", "Services"); + break; + case T_MB: + fprintf(filePtr, " %-30s\n", "Mailbox"); + break; + case T_MG: + fprintf(filePtr, " %-30s\n", "Mail Group"); + break; + case T_MR: + fprintf(filePtr, " %-30s\n", "Mail Rename"); + break; + case T_MINFO: + fprintf(filePtr, " %-30s\n", "Mail List Requests & Errors"); + break; + case T_UINFO: + fprintf(filePtr, " %-30s\n", "User Information"); + break; + case T_UID: + fprintf(filePtr, " %-30s\n", "User ID"); + break; + case T_GID: + fprintf(filePtr, " %-30s\n", "Group ID"); + break; + case T_TXT: + fprintf(filePtr, " %-30s\n", "Text"); + break; + case T_RP: + fprintf(filePtr, " %-30s\n", "Responsible Person"); + break; + case T_RT: + fprintf(filePtr, " %-30s\n", "Router"); + break; + case T_NSAP: + fprintf(filePtr, " %-30s\n", "NSAP address"); + break; + case T_NS: + fprintf(filePtr, " %-30s\n", "Name Servers"); + break; + case T_PTR: + fprintf(filePtr, " %-30s\n", "Pointers"); + break; + case T_SOA: + fprintf(filePtr, " %-30s\n", "Start of Authority"); + break; + case T_ANY: + fprintf(filePtr, " %-30s\n", "Resource Record Info."); + break; + } +#endif + + + dname[0][0] = '\0'; + while (1) { + unsigned short tmp; + + /* + * Read the length of the response. + */ + + cp = (u_char *)&tmp; + amtToRead = INT16SZ; + while ((numRead = read(sockFD, cp, amtToRead)) > 0) { + cp += numRead; + if ((amtToRead -= numRead) <= 0) + break; + } + if (numRead <= 0) { + error = ERR_READING_LEN; + break; + } + + if ((len = _getshort((u_char*)&tmp)) == 0) { + break; /* nothing left to read */ + } + + /* + * The server sent too much data to fit the existing buffer -- + * allocate a new one. + */ + if (len > answerLen) { + if (answerLen != 0) { + free(answer); + } + answerLen = len; + answer = (u_char *)Malloc(answerLen); + } + + /* + * Read the response. + */ + + amtToRead = len; + cp = answer; + while (amtToRead > 0 && (numRead=read(sockFD, cp, amtToRead)) > 0) { + cp += numRead; + amtToRead -= numRead; + } + if (numRead <= 0) { + error = ERR_READING_MSG; + break; + } + + result = PrintListInfo(filePtr, answer, cp, qtype, dname[0]); + if (result != SUCCESS) { + error = ERR_PRINTING; + break; + } + + numAnswers++; + if (cmd != NULL && ((numAnswers % HASH_SIZE) == 0)) { + fprintf(stdout, "#"); + fflush(stdout); + } + cp = answer + HFIXEDSZ; + if (ntohs(((HEADER* )answer)->qdcount) > 0) + cp += dn_skipname((u_char *)cp, + (u_char *)answer + len) + QFIXEDSZ; + nmp = cp; + cp += dn_skipname((u_char *)cp, (u_char *)answer + len); + if ((_getshort((u_char*)cp) == T_SOA)) { + (void) dn_expand(answer, answer + len, nmp, + dname[soacnt], sizeof dname[0]); + if (soacnt) { + if (strcmp(dname[0], dname[1]) == 0) + break; + } else + soacnt++; + } + } + + if (cmd != NULL) { + fprintf(stdout, "%sReceived %d record%s.\n", + (numAnswers >= HASH_SIZE) ? "\n" : "", + numAnswers, + (numAnswers != 1) ? "s" : ""); + } + + (void) close(sockFD); + sockFD = -1; + if (cmd != NULL && filePtr != NULL) { + fclose(filePtr); + filePtr = NULL; + } + + switch (error) { + case NO_ERRORS: + return (SUCCESS); + + case ERR_READING_LEN: + return(ERROR); + + case ERR_PRINTING: + return(result); + + case ERR_READING_MSG: + headerPtr = (HEADER *) answer; + fprintf(stderr,"*** ls: 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); + } +} + + +/* + ******************************************************************************* + * + * PrintListInfo -- + * + * Used by the ListInfo routine to print the answer + * received from the name server. Only the desired + * information is printed. + * + * Results: + * SUCCESS the answer was printed without a problem. + * NO_INFO the answer packet did not contain an answer. + * ERROR the answer was malformed. + * Misc. errors returned in the packet header. + * + ******************************************************************************* + */ + +#define NAME_FORMAT " %-30s" + +static Boolean +strip_domain(string, domain) + char *string, *domain; +{ + register char *dot; + + if (*domain != '\0') { + dot = string; + while ((dot = strchr(dot, '.')) != NULL && strcasecmp(domain, ++dot)) + ; + if (dot != NULL) { + dot[-1] = '\0'; + return TRUE; + } + } + return FALSE; +} + + +PrintListInfo(file, msg, eom, qtype, domain) + FILE *file; + u_char *msg, *eom; + int qtype; + char *domain; +{ + register u_char *cp; + HEADER *headerPtr; + int type, class, dlen, nameLen; + u_int32_t ttl; + int n, pref; + struct in_addr inaddr; + char name[NAME_LEN]; + char name2[NAME_LEN]; + Boolean stripped; + + /* + * Read the header fields. + */ + headerPtr = (HEADER *)msg; + cp = msg + HFIXEDSZ; + if (headerPtr->rcode != NOERROR) { + return(headerPtr->rcode); + } + + /* + * We are looking for info from answer resource records. + * If there aren't any, return with an error. We assume + * there aren't any question records. + */ + + if (ntohs(headerPtr->ancount) == 0) { + return(NO_INFO); + } else { + if (ntohs(headerPtr->qdcount) > 0) { + nameLen = dn_skipname(cp, eom); + if (nameLen < 0) + return (ERROR); + cp += nameLen + QFIXEDSZ; + } + nameLen = dn_expand(msg, eom, cp, name, sizeof name); + if (nameLen < 0) + return (ERROR); + cp += nameLen; + + type = _getshort((u_char*)cp); + cp += INT16SZ; + + if (!(type == qtype || qtype == T_ANY) && + !((type == T_NS || type == T_PTR) && qtype == T_A)) + return(SUCCESS); + + class = _getshort((u_char*)cp); + cp += INT16SZ; + ttl = _getlong((u_char*)cp); + cp += INT32SZ; + dlen = _getshort((u_char*)cp); + cp += INT16SZ; + + if (name[0] == 0) + strcpy(name, "(root)"); + + /* Strip the domain name from the data, if desired. */ + stripped = FALSE; + if ((_res.options & RES_DEBUG) == 0) { + if (type != T_SOA) { + stripped = strip_domain(name, domain); + } + } + if (!stripped && nameLen < sizeof(name)-1) { + strcat(name, "."); + } + + fprintf(file, NAME_FORMAT, name); + + if (qtype == T_ANY) { + if (_res.options & RES_DEBUG) { + fprintf(file,"\t%lu %-5s", ttl, p_class(queryClass)); + } + fprintf(file," %-5s", p_type(type)); + } + + /* XXX merge this into debug.c's print routines */ + + switch (type) { + case T_A: + if (class == C_IN) { + bcopy(cp, (char *)&inaddr, INADDRSZ); + if (dlen == 4) { + fprintf(file," %s", inet_ntoa(inaddr)); + } else if (dlen == 7) { + fprintf(file," %s", inet_ntoa(inaddr)); + fprintf(file," (%d, %d)", cp[4],(cp[5] << 8) + cp[6]); + } else + fprintf(file, " (dlen = %d?)", dlen); + } + break; + + case T_CNAME: + case T_MB: + case T_MG: + case T_MR: + nameLen = dn_expand(msg, eom, cp, name2, sizeof name2); + if (nameLen < 0) { + fprintf(file, " ***\n"); + return (ERROR); + } + fprintf(file, " %s", name2); + break; + + case T_NS: + case T_PTR: + putc(' ', file); + if (qtype != T_ANY) + fprintf(file,"%s = ", type == T_PTR ? "host" : "server"); + cp = (u_char *)Print_cdname2(cp, msg, eom, file); + break; + + case T_HINFO: + case T_ISDN: + if (n = *cp++) { + (void)sprintf(name,"%.*s", n, cp); + fprintf(file," %-10s", name); + cp += n; + } else { + fprintf(file," %-10s", " "); + } + if (n = *cp++) { + fprintf(file," %.*s", n, cp); + cp += n; + } + break; + + case T_SOA: + nameLen = dn_expand(msg, eom, cp, name2, sizeof name2); + if (nameLen < 0) { + fprintf(file, " ***\n"); + return (ERROR); + } + cp += nameLen; + fprintf(file, " %s", name2); + nameLen = dn_expand(msg, eom, cp, name2, sizeof name2); + if (nameLen < 0) { + fprintf(file, " ***\n"); + return (ERROR); + } + cp += nameLen; + fprintf(file, " %s. (", name2); + for (n = 0; n < 5; n++) { + u_int32_t u; + + u = _getlong((u_char*)cp); + cp += INT32SZ; + fprintf(file,"%s%lu", n? " " : "", u); + } + fprintf(file, ")"); + break; + + case T_MX: + case T_AFSDB: + case T_RT: + pref = _getshort((u_char*)cp); + cp += INT16SZ; + fprintf(file," %-3d ",pref); + nameLen = dn_expand(msg, eom, cp, name2, sizeof name2); + if (nameLen < 0) { + fprintf(file, " ***\n"); + return (ERROR); + } + fprintf(file, " %s", name2); + break; + + case T_TXT: + case T_X25: + { + u_char *cp2 = cp + dlen; + int c; + + (void) fputs(" \"", file); + 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); + } + } + (void) putc('"', file); + } + break; + + case T_NSAP: + fprintf(file, " %s", inet_nsap_ntoa(dlen, cp, NULL)); + break; + + case T_MINFO: + case T_RP: + (void) putc(' ', file); + cp = (u_char *)Print_cdname(cp, msg, eom, file); + fprintf(file, " "); + cp = (u_char *)Print_cdname(cp, msg, eom, file); + break; + + case T_UINFO: + fprintf(file, " %s", cp); + break; + + case T_UID: + case T_GID: + fprintf(file, " %lu", _getlong((u_char*)cp)); + break; + + case T_WKS: + if (class == C_IN) { + struct protoent *pp; + struct servent *ss; + u_short port; + + cp += 4; /* skip inet address */ + dlen -= 4; + + setprotoent(1); + setservent(1); + n = *cp & 0377; + pp = getprotobynumber(n); + if (pp == 0) + fprintf(file," %-3d ", n); + else + fprintf(file," %-3s ", pp->p_name); + cp++; dlen--; + + port = 0; + while (dlen-- > 0) { + n = *cp++; + do { + if (n & 0200) { + ss = getservbyport((int)htons(port), + pp->p_name); + if (ss == 0) + fprintf(file," %u", port); + else + fprintf(file," %s", ss->s_name); + } + n <<= 1; + } while (++port & 07); + } + endprotoent(); + endservent(); + } + break; + } + fprintf(file,"\n"); + } + return(SUCCESS); +} + + +/* + ******************************************************************************* + * + * ViewList -- + * + * A hack to view the output of the ls command in sorted + * order using more. + * + ******************************************************************************* + */ + +ViewList(string) + char *string; +{ + char file[PATH_MAX]; + char command[PATH_MAX]; + + sscanf(string, " view %s", file); + (void)sprintf(command, "grep \"^ \" %s | sort | %s", file, pager); + system(command); +} + +/* + ******************************************************************************* + * + * Finger -- + * + * Connects with the finger server for the current host + * to request info on the specified person (long form) + * who is on the system (short form). + * + * Results: + * SUCCESS the finger server was contacted. + * ERROR the server could not be contacted because + * a socket could not be obtained or connected + * to or the service could not be found. + * + ******************************************************************************* + */ + +Finger(string, putToFile) + char *string; + int putToFile; +{ + struct servent *sp; + struct sockaddr_in sin; + register FILE *f; + register int c; + register int lastc; + char name[NAME_LEN]; + char file[NAME_LEN]; + + /* + * We need a valid current host info to get an inet address. + */ + if (!curHostValid) { + fprintf(stderr, "Finger: no current host defined.\n"); + return (ERROR); + } + + if (sscanf(string, " finger %s", name) == 1) { + if (putToFile && (name[0] == '>')) { + name[0] = '\0'; + } + } else { + name[0] = '\0'; + } + + sp = getservbyname("finger", "tcp"); + if (sp == 0) { + fprintf(stderr, "Finger: unknown service\n"); + return (ERROR); + } + + bzero((char *)&sin, sizeof(sin)); + sin.sin_family = curHostInfo.addrType; + sin.sin_port = sp->s_port; + bcopy(curHostInfo.addrList[0], (char *)&sin.sin_addr, + curHostInfo.addrLen); + + /* + * Set up a virtual circuit to the host. + */ + + sockFD = socket(curHostInfo.addrType, SOCK_STREAM, 0); + if (sockFD < 0) { + fflush(stdout); + perror("finger: socket"); + return (ERROR); + } + + if (connect(sockFD, (struct sockaddr *)&sin, sizeof (sin)) < 0) { + fflush(stdout); + perror("finger: connect"); + close(sockFD); + sockFD = -1; + return (ERROR); + } + + if (!putToFile) { + filePtr = stdout; + } else { + filePtr = OpenFile(string, file); + if (filePtr == NULL) { + fprintf(stderr, "*** Can't open %s for writing\n", file); + close(sockFD); + sockFD = -1; + return(ERROR); + } + fprintf(filePtr,"> %s\n", string); + } + fprintf(filePtr, "[%s]\n", curHostInfo.name); + + if (name[0] != '\0') { + write(sockFD, "/W ", 3); + } + write(sockFD, name, strlen(name)); + write(sockFD, "\r\n", 2); + f = fdopen(sockFD, "r"); + lastc = '\n'; + while ((c = getc(f)) != EOF) { + switch (c) { + case 0210: + case 0211: + case 0212: + case 0214: + c -= 0200; + break; + case 0215: + c = '\n'; + break; + } + putc(lastc = c, filePtr); + } + if (lastc != '\n') { + putc('\n', filePtr); + } + putc('\n', filePtr); + + close(sockFD); + sockFD = -1; + + if (putToFile) { + fclose(filePtr); + filePtr = NULL; + } + return (SUCCESS); +} + +ListHost_close() +{ + if (sockFD != -1) { + (void) close(sockFD); + sockFD = -1; + } +} diff --git a/usr.sbin/nslookup/main.c b/usr.sbin/nslookup/main.c new file mode 100644 index 0000000..2324ed8 --- /dev/null +++ b/usr.sbin/nslookup/main.c @@ -0,0 +1,1112 @@ +/* + * ++Copyright++ 1985, 1989 + * - + * Copyright (c) 1985, 1989 + * 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. + * - + * --Copyright-- + */ + +#ifndef lint +char copyright[] = +"@(#) Copyright (c) 1985,1989 Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)main.c 5.42 (Berkeley) 3/3/91"; +static char rcsid[] = "$Id: main.c,v 4.9.1.3 1993/09/16 09:02:07 vixie Exp $"; +#endif /* not lint */ + +/* + ****************************************************************************** + * + * main.c -- + * + * Main routine and some action routines for the name server + * lookup program. + * + * Andrew Cherenson + * U.C. Berkeley Computer Science Div. + * CS298-26, Fall 1985 + * + ****************************************************************************** + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "res.h" +#include "pathnames.h" +#include "../../conf/portability.h" + + +/* + * Name of a top-level name server. Can be changed with + * the "set root" command. + */ + +#ifndef ROOT_SERVER +#define ROOT_SERVER "ns.internic.net." +#endif +char rootServerName[NAME_LEN] = ROOT_SERVER; + + +/* + * Import the state information from the resolver library. + */ + +extern struct __res_state _res; + + +/* + * Info about the most recently queried host. + */ + +HostInfo curHostInfo; +int curHostValid = FALSE; + + +/* + * Info about the default name server. + */ + +HostInfo *defaultPtr = NULL; +char defaultServer[NAME_LEN]; +struct in_addr defaultAddr; + + +/* + * Initial name server query type is Address. + */ + +int queryType = T_A; +int queryClass = C_IN; + +/* + * Stuff for Interrupt (control-C) signal handler. + */ + +extern SIG_FN IntrHandler(); +FILE *filePtr; +jmp_buf env; + + +/* + * Browser command for help and view. + */ +char *pager; + +static void CvtAddrToPtr(); +static void ReadRC(); + + +/* + ****************************************************************************** + * + * main -- + * + * Initializes the resolver library and determines the address + * of the initial name server. The yylex routine is used to + * read and perform commands. + * + ****************************************************************************** + */ + +main(argc, argv) + int argc; + char **argv; +{ + char *wantedHost = NULL; + Boolean useLocalServer; + int result; + int i; + struct hostent *hp; + + /* + * Initialize the resolver library routines. + */ + + if (res_init() == -1) { + fprintf(stderr,"*** Can't initialize resolver.\n"); + exit(1); + } + + /* + * Allocate space for the default server's host info and + * find the server's address and name. If the resolver library + * already has some addresses for a potential name server, + * then use them. Otherwise, see if the current host has a server. + * Command line arguments may override the choice of initial server. + */ + + defaultPtr = (HostInfo *) Calloc(1, sizeof(HostInfo)); + + /* + * Parse the arguments: + * no args = go into interactive mode, use default host as server + * 1 arg = use as host name to be looked up, default host will be server + * non-interactive mode + * 2 args = 1st arg: + * if it is '-', then + * ignore but go into interactive mode + * else + * use as host name to be looked up, + * go into non-interactive mode + * 2nd arg: name or inet address of server + * + * "Set" options are specified with a leading - and must come before + * any arguments. For example, to find the well-known services for + * a host, type "nslookup -query=wks host" + */ + + ReadRC(); /* look for options file */ + + ++argv; --argc; /* skip prog name */ + + while (argc && *argv[0] == '-' && argv[0][1]) { + (void) SetOption (&(argv[0][1])); + ++argv; --argc; + } + if (argc > 2) { + Usage(); + } + if (argc && *argv[0] != '-') { + wantedHost = *argv; /* name of host to be looked up */ + } + + useLocalServer = FALSE; + if (argc == 2) { + struct in_addr addr; + + /* + * Use an explicit name server. If the hostname lookup fails, + * default to the server(s) in resolv.conf. + */ + + if (inet_aton(*++argv, &addr)) { + _res.nscount = 1; + _res.nsaddr.sin_addr = addr; + } else { + hp = gethostbyname(*argv); + if (hp == NULL) { + fprintf(stderr, "*** Can't find server address for '%s': ", + *argv); + herror((char *)NULL); + fputc('\n', stderr); + } else { + for (i = 0; i < MAXNS && hp->h_addr_list[i] != NULL; i++) { + bcopy(hp->h_addr_list[i], + (char *)&_res.nsaddr_list[i].sin_addr, + hp->h_length); + } + _res.nscount = i; + } + } + } + + + if (_res.nscount == 0 || useLocalServer) { + LocalServer(defaultPtr); + } else { + for (i = 0; i < _res.nscount; i++) { + if (_res.nsaddr_list[i].sin_addr.s_addr == INADDR_ANY) { + LocalServer(defaultPtr); + break; + } else { + result = GetHostInfoByAddr(&(_res.nsaddr_list[i].sin_addr), + &(_res.nsaddr_list[i].sin_addr), + defaultPtr); + if (result != SUCCESS) { + fprintf(stderr, + "*** Can't find server name for address %s: %s\n", + inet_ntoa(_res.nsaddr_list[i].sin_addr), + DecodeError(result)); + } else { + defaultAddr = _res.nsaddr_list[i].sin_addr; + break; + } + } + } + + /* + * If we have exhausted the list, tell the user about the + * command line argument to specify an address. + */ + + if (i == _res.nscount) { + fprintf(stderr, "*** Default servers are not available\n"); + exit(1); + } + + } + strcpy(defaultServer, defaultPtr->name); + + +#ifdef DEBUG +#ifdef DEBUG2 + _res.options |= RES_DEBUG2; +#endif + _res.options |= RES_DEBUG; + _res.retry = 2; +#endif /* DEBUG */ + + /* + * If we're in non-interactive mode, look up the wanted host and quit. + * Otherwise, print the initial server's name and continue with + * the initialization. + */ + + if (wantedHost != (char *) NULL) { + LookupHost(wantedHost, 0); + } else { + PrintHostInfo(stdout, "Default Server:", defaultPtr); + + pager = getenv("PAGER"); + if (pager == NULL) { + pager = _PATH_PAGERCMD; + } + + /* + * Setup the environment to allow the interrupt handler to return here. + */ + + (void) setjmp(env); + + /* + * Return here after a longjmp. + */ + + signal(SIGINT, IntrHandler); + signal(SIGPIPE, SIG_IGN); + + /* + * Read and evaluate commands. The commands are described in commands.l + * Yylex returns 0 when ^D or 'exit' is typed. + */ + + printf("> "); + fflush(stdout); + while(yylex()) { + printf("> "); + fflush(stdout); + } + } + exit(0); +} + + +LocalServer(defaultPtr) + HostInfo *defaultPtr; +{ + char hostName[NAME_LEN]; + + (void) gethostname(hostName, sizeof(hostName)); + + defaultAddr.s_addr = htonl(INADDR_ANY); + (void) GetHostInfoByName(&defaultAddr, C_IN, T_A, + "0.0.0.0", defaultPtr, 1); + free(defaultPtr->name); + defaultPtr->name = Calloc(1, sizeof(hostName)+1); + strcpy(defaultPtr->name, hostName); +} + + +/* + ****************************************************************************** + * + * Usage -- + * + * Lists the proper methods to run the program and exits. + * + ****************************************************************************** + */ + +Usage() +{ + fprintf(stderr, "Usage:\n"); + fprintf(stderr, +" nslookup [-opt ...] # interactive mode using default server\n"); + fprintf(stderr, +" nslookup [-opt ...] - server # interactive mode using 'server'\n"); + fprintf(stderr, +" nslookup [-opt ...] host # just look up 'host' using default server\n"); + fprintf(stderr, +" nslookup [-opt ...] host server # just look up 'host' using 'server'\n"); + exit(1); +} + +/* + ****************************************************************************** + * + * IsAddr -- + * + * Returns TRUE if the string looks like an Internet address. + * A string with a trailing dot is not an address, even if it looks + * like one. + * + ****************************************************************************** + */ + +Boolean +IsAddr(host, addrPtr) + char *host; + struct in_addr *addrPtr; /* If return TRUE, contains IP address */ +{ + register char *cp; + + if (isdigit(host[0])) { + /* Make sure it has only digits and dots. */ + for (cp = host; *cp; ++cp) { + if (!isdigit(*cp) && *cp != '.') + return FALSE; + } + /* If it has a trailing dot, don't treat it as an address. */ + if (*--cp != '.') { + return inet_aton(host, addrPtr); + } + } + return FALSE; +} + + +/* + ****************************************************************************** + * + * SetDefaultServer -- + * + * Changes the default name server to the one specified by + * the first argument. The command "server name" uses the current + * default server to lookup the info for "name". The command + * "lserver name" uses the original server to lookup "name". + * + * Side effects: + * This routine will cause a core dump if the allocation requests fail. + * + * Results: + * SUCCESS The default server was changed successfully. + * NONAUTH The server was changed but addresses of + * other servers who know about the requested server + * were returned. + * Errors No info about the new server was found or + * requests to the current server timed-out. + * + ****************************************************************************** + */ + +int +SetDefaultServer(string, local) + char *string; + Boolean local; +{ + register HostInfo *newDefPtr; + struct in_addr *servAddrPtr; + struct in_addr addr; + char newServer[NAME_LEN]; + int result; + int i; + + /* + * Parse the command line. It maybe of the form "server name", + * "lserver name" or just "name". + */ + + if (local) { + i = sscanf(string, " lserver %s", newServer); + } else { + i = sscanf(string, " server %s", newServer); + } + if (i != 1) { + i = sscanf(string, " %s", newServer); + if (i != 1) { + fprintf(stderr,"SetDefaultServer: invalid name: %s\n", string); + return(ERROR); + } + } + + /* + * Allocate space for a HostInfo variable for the new server. Don't + * overwrite the old HostInfo struct because info about the new server + * might not be found and we need to have valid default server info. + */ + + newDefPtr = (HostInfo *) Calloc(1, sizeof(HostInfo)); + + + /* + * A 'local' lookup uses the original server that the program was + * initialized with. + * + * Check to see if we have the address of the server or the + * address of a server who knows about this domain. + * XXX For now, just use the first address in the list. + */ + + if (local) { + servAddrPtr = &defaultAddr; + } else if (defaultPtr->addrList != NULL) { + servAddrPtr = (struct in_addr *) defaultPtr->addrList[0]; + } else { + servAddrPtr = (struct in_addr *) defaultPtr->servers[0]->addrList[0]; + } + + result = ERROR; + if (IsAddr(newServer, &addr)) { + result = GetHostInfoByAddr(servAddrPtr, &addr, newDefPtr); + /* If we can't get the name, fall through... */ + } + if (result != SUCCESS && result != NONAUTH) { + result = GetHostInfoByName(servAddrPtr, C_IN, T_A, + newServer, newDefPtr, 1); + } + + if (result == SUCCESS || result == NONAUTH) { + /* + * Found info about the new server. Free the resources for + * the old server. + */ + + FreeHostInfoPtr(defaultPtr); + free((char *)defaultPtr); + defaultPtr = newDefPtr; + strcpy(defaultServer, defaultPtr->name); + PrintHostInfo(stdout, "Default Server:", defaultPtr); + return(SUCCESS); + } else { + fprintf(stderr, "*** Can't find address for server %s: %s\n", + newServer, DecodeError(result)); + free((char *)newDefPtr); + + return(result); + } +} + +/* + ****************************************************************************** + * + * DoLoookup -- + * + * Common subroutine for LookupHost and LookupHostWithServer. + * + * Results: + * SUCCESS - the lookup was successful. + * Misc. Errors - an error message is printed if the lookup failed. + * + ****************************************************************************** + */ + +static int +DoLookup(host, servPtr, serverName) + char *host; + HostInfo *servPtr; + char *serverName; +{ + int result; + struct in_addr *servAddrPtr; + struct in_addr addr; + + /* Skip escape character */ + if (host[0] == '\\') + host++; + + /* + * If the user gives us an address for an address query, + * silently treat it as a PTR query. If the query type is already + * PTR, then convert the address into the in-addr.arpa format. + * + * Use the address of the server if it exists, otherwise use the + * address of a server who knows about this domain. + * XXX For now, just use the first address in the list. + */ + + if (servPtr->addrList != NULL) { + servAddrPtr = (struct in_addr *) servPtr->addrList[0]; + } else { + servAddrPtr = (struct in_addr *) servPtr->servers[0]->addrList[0]; + } + + /* + * RFC1123 says we "SHOULD check the string syntactically for a + * dotted-decimal number before looking it up [...]" (p. 13). + */ + if (queryType == T_A && IsAddr(host, &addr)) { + result = GetHostInfoByAddr(servAddrPtr, &addr, &curHostInfo); + } else { + if (queryType == T_PTR) { + CvtAddrToPtr(host); + } + result = GetHostInfoByName(servAddrPtr, queryClass, queryType, host, + &curHostInfo, 0); + } + + switch (result) { + case SUCCESS: + /* + * If the query was for an address, then the &curHostInfo + * variable can be used by Finger. + * There's no need to print anything for other query types + * because the info has already been printed. + */ + if (queryType == T_A) { + curHostValid = TRUE; + PrintHostInfo(filePtr, "Name:", &curHostInfo); + } + break; + + /* + * No Authoritative answer was available but we got names + * of servers who know about the host. + */ + case NONAUTH: + PrintHostInfo(filePtr, "Name:", &curHostInfo); + break; + + case NO_INFO: + fprintf(stderr, "*** No %s (%s) records available for %s\n", + DecodeType(queryType), p_type(queryType), host); + break; + + case TIME_OUT: + fprintf(stderr, "*** Request to %s timed-out\n", serverName); + break; + + default: + fprintf(stderr, "*** %s can't find %s: %s\n", serverName, host, + DecodeError(result)); + } + return result; +} + +/* + ****************************************************************************** + * + * LookupHost -- + * + * Asks the default name server for information about the + * specified host or domain. The information is printed + * if the lookup was successful. + * + * Results: + * ERROR - the output file could not be opened. + * + results of DoLookup + * + ****************************************************************************** + */ + +int +LookupHost(string, putToFile) + char *string; + Boolean putToFile; +{ + char host[NAME_LEN]; + char file[PATH_MAX]; + int result; + + /* + * Invalidate the current host information to prevent Finger + * from using bogus info. + */ + + curHostValid = FALSE; + + /* + * Parse the command string into the host and + * optional output file name. + * + */ + + sscanf(string, " %s", host); /* removes white space */ + if (!putToFile) { + filePtr = stdout; + } else { + filePtr = OpenFile(string, file); + if (filePtr == NULL) { + fprintf(stderr, "*** Can't open %s for writing\n", file); + return(ERROR); + } + fprintf(filePtr,"> %s\n", string); + } + + PrintHostInfo(filePtr, "Server:", defaultPtr); + + result = DoLookup(host, defaultPtr, defaultServer); + + if (putToFile) { + fclose(filePtr); + filePtr = NULL; + } + return(result); +} + +/* + ****************************************************************************** + * + * LookupHostWithServer -- + * + * Asks the name server specified in the second argument for + * information about the host or domain specified in the first + * argument. The information is printed if the lookup was successful. + * + * Address info about the requested name server is obtained + * from the default name server. This routine will return an + * error if the default server doesn't have info about the + * requested server. Thus an error return status might not + * mean the requested name server doesn't have info about the + * requested host. + * + * Comments from LookupHost apply here, too. + * + * Results: + * ERROR - the output file could not be opened. + * + results of DoLookup + * + ****************************************************************************** + */ + +int +LookupHostWithServer(string, putToFile) + char *string; + Boolean putToFile; +{ + char file[PATH_MAX]; + char host[NAME_LEN]; + char server[NAME_LEN]; + int result; + static HostInfo serverInfo; + + curHostValid = FALSE; + + sscanf(string, " %s %s", host, server); + if (!putToFile) { + filePtr = stdout; + } else { + filePtr = OpenFile(string, file); + if (filePtr == NULL) { + fprintf(stderr, "*** Can't open %s for writing\n", file); + return(ERROR); + } + fprintf(filePtr,"> %s\n", string); + } + + result = GetHostInfoByName( + defaultPtr->addrList ? + (struct in_addr *) defaultPtr->addrList[0] : + (struct in_addr *) defaultPtr->servers[0]->addrList[0], + C_IN, T_A, server, &serverInfo, 1); + + if (result != SUCCESS) { + fprintf(stderr,"*** Can't find address for server %s: %s\n", server, + DecodeError(result)); + } else { + PrintHostInfo(filePtr, "Server:", &serverInfo); + + result = DoLookup(host, &serverInfo, server); + } + if (putToFile) { + fclose(filePtr); + filePtr = NULL; + } + return(result); +} + +/* + ****************************************************************************** + * + * SetOption -- + * + * This routine is used to change the state information + * that affect the lookups. The command format is + * set keyword[=value] + * Most keywords can be abbreviated. Parsing is very simplistic-- + * A value must not be separated from its keyword by white space. + * + * Valid keywords: Meaning: + * all lists current values of options. + * ALL lists current values of options, including + * hidden options. + * [no]d2 turn on/off extra debugging mode. + * [no]debug turn on/off debugging mode. + * [no]defname use/don't use default domain name. + * [no]search use/don't use domain search list. + * domain=NAME set default domain name to NAME. + * [no]ignore ignore/don't ignore trunc. errors. + * query=value set default query type to value, + * value is one of the query types in RFC883 + * without the leading T_. (e.g., A, HINFO) + * [no]recurse use/don't use recursive lookup. + * retry=# set number of retries to #. + * root=NAME change root server to NAME. + * time=# set timeout length to #. + * [no]vc use/don't use virtual circuit. + * port TCP/UDP port to server. + * + * Deprecated: + * [no]primary use/don't use primary server. + * + * Results: + * SUCCESS the command was parsed correctly. + * ERROR the command was not parsed correctly. + * + ****************************************************************************** + */ + +int +SetOption(option) + register char *option; +{ + char type[NAME_LEN]; + char *ptr; + int tmp; + + while (isspace(*option)) + ++option; + if (strncmp (option, "set ", 4) == 0) + option += 4; + while (isspace(*option)) + ++option; + + if (*option == 0) { + fprintf(stderr, "*** Invalid set command\n"); + return(ERROR); + } else { + if (strncmp(option, "all", 3) == 0) { + ShowOptions(); + } else if (strncmp(option, "ALL", 3) == 0) { + ShowOptions(); + } else if (strncmp(option, "d2", 2) == 0) { /* d2 (more debug) */ + _res.options |= (RES_DEBUG | RES_DEBUG2); + } else if (strncmp(option, "nod2", 4) == 0) { + _res.options &= ~RES_DEBUG2; + printf("d2 mode disabled; still in debug mode\n"); + } else if (strncmp(option, "def", 3) == 0) { /* defname */ + _res.options |= RES_DEFNAMES; + } else if (strncmp(option, "nodef", 5) == 0) { + _res.options &= ~RES_DEFNAMES; + } else if (strncmp(option, "do", 2) == 0) { /* domain */ + ptr = strchr(option, '='); + if (ptr != NULL) { + sscanf(++ptr, "%s", _res.defdname); + res_re_init(); + } + } else if (strncmp(option, "deb", 1) == 0) { /* debug */ + _res.options |= RES_DEBUG; + } else if (strncmp(option, "nodeb", 5) == 0) { + _res.options &= ~(RES_DEBUG | RES_DEBUG2); + } else if (strncmp(option, "ig", 2) == 0) { /* ignore */ + _res.options |= RES_IGNTC; + } else if (strncmp(option, "noig", 4) == 0) { + _res.options &= ~RES_IGNTC; + } else if (strncmp(option, "po", 2) == 0) { /* port */ + ptr = strchr(option, '='); + if (ptr != NULL) { + sscanf(++ptr, "%hu", &nsport); + } +#ifdef deprecated + } else if (strncmp(option, "pri", 3) == 0) { /* primary */ + _res.options |= RES_PRIMARY; + } else if (strncmp(option, "nopri", 5) == 0) { + _res.options &= ~RES_PRIMARY; +#endif + } else if (strncmp(option, "q", 1) == 0 || /* querytype */ + strncmp(option, "ty", 2) == 0) { /* type */ + ptr = strchr(option, '='); + if (ptr != NULL) { + sscanf(++ptr, "%s", type); + queryType = StringToType(type, queryType, stderr); + } + } else if (strncmp(option, "cl", 2) == 0) { /* query class */ + ptr = strchr(option, '='); + if (ptr != NULL) { + sscanf(++ptr, "%s", type); + queryClass = StringToClass(type, queryClass, stderr); + } + } else if (strncmp(option, "rec", 3) == 0) { /* recurse */ + _res.options |= RES_RECURSE; + } else if (strncmp(option, "norec", 5) == 0) { + _res.options &= ~RES_RECURSE; + } else if (strncmp(option, "ret", 3) == 0) { /* retry */ + ptr = strchr(option, '='); + if (ptr != NULL) { + sscanf(++ptr, "%d", &tmp); + if (tmp >= 0) { + _res.retry = tmp; + } + } + } else if (strncmp(option, "ro", 2) == 0) { /* root */ + ptr = strchr(option, '='); + if (ptr != NULL) { + sscanf(++ptr, "%s", rootServerName); + } + } else if (strncmp(option, "sea", 3) == 0) { /* search list */ + _res.options |= RES_DNSRCH; + } else if (strncmp(option, "nosea", 5) == 0) { + _res.options &= ~RES_DNSRCH; + } else if (strncmp(option, "srchl", 5) == 0) { /* domain search list */ + ptr = strchr(option, '='); + if (ptr != NULL) { + res_dnsrch(++ptr); + } + } else if (strncmp(option, "ti", 2) == 0) { /* timeout */ + ptr = strchr(option, '='); + if (ptr != NULL) { + sscanf(++ptr, "%d", &tmp); + if (tmp >= 0) { + _res.retrans = tmp; + } + } + } else if (strncmp(option, "v", 1) == 0) { /* vc */ + _res.options |= RES_USEVC; + } else if (strncmp(option, "nov", 3) == 0) { + _res.options &= ~RES_USEVC; + } else { + fprintf(stderr, "*** Invalid option: %s\n", option); + return(ERROR); + } + } + return(SUCCESS); +} + +/* + * Fake a reinitialization when the domain is changed. + */ +res_re_init() +{ + register char *cp, **pp; + int n; + + /* find components of local domain that might be searched */ + pp = _res.dnsrch; + *pp++ = _res.defdname; + for (cp = _res.defdname, n = 0; *cp; cp++) + if (*cp == '.') + n++; + cp = _res.defdname; + for (; n >= LOCALDOMAINPARTS && pp < _res.dnsrch + MAXDFLSRCH; n--) { + cp = strchr(cp, '.'); + *pp++ = ++cp; + } + *pp = 0; + _res.options |= RES_INIT; +} + +#define SRCHLIST_SEP '/' + +res_dnsrch(cp) + register char *cp; +{ + register char **pp; + int n; + + (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1); + if ((cp = strchr(_res.defdname, '\n')) != NULL) + *cp = '\0'; + /* + * Set search list to be blank-separated strings + * on rest of line. + */ + cp = _res.defdname; + pp = _res.dnsrch; + *pp++ = cp; + for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) { + if (*cp == SRCHLIST_SEP) { + *cp = '\0'; + n = 1; + } else if (n) { + *pp++ = cp; + n = 0; + } + } + if ((cp = strchr(pp[-1], SRCHLIST_SEP)) != NULL) { + *cp = '\0'; + } + *pp = NULL; +} + + +/* + ****************************************************************************** + * + * ShowOptions -- + * + * Prints out the state information used by the resolver + * library and other options set by the user. + * + ****************************************************************************** + */ + +void +ShowOptions() +{ + register char **cp; + + PrintHostInfo(stdout, "Default Server:", defaultPtr); + if (curHostValid) { + PrintHostInfo(stdout, "Host:", &curHostInfo); + } + + printf("Set options:\n"); + printf(" %sdebug \t", (_res.options & RES_DEBUG) ? "" : "no"); + printf(" %sdefname\t", (_res.options & RES_DEFNAMES) ? "" : "no"); + printf(" %ssearch\t", (_res.options & RES_DNSRCH) ? "" : "no"); + printf(" %srecurse\n", (_res.options & RES_RECURSE) ? "" : "no"); + + printf(" %sd2\t\t", (_res.options & RES_DEBUG2) ? "" : "no"); + printf(" %svc\t\t", (_res.options & RES_USEVC) ? "" : "no"); + printf(" %signoretc\t", (_res.options & RES_IGNTC) ? "" : "no"); + printf(" port=%u\n", nsport); + + printf(" querytype=%s\t", p_type(queryType)); + printf(" class=%s\t", p_class(queryClass)); + printf(" timeout=%d\t", _res.retrans); + printf(" retry=%d\n", _res.retry); + printf(" root=%s\n", rootServerName); + printf(" domain=%s\n", _res.defdname); + + if (cp = _res.dnsrch) { + printf(" srchlist=%s", *cp); + for (cp++; *cp; cp++) { + printf("%c%s", SRCHLIST_SEP, *cp); + } + putchar('\n'); + } + putchar('\n'); +} +#undef SRCHLIST_SEP + +/* + ****************************************************************************** + * + * PrintHelp -- + * + * Displays the help file. + * + ****************************************************************************** + */ + +void +PrintHelp() +{ + char cmd[PATH_MAX]; + + sprintf(cmd, "%s %s", pager, _PATH_HELPFILE); + system(cmd); +} + +/* + ****************************************************************************** + * + * CvtAddrToPtr -- + * + * Convert a dotted-decimal Internet address into the standard + * PTR format (reversed address with .in-arpa. suffix). + * + * Assumes the argument buffer is large enougth to hold the result. + * + ****************************************************************************** + */ + +static void +CvtAddrToPtr(name) + char *name; +{ + char *p; + int ip[4]; + struct in_addr addr; + + if (IsAddr(name, &addr)) { + p = inet_ntoa(addr); + if (sscanf(p, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]) == 4) { + sprintf(name, "%d.%d.%d.%d.in-addr.arpa.", + ip[3], ip[2], ip[1], ip[0]); + } + } +} + +/* + ****************************************************************************** + * + * ReadRC -- + * + * Use the contents of ~/.nslookuprc as options. + * + ****************************************************************************** + */ + +static void +ReadRC() +{ + register FILE *fp; + register char *cp; + char buf[PATH_MAX]; + + if ((cp = getenv("HOME")) != NULL) { + (void) strcpy(buf, cp); + (void) strcat(buf, _PATH_NSLOOKUPRC); + + if ((fp = fopen(buf, "r")) != NULL) { + while (fgets(buf, sizeof(buf), fp) != NULL) { + if ((cp = strchr(buf, '\n')) != NULL) { + *cp = '\0'; + } + (void) SetOption(buf); + } + (void) fclose(fp); + } + } +} diff --git a/usr.sbin/nslookup/nslookup.8 b/usr.sbin/nslookup/nslookup.8 new file mode 100644 index 0000000..de0306a --- /dev/null +++ b/usr.sbin/nslookup/nslookup.8 @@ -0,0 +1,387 @@ +.\" +.\" ++Copyright++ 1985, 1989 +.\" - +.\" Copyright (c) 1985, 1989 +.\" 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. +.\" - +.\" --Copyright-- +.\" +.\" @(#)nslookup.8 5.3 (Berkeley) 6/24/90 +.\" +.TH NSLOOKUP @SYS_OPS_EXT_U@ "June 24, 1990" +.UC 6 +.SH NAME +nslookup \- query Internet name servers interactively +.SH SYNOPSIS +.B nslookup +[ +.I \-option ... +] +[ +.I host-to-find +| \- [ +.I server +]] +.SH DESCRIPTION +.I Nslookup +is a program to query Internet domain name servers. +Nslookup has two modes: interactive and non-interactive. +Interactive mode allows the user to query name servers for +information about various hosts and domains or to print a list of hosts +in a domain. +Non-interactive mode is used to print just the name and requested information +for a host or domain. +.sp 1 +.SH ARGUMENTS +Interactive mode is entered in the following cases: +.IP a) 4 +when no arguments are given (the default name server will be used), +.IP b) 4 +when the first argument is a hyphen (\-) and the second argument +is the host name or Internet address of a name server. +.LP +Non-interactive mode is used when the name or Internet address +of the host to be looked up +is given as the first argument. The optional second argument specifies +the host name or address of a name server. +.LP +The options listed under the ``set'' command below can be specified in +the .nslookuprc file in the user's home directory if they are listed +one per line. Options can also be specified +on the command line if they precede the arguments and are prefixed with +a hyphen. For example, to change the default query type to host information, +and the initial timeout to 10 seconds, type: +.sp .5v + nslookup \-query=hinfo \-timeout=10 +.sp .5v +.SH "INTERACTIVE COMMANDS" +Commands may be interrupted at any time by typing a control-C. +To exit, type a control-D (EOF) or type exit. +The command line length must be less than 256 characters. +To treat a built-in command as a host name, +precede it with an escape character (\e). +\fBN.B.\fP an unrecognized command will be interpreted as a host name. +.sp .5v +.IP "\fIhost\fP [\fIserver\fP]" +Look up information for \fIhost\fP using the current default server +or using \fIserver\fP if specified. +If \fIhost\fP is an Internet address and the query type is A or PTR, the +name of the host is returned. +If \fIhost\fP is a name and does not have a trailing period, the default +domain name is appended to the name. (This behavior depends on the state of the +\fBset\fP options \fBdomain\fP, \fBsrchlist\fP, +\fBdefname\fP, and \fBsearch\fP). +To look up a host not in the current domain, append a period to +the name. +.sp 1 +.IP "\fBserver\fP \fIdomain\fP" +.ns +.IP "\fBlserver\fP \fIdomain\fP" +Change the default server to \fIdomain\fP. +\fBLserver\fP uses the initial server to look up +information about \fIdomain\fP while \fBserver\fP +uses the current default server. +If an authoritative answer can't be found, the names of servers +that might have the answer are returned. +.sp 1 +.IP \fBroot\fP +Changes the default server to the server for the root of the domain name space. +Currently, the host ns.internic.net is used. +(This command is a synonym for \fBlserver ns.internic.net.\fP) +The name of the root server can be changed with the \fBset root\fP command. +.sp 1 +.IP "\fBfinger\fP [\fIname\fP] [\fB>\fP \fIfilename\fP]" +.ns +.IP "\fBfinger\fP [\fIname\fP] [\fB>>\fP \fIfilename\fP]" +Connects with the finger server on the current host. +The current host is defined when a previous lookup for a host +was successful and returned address information (see the +\fBset querytype=A\fP command). +\fIName\fP is optional. +\fB>\fP and \fB>>\fP can be used to redirect output in the +usual manner. +.sp 1 +.IP "\fBls\fR [\fIoption\fR] \fIdomain\fR [\fB>\fR \fIfilename\fR]" +.ns +.IP "\fBls\fR [\fIoption\fR] \fIdomain\fR [\fB>>\fR \fIfilename\fR]" +List the information available for \fIdomain\fP, optionally creating +or appending to \fIfilename\fP. +The default output contains host names and their Internet addresses. +.I Option +can be one of the following: +.RS +.IP "\fB\-t \fIquerytype\fP" 4 +lists all records of the specified type (see \fIquerytype\fP below). +.IP \fB\-a\fP 4 +lists aliases of hosts in the domain. +synonym for \fB\-t\ \ CNAME\fP. +.IP \fB\-d\fP 4 +lists all records for the domain. +synonym for \fB\-t\ \ ANY\fP. +.IP \fB\-h\fP 4 +lists CPU and operating system information for the domain. +synonym for \fB\-t\ \ HINFO\fP. +.IP \fB\-s\fP 4 +lists well-known services of hosts in the domain. +synonym for \fB\-t\ \ WKS\fP. +.P +When output is directed to a file, hash marks are printed for every +50 records received from the server. +.RE +.sp 1 +.IP "\fBview\fP \fIfilename\fP" +Sorts and lists the output of previous \fBls\fP command(s) with +\fImore\fP(@CMD_EXT@). +.sp 1 +.ne 4 +.IP "\fBhelp\fP" +.ns +.IP "\fB?\fP" +Prints a brief summary of commands. +.sp 1 +.IP "\fBexit\fP" +Exits the program. +.sp 1 +.IP "\fBset\fP \fIkeyword\fP[=\fIvalue\fP]" +This command is used to change state information that affects the lookups. +Valid keywords are: +.RS +.IP "\fBall\fP" +Prints the current values of the frequently-used options to \fBset\fP. +Information about the current default server and host is also printed. +.IP "\fBclass=\fIvalue\fR" +Change the query class to one of: +.RS +.IP IN 10 +the Internet class. +.IP CHAOS 10 +the Chaos class. +.IP HESIOD 10 +the MIT Athena Hesiod class. +.IP ANY 10 +wildcard (any of the above). +.P +The class specifies the protocol group of the information. +.br +(Default = IN, abbreviation = cl) +.RE +.IP "\fB[no]debug\fP" +Turn debugging mode on. A lot more information is printed about the +packet sent to the server and the resulting answer. +.br +(Default = nodebug, abbreviation = [no]deb) +.IP "\fB[no]d2\fP" +Turn exhaustive debugging mode on. +Essentially all fields of every packet are printed. +.br +(Default = nod2) +.IP "\fBdomain=\fIname\fR" +Change the default domain name to \fIname\fP. +The default domain name is appended to a lookup request depending on the +state of the \fBdefname\fP and \fBsearch\fP options. +The domain search list contains the parents of the default domain if it has +at least two components in its name. +For example, if the default domain +is CC.Berkeley.EDU, the search list is CC.Berkeley.EDU and Berkeley.EDU. +Use the \fBset srchlist\fP command to specify a different list. +Use the \fBset all\fP command to display the list. +.br +(Default = value from hostname, /etc/resolv.conf or LOCALDOMAIN, +abbreviation = do) +.IP "\fBsrchlist=\fIname1/name2/...\fR" +Change the default domain name to \fIname1\fP and the domain search list +to \fIname1\fP, \fIname2\fP, etc. A maximum of 6 names separated by slashes (/) +can be specified. +For example, +.sp .5v + set\ srchlist=lcs.MIT.EDU/ai.MIT.EDU/MIT.EDU +.sp .5v +sets the domain to lcs.MIT.EDU and the search list to the three names. +This command overrides the +default domain name and search list of the \fBset domain\fP command. +Use the \fBset all\fP command to display the list. +.br +(Default = value based on hostname, /etc/resolv.conf or LOCALDOMAIN, +abbreviation = srchl) +.IP "\fB[no]defname\fP" +If set, append the default domain name to a single-component lookup request +(i.e., one that does not contain a period). +.br +(Default = defname, abbreviation = [no]def) +.IP "\fB[no]search\fP" +If the lookup request contains at least one period but doesn't end +with a trailing period, +append the domain names in the domain search list +to the request until an answer is received. +.br +(Default = search, abbreviation = [no]sea) +.IP "\fBport=\fIvalue\fR" +Change the default TCP/UDP name server port to \fIvalue\fP. +.br +(Default = 53, abbreviation = po) +.IP "\fBquerytype=\fIvalue\fR" +.ns +.IP "\fBtype=\fIvalue\fR" +.ns +Change the type of information query to one of: +.RS +.IP A 10 +the host's Internet address. +.IP CNAME 10 +the canonical name for an alias. +.IP HINFO 10 +the host CPU and operating system type. +.IP MINFO 10 +the mailbox or mail list information. +.IP MX 10 +the mail exchanger. +.IP NS 10 +the name server for the named zone. +.IP PTR 10 +the host name if the query is an Internet address, +otherwise the pointer to other information. +.IP SOA 10 +the domain's ``start-of-authority'' information. +.IP TXT 10 +the text information. +.IP UINFO 10 +the user information. +.IP WKS 10 +the supported well-known services. +.P +Other types (ANY, AXFR, MB, MD, MF, NULL) are described in the +RFC-1035 document. +.br +(Default = A, abbreviations = q, ty) +.RE +.IP "\fB[no]recurse\fP" +Tell the name server to query other servers if it does not have the +information. +.br +(Default = recurse, abbreviation = [no]rec) +.IP \fBretry=\fInumber\fR +Set the number of retries to \fInumber\fP. +When a reply to a request is not received within a certain +amount of time (changed with \fBset timeout\fP), +the timeout period is doubled and the request is resent. +The retry value controls how many times a request is resent before giving up. +.br +(Default = 4, abbreviation = ret) +.IP \fBroot=\fIhost\fR +Change the name of the root server to \fIhost\fP. This +affects the \fBroot\fP command. +.br +(Default = ns.internic.net., abbreviation = ro) +.IP \fBtimeout=\fInumber\fR +Change the initial timeout interval +for waiting for a reply +to \fInumber\fP seconds. +Each retry doubles the timeout period. +.br +(Default = 5 seconds, abbreviation = ti) +.IP "\fB[no]vc\fP" +Always use a virtual circuit when sending requests to the server. +.br +(Default = novc, abbreviation = [no]v) +.IP "\fB[no]ignoretc\fP" +Ignore packet truncation errors. +.br +(Default = noignoretc, abbreviation = [no]ig) +.RE +.SH DIAGNOSTICS +If the lookup request was not successful, an error message is printed. +Possible errors are: +.IP "Timed out" 5 +The server did not respond to a request after a certain amount of +time (changed with \fBset timeout=\fIvalue\fR) +and a certain number of retries (changed with \fBset retry=\fIvalue\fR). +.IP "No response from server" 5 +No name server is running on the server machine. +.IP "No records" 5 +The server does not have resource records of the current query type for the +host, although the host name is valid. +The query type is specified with the \fBset querytype\fP command. +.IP "Non-existent domain" 5 +The host or domain name does not exist. +.IP "Connection refused" 5 +.ns +.IP "Network is unreachable" 5 +The connection to the name or finger server could not be made +at the current time. +This error commonly occurs with \fBls\fP and \fBfinger\fP requests. +.IP "Server failure" 5 +The name server found an internal inconsistency in its database +and could not return a valid answer. +.IP "Refused" 5 +The name server refused to service the request. +.IP "Format error" 5 +The name server found that the request packet was not in the proper format. +It may indicate an error in \fInslookup\fP. +.sp 1 +.SH FILES +.ta \w'/usr/share/misc/nslookup.helpXXX'u +/etc/resolv.conf initial domain name and + name server addresses. +.br +$HOME/.nslookuprc user's initial options. +.br +/usr/share/misc/nslookup.help summary of commands. +.SH ENVIRONMENT +.ta \w'HOSTALIASESXXXX'u +HOSTALIASES file containing host aliases. +.br +LOCALDOMAIN overrides default domain. +.SH SEE ALSO +resolver(@LIB_NETWORK_EXT@), resolver(@FORMAT_EXT@), @INDOT@named(@SYS_OPS_EXT@), +.br +RFC-1034 ``Domain Names \- Concepts and Facilities'' +.br +RFC-1035 ``Domain Names \- Implementation and Specification'' +.SH AUTHOR +Andrew Cherenson diff --git a/usr.sbin/nslookup/nslookup.help b/usr.sbin/nslookup/nslookup.help new file mode 100644 index 0000000..2c17d4d --- /dev/null +++ b/usr.sbin/nslookup/nslookup.help @@ -0,0 +1,33 @@ +$Id: nslookup.help,v 4.9.1.3 1993/12/06 00:43:17 vixie Exp $ + +Commands: (identifiers are shown in uppercase, [] means optional) +NAME - print info about the host/domain NAME using default server +NAME1 NAME2 - as above, but use NAME2 as server +help or ? - print info on common commands; see nslookup(1) for details +set OPTION - set an option + all - print options, current server and host + [no]debug - print debugging information + [no]d2 - print exhaustive debugging information + [no]defname - append domain name to each query + [no]recurse - ask for recursive answer to query + [no]vc - always use a virtual circuit + domain=NAME - set default domain name to NAME + srchlist=N1[/N2/.../N6] - set domain to N1 and search list to N1,N2, etc. + root=NAME - set root server to NAME + retry=X - set number of retries to X + timeout=X - set initial time-out interval to X seconds + querytype=X - set query type, e.g., A,ANY,CNAME,HINFO,MX,NS,PTR,SOA,TXT,WKS + type=X - synonym for querytype + class=X - set query class to one of IN (Internet), CHAOS, HESIOD or ANY +server NAME - set default server to NAME, using current default server +lserver NAME - set default server to NAME, using initial server +finger [USER] - finger the optional NAME at the current default host +root - set current default server to the root +ls [opt] DOMAIN [> FILE] - list addresses in DOMAIN (optional: output to FILE) + -a - list canonical names and aliases + -h - list HINFO (CPU type and operating system) + -s - list well-known services + -d - list all records + -t TYPE - list records of the given type (e.g., A,CNAME,MX, etc.) +view FILE - sort an 'ls' output file and view it with more +exit - exit the program, ^D also exits diff --git a/usr.sbin/nslookup/pathnames.h b/usr.sbin/nslookup/pathnames.h new file mode 100644 index 0000000..a915293 --- /dev/null +++ b/usr.sbin/nslookup/pathnames.h @@ -0,0 +1,71 @@ +/* + * ++Copyright++ 1990 + * - + * Copyright (c) 1990 + * 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. + * - + * --Copyright-- + */ + +/* + * @(#)pathnames.h 5.1 (Berkeley) 5/28/90 + * $Id: pathnames.h,v 4.9.1.3 1993/09/16 09:02:07 vixie Exp $ + */ + +#define _PATH_NSLOOKUPRC "/.nslookuprc" +#define _PATH_PAGERCMD "more" + +#ifndef _PATH_HELPFILE +#if defined(BSD) && BSD >= 198810 +#define _PATH_HELPFILE "/usr/share/misc/nslookup.help" +#else +#define _PATH_HELPFILE "/usr/lib/nslookup.help" +#endif +#endif + diff --git a/usr.sbin/nslookup/res.h b/usr.sbin/nslookup/res.h new file mode 100644 index 0000000..e86bc2f --- /dev/null +++ b/usr.sbin/nslookup/res.h @@ -0,0 +1,172 @@ +/* + * ++Copyright++ 1985, 1989 + * - + * Copyright (c) 1985, 1989 + * 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. + * - + * --Copyright-- + */ + +/* + * @(#)res.h 5.10 (Berkeley) 6/1/90 + * $Id: res.h,v 4.9.1.3 1994/06/01 21:10:16 vixie Exp $ + */ + +/* + ******************************************************************************* + * + * res.h -- + * + * Definitions used by modules of the name server lookup program. + * + * Copyright (c) 1985 + * Andrew Cherenson + * U.C. Berkeley + * CS298-26 Fall 1985 + * + ******************************************************************************* + */ + +#define TRUE 1 +#define FALSE 0 +typedef int Boolean; + +/* + * Define return statuses in addtion to the ones defined in namserv.h + * let SUCCESS be a synonym for NOERROR + * + * TIME_OUT - a socket connection timed out. + * NO_INFO - the server didn't find any info about the host. + * ERROR - one of the following types of errors: + * dn_expand, res_mkquery failed + * bad command line, socket operation failed, etc. + * NONAUTH - the server didn't have the desired info but + * returned the name(s) of some servers who should. + * NO_RESPONSE - the server didn't respond. + * + */ + +#define SUCCESS 0 +#define TIME_OUT -1 +#define NO_INFO -2 +#define ERROR -3 +#define NONAUTH -4 +#define NO_RESPONSE -5 + +/* + * Define additional options for the resolver state structure. + * + * RES_DEBUG2 more verbose debug level + */ + +#define RES_DEBUG2 0x80000000 + +/* + * Maximum length of server, host and file names. + */ + +#define NAME_LEN 256 + + +/* + * Modified struct hostent from + * + * "Structures returned by network data base library. All addresses + * are supplied in host order, and returned in network order (suitable + * for use in system calls)." + */ + +typedef struct { + char *name; /* official name of host */ + char **domains; /* domains it serves */ + char **addrList; /* list of addresses from name server */ +} ServerInfo; + +typedef struct { + char *name; /* official name of host */ + char **aliases; /* alias list */ + char **addrList; /* list of addresses from name server */ + int addrType; /* host address type */ + int addrLen; /* length of address */ + ServerInfo **servers; +} HostInfo; + + +/* + * FilePtr is used for directing listings to a file. + * It is global so the Control-C handler can close it. + */ + +extern FILE *filePtr; + +/* + * TCP/UDP port of server. + */ +extern unsigned short nsport; + +/* + * External routines: + */ + +extern Boolean IsAddr(); +extern int Print_query(); +extern unsigned char *Print_cdname(); +extern unsigned char *Print_cdname2(); /* fixed width */ +extern unsigned char *Print_rr(); +extern char *DecodeType(); /* descriptive version of p_type */ +extern char *DecodeError(); +extern char *Calloc(); +extern char *Malloc(); +extern void NsError(); +extern void PrintServer(); +extern void PrintHostInfo(); +extern void ShowOptions(); +extern void FreeHostInfoPtr(); +extern FILE *OpenFile(); +extern char *res_skip(); diff --git a/usr.sbin/nslookup/send.c b/usr.sbin/nslookup/send.c new file mode 100644 index 0000000..e895bfa --- /dev/null +++ b/usr.sbin/nslookup/send.c @@ -0,0 +1,412 @@ +/* + * ++Copyright++ 1985, 1989 + * - + * Copyright (c) 1985, 1989 + * 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. + * - + * --Copyright-- + */ + +#ifndef lint +static char sccsid[] = "@(#)send.c 5.18 (Berkeley) 3/2/91"; +static char rcsid[] = "$Id: send.c,v 4.9.1.5 1994/06/06 09:08:43 vixie Exp $"; +#endif /* not lint */ + +/* + ****************************************************************************** + * + * send.c -- + * + * Routine to send request packets to a name server. + * + * Based on "@(#)res_send.c 6.25 (Berkeley) 6/1/90". + * + ****************************************************************************** + */ + + +/* + * Send query to name server and wait for reply. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "res.h" +#include "../../conf/portability.h" + +static int s = -1; /* socket used for communications */ + + +#ifndef FD_SET +#define NFDBITS 32 +#define FD_SETSIZE 32 +#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) +#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) +#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) +#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) +#endif + + + +unsigned short nsport = NAMESERVER_PORT; + + + +/* + ****************************************************************************** + * + * SendRequest -- + * + * Sends a request packet to a name server whose address + * is specified by the first argument and returns with + * the answer packet. + * + * Results: + * SUCCESS - the request was sent and an answer + * was received. + * TIME_OUT - the virtual circuit connection timed-out + * or a reply to a datagram wasn't received. + * + * + ****************************************************************************** + */ + +int +SendRequest(nsAddrPtr, buf, buflen, answer, anslen, trueLenPtr) + struct in_addr *nsAddrPtr; + char *buf; + int buflen; + char *answer; + u_int anslen; + int *trueLenPtr; +{ + register int n; + int try, v_circuit, resplen; + int gotsomewhere = 0, connected = 0; + int connreset = 0; + u_short id, len; + char *cp; + fd_set dsmask; + struct timeval timeout; + HEADER *hp = (HEADER *) buf; + HEADER *anhp = (HEADER *) answer; + struct iovec iov[2]; + int terrno = ETIMEDOUT; + char junk[512]; + struct sockaddr_in sin; + + if (_res.options & RES_DEBUG2) { + printf("------------\nSendRequest(), len %d\n", buflen); + Print_query(buf, buf+buflen, 1); + } + sin.sin_family = AF_INET; + sin.sin_port = htons(nsport); + sin.sin_addr = *nsAddrPtr; + v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; + id = hp->id; + /* + * Send request, RETRY times, or until successful + */ + for (try = 0; try < _res.retry; try++) { + usevc: + if (v_circuit) { + int truncated = 0; + + /* + * Use virtual circuit; + * at most one attempt per server. + */ + try = _res.retry; + if (s < 0) { + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) { + terrno = errno; + if (_res.options & RES_DEBUG) + perror("socket (vc) failed"); + continue; + } + if (connect(s, (struct sockaddr *)&sin, + sizeof(struct sockaddr)) < 0) { + terrno = errno; + if (_res.options & RES_DEBUG) + perror("connect failed"); + (void) close(s); + s = -1; + continue; + } + } + /* + * Send length & message + */ + __putshort(buflen, (u_char *)&len); + iov[0].iov_base = (caddr_t)&len; + iov[0].iov_len = INT16SZ; + iov[1].iov_base = buf; + iov[1].iov_len = buflen; + if (writev(s, iov, 2) != INT16SZ + buflen) { + terrno = errno; + if (_res.options & RES_DEBUG) + perror("write failed"); + (void) close(s); + s = -1; + continue; + } + /* + * Receive length & response + */ + cp = answer; + len = INT16SZ; + while ((n = read(s, (char *)cp, (int)len)) > 0) { + cp += n; + if ((len -= n) <= 0) + break; + } + if (n <= 0) { + terrno = errno; + if (_res.options & RES_DEBUG) + perror("read failed"); + (void) close(s); + s = -1; + /* + * A long running process might get its TCP + * connection reset if the remote server was + * restarted. Requery the server instead of + * trying a new one. When there is only one + * server, this means that a query might work + * instead of failing. We only allow one reset + * per query to prevent looping. + */ + if (terrno == ECONNRESET && !connreset) { + connreset = 1; + } + continue; + } + cp = answer; + if ((resplen = _getshort((u_char*)cp)) > anslen) { + if (_res.options & RES_DEBUG) + fprintf(stderr, "response truncated\n"); + len = anslen; + truncated = 1; + } else + len = resplen; + while (len != 0 && + (n = read(s, (char *)cp, (int)len)) > 0) { + cp += n; + len -= n; + } + if (n <= 0) { + terrno = errno; + if (_res.options & RES_DEBUG) + perror("read failed"); + (void) close(s); + s = -1; + continue; + } + if (truncated) { + /* + * Flush rest of answer + * so connection stays in synch. + */ + anhp->tc = 1; + len = resplen - anslen; + while (len != 0) { + n = (len > sizeof(junk) ? + sizeof(junk) : len); + if ((n = read(s, junk, n)) > 0) + len -= n; + else + break; + } + } + } else { + /* + * Use datagrams. + */ + if (s < 0) { + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + terrno = errno; + if (_res.options & RES_DEBUG) + perror("socket (dg) failed"); + continue; + } + } +#if BSD >= 43 + if (connected == 0) { + if (connect(s, (struct sockaddr *)&sin, + sizeof(struct sockaddr)) < 0) { + if (_res.options & RES_DEBUG) + perror("connect"); + continue; + } + connected = 1; + } + if (send(s, buf, buflen, 0) != buflen) { + if (_res.options & RES_DEBUG) + perror("send"); + continue; + } +#else /* BSD */ + if (sendto(s, buf, buflen, 0, + (struct sockaddr *) &sin, + sizeof(sin)) != buflen) { + if (_res.options & RES_DEBUG) + perror("sendto"); + continue; + } +#endif + + /* + * Wait for reply + */ + timeout.tv_sec = (_res.retrans << try); + if (timeout.tv_sec <= 0) + timeout.tv_sec = 1; + timeout.tv_usec = 0; +wait: + FD_ZERO(&dsmask); + FD_SET(s, &dsmask); + n = select(s+1, &dsmask, (fd_set *)NULL, + (fd_set *)NULL, &timeout); + if (n < 0) { + if (_res.options & RES_DEBUG) + perror("select"); + continue; + } + if (n == 0) { + /* + * timeout + */ + if (_res.options & RES_DEBUG) + printf("timeout (%d secs)\n", + timeout.tv_sec); +#if BSD >= 43 + gotsomewhere = 1; +#endif + continue; + } + if ((resplen = recv(s, answer, anslen, 0)) <= 0) { + if (_res.options & RES_DEBUG) + perror("recvfrom"); + continue; + } + gotsomewhere = 1; + if (id != anhp->id) { + /* + * response from old query, ignore it + */ + if (_res.options & RES_DEBUG2) { + printf("------------\nOld answer:\n"); + Print_query(answer, answer+resplen, 1); + } + goto wait; + } + if (!(_res.options & RES_IGNTC) && anhp->tc) { + /* + * get rest of answer; + * use TCP with same server. + */ + if (_res.options & RES_DEBUG) + printf("truncated answer\n"); + (void) close(s); + s = -1; + v_circuit = 1; + goto usevc; + } + } + if (_res.options & RES_DEBUG) { + if (_res.options & RES_DEBUG2) + printf("------------\nGot answer (%d bytes):\n", + resplen); + else + printf("------------\nGot answer:\n"); + Print_query(answer, answer+resplen, 1); + } + (void) close(s); + s = -1; + *trueLenPtr = resplen; + return (SUCCESS); + } + if (s >= 0) { + (void) close(s); + s = -1; + } + if (v_circuit == 0) + if (gotsomewhere == 0) + return NO_RESPONSE; /* no nameservers found */ + else + return TIME_OUT; /* no answer obtained */ + else + if (errno == ECONNREFUSED) + return NO_RESPONSE; + else + return ERROR; +} + +/* + * This routine is for closing the socket if a virtual circuit is used and + * the program wants to close it. + * + * Called from the interrupt handler. + */ +SendRequest_close() +{ + if (s != -1) { + (void) close(s); + s = -1; + } +} diff --git a/usr.sbin/nslookup/skip.c b/usr.sbin/nslookup/skip.c new file mode 100644 index 0000000..4119951 --- /dev/null +++ b/usr.sbin/nslookup/skip.c @@ -0,0 +1,211 @@ +/* + * ++Copyright++ 1985, 1989 + * - + * Copyright (c) 1985, 1989 + * 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. + * - + * --Copyright-- + */ + +#ifndef lint +static char sccsid[] = "@(#)skip.c 5.12 (Berkeley) 3/21/91"; +static char rcsid[] = "$Id: skip.c,v 4.9.1.6 1994/06/01 21:10:16 vixie Exp $"; +#endif /* not lint */ + +/* + ******************************************************************************* + * + * skip.c -- + * + * Routines to skip over portions of a query buffer. + * + * Note: this file has been submitted for inclusion in + * BIND resolver library. When this has been done, this file + * is no longer necessary (assuming there haven't been any + * changes). + * + * Adapted from 4.3BSD BIND res_debug.c + * + ******************************************************************************* + */ + +#include +#include +#include +#include +#include +#include "../../conf/portability.h" + +char *res_skip_rr(); + + +/* + ******************************************************************************* + * + * res_skip -- + * + * Skip the contents of a query. + * + * Interpretation of numFieldsToSkip argument: + * res_skip returns pointer to: + * 1 -> start of question records. + * 2 -> start of authoritative answer records. + * 3 -> start of additional records. + * 4 -> first byte after end of additional records. + * + * Results: + * (address) - success operation. + * NULL - a resource record had an incorrect format. + * + ******************************************************************************* + */ + +char * +res_skip(msg, numFieldsToSkip, eom) + char *msg; + int numFieldsToSkip; + char *eom; +{ + register char *cp; + register HEADER *hp; + register int tmp; + register int n; + + /* + * Skip the header fields. + */ + hp = (HEADER *)msg; + cp = msg + HFIXEDSZ; + + /* + * skip question records. + */ + if (n = ntohs(hp->qdcount) ) { + while (--n >= 0 && cp < eom) { + tmp = dn_skipname((u_char *)cp, (u_char *)eom); + if (tmp == -1) return(NULL); + cp += tmp; + cp += INT16SZ; /* type */ + cp += INT16SZ; /* class */ + } + } + if (--numFieldsToSkip <= 0) return(cp); + + /* + * skip authoritative answer records + */ + if (n = ntohs(hp->ancount)) { + while (--n >= 0 && cp < eom) { + cp = res_skip_rr(cp, eom); + if (cp == NULL) return(NULL); + } + } + if (--numFieldsToSkip == 0) return(cp); + + /* + * skip name server records + */ + if (n = ntohs(hp->nscount)) { + while (--n >= 0 && cp < eom) { + cp = res_skip_rr(cp, eom); + if (cp == NULL) return(NULL); + } + } + if (--numFieldsToSkip == 0) return(cp); + + /* + * skip additional records + */ + if (n = ntohs(hp->arcount)) { + while (--n >= 0 && cp < eom) { + cp = res_skip_rr(cp, eom); + if (cp == NULL) return(NULL); + } + } + + return(cp); +} + + +/* + ******************************************************************************* + * + * res_skip_rr -- + * + * Skip over resource record fields. + * + * Results: + * (address) - success operation. + * NULL - a resource record had an incorrect format. + ******************************************************************************* + */ + +char * +res_skip_rr(cp, eom) + char *cp; + char *eom; +{ + int tmp; + int dlen; + + if ((tmp = dn_skipname((u_char *)cp, (u_char *)eom)) == -1) + return (NULL); /* compression error */ + cp += tmp; + if ((cp + RRFIXEDSZ) > eom) + return (NULL); + cp += INT16SZ; /* type */ + cp += INT16SZ; /* class */ + cp += INT32SZ; /* ttl */ + dlen = _getshort((u_char*)cp); + cp += INT16SZ; /* dlen */ + cp += dlen; + if (cp > eom) + return (NULL); + return (cp); +} diff --git a/usr.sbin/nslookup/subr.c b/usr.sbin/nslookup/subr.c new file mode 100644 index 0000000..f9d9012 --- /dev/null +++ b/usr.sbin/nslookup/subr.c @@ -0,0 +1,559 @@ +/* + * ++Copyright++ 1985, 1989 + * - + * Copyright (c) 1985, 1989 + * 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. + * - + * --Copyright-- + */ + +#ifndef lint +static char sccsid[] = "@(#)subr.c 5.24 (Berkeley) 3/2/91"; +static char rcsid[] = "$Id: subr.c,v 4.9.1.7 1994/07/19 22:51:24 vixie Exp $"; +#endif /* not lint */ + +/* + ******************************************************************************* + * + * subr.c -- + * + * Miscellaneous subroutines for the name server + * lookup program. + * + * Copyright (c) 1985 + * Andrew Cherenson + * U.C. Berkeley + * CS298-26 Fall 1985 + * + ******************************************************************************* + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "res.h" +#include "../../conf/portability.h" + + + +/* + ******************************************************************************* + * + * IntrHandler -- + * + * This routine is called whenever a control-C is typed. + * It performs three main functions: + * - closes an open socket connection, + * - closes an open output file (used by LookupHost, et al.), + * - jumps back to the main read-eval loop. + * + * If a user types a ^C in the middle of a routine that uses a socket, + * the routine would not be able to close the socket. To prevent an + * overflow of the process's open file table, the socket and output + * file descriptors are closed by the interrupt handler. + * + * Side effects: + * Open file descriptors are closed. + * If filePtr is valid, it is closed. + * Flow of control returns to the main() routine. + * + ******************************************************************************* + */ + +SIG_FN +IntrHandler() +{ + extern jmp_buf env; +#if defined(BSD) && BSD >= 199006 && !defined(RISCOS_BSD) + extern FILE *yyin; /* scanner input file */ + extern void yyrestart(); /* routine to restart scanner after interrupt */ +#endif + + SendRequest_close(); + ListHost_close(); + if (filePtr != NULL && filePtr != stdout) { + fclose(filePtr); + filePtr = NULL; + } + printf("\n"); +#if defined(BSD) && BSD >= 199006 && !defined(RISCOS_BSD) + yyrestart(yyin); +#endif + longjmp(env, 1); +} + + +/* + ******************************************************************************* + * + * Malloc -- + * Calloc -- + * + * Calls the malloc library routine with SIGINT blocked to prevent + * corruption of malloc's data structures. We need to do this because + * a control-C doesn't kill the program -- it causes a return to the + * main command loop. + * + * NOTE: This method doesn't prevent the pointer returned by malloc + * from getting lost, so it is possible to get "core leaks". + * + * If malloc fails, the program exits. + * + * Results: + * (address) - address of new buffer. + * + ******************************************************************************* + */ + +char * +Malloc(size) + int size; +{ + char *ptr; + +#ifdef SYSV +#if defined(SVR3) || defined(SVR4) + sighold(SIGINT); + ptr = malloc((unsigned) size); + sigrelse(SIGINT); +#else + { SIG_FN (*old)(); + old = signal(SIGINT, SIG_IGN); + ptr = malloc((unsigned) size); + signal(SIGINT, old); + } +#endif +#else + { int saveMask; + saveMask = sigblock(sigmask(SIGINT)); + ptr = malloc((unsigned) size); + (void) sigsetmask(saveMask); + } +#endif + if (ptr == NULL) { + fflush(stdout); + fprintf(stderr, "*** Can't allocate memory\n"); + fflush(stderr); + abort(); + /*NOTREACHED*/ + } else { + return(ptr); + } +} + +char * +Calloc(num, size) + register int num, size; +{ + char *ptr = Malloc(num*size); + bzero(ptr, num*size); + return(ptr); +} + + +/* + ******************************************************************************* + * + * PrintHostInfo -- + * + * Prints out the HostInfo structure for a host. + * + ******************************************************************************* + */ + +void +PrintHostInfo(file, title, hp) + FILE *file; + char *title; + register HostInfo *hp; +{ + register char **cp; + register ServerInfo **sp; + char comma; + int i; + + fprintf(file, "%-7s %s", title, hp->name); + + if (hp->addrList != NULL) { + if (hp->addrList[1] != NULL) { + fprintf(file, "\nAddresses:"); + } else { + fprintf(file, "\nAddress:"); + } + comma = ' '; + i = 0; + for (cp = hp->addrList; cp && *cp; cp++) { + i++; + if (i > 4) { + fprintf(file, "\n\t"); + comma = ' '; + i = 0; + } + fprintf(file,"%c %s", comma, inet_ntoa(*(struct in_addr *)*cp)); + comma = ','; + } + } + + if (hp->aliases != NULL) { + fprintf(file, "\nAliases:"); + comma = ' '; + i = 10; + for (cp = hp->aliases; cp && *cp && **cp; cp++) { + i += strlen(*cp) + 2; + if (i > 75) { + fprintf(file, "\n\t"); + comma = ' '; + i = 10; + } + fprintf(file, "%c %s", comma, *cp); + comma = ','; + } + } + + if (hp->servers != NULL) { + fprintf(file, "\nServed by:\n"); + for (sp = hp->servers; *sp != NULL ; sp++) { + + fprintf(file, "- %s\n\t", (*sp)->name); + + comma = ' '; + i = 0; + for (cp = (*sp)->addrList; cp && *cp && **cp; cp++) { + i++; + if (i > 4) { + fprintf(file, "\n\t"); + comma = ' '; + i = 0; + } + fprintf(file, + "%c %s", comma, inet_ntoa(*(struct in_addr *)*cp)); + comma = ','; + } + fprintf(file, "\n\t"); + + comma = ' '; + i = 10; + for (cp = (*sp)->domains; cp && *cp && **cp; cp++) { + i += strlen(*cp) + 2; + if (i > 75) { + fprintf(file, "\n\t"); + comma = ' '; + i = 10; + } + fprintf(file, "%c %s", comma, *cp); + comma = ','; + } + fprintf(file, "\n"); + } + } + + fprintf(file, "\n\n"); +} + +/* + ******************************************************************************* + * + * OpenFile -- + * + * Parses a command string for a file name and opens + * the file. + * + * Results: + * file pointer - the open was successful. + * NULL - there was an error opening the file or + * the input string was invalid. + * + ******************************************************************************* + */ + +FILE * +OpenFile(string, file) + char *string; + char *file; +{ + char *redirect; + FILE *tmpPtr; + + /* + * Open an output file if we see '>' or >>'. + * Check for overwrite (">") or concatenation (">>"). + */ + + redirect = strchr(string, '>'); + if (redirect == NULL) { + return(NULL); + } + if (redirect[1] == '>') { + sscanf(redirect, ">> %s", file); + tmpPtr = fopen(file, "a+"); + } else { + sscanf(redirect, "> %s", file); + tmpPtr = fopen(file, "w"); + } + + if (tmpPtr != NULL) { + redirect[0] = '\0'; + } + + return(tmpPtr); +} + +/* + ******************************************************************************* + * + * DecodeError -- + * + * Converts an error code into a character string. + * + ******************************************************************************* + */ + +char * +DecodeError(result) + 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 host/domain"); break; + case NOTIMP: return("Not implemented"); break; + case REFUSED: return("Query refused"); break; + case NOCHANGE: return("No change"); break; + case TIME_OUT: return("Timed out"); break; + case NO_INFO: return("No information"); break; + case ERROR: return("Unspecified error"); break; + case NONAUTH: return("Non-authoritative answer"); break; + case NO_RESPONSE: return("No response from server"); break; + default: break; + } + return("BAD ERROR VALUE"); +} + + +int +StringToClass(class, dflt, errorfile) + char *class; + int dflt; + FILE *errorfile; +{ + if (strcasecmp(class, "IN") == 0) + return(C_IN); + if (strcasecmp(class, "HESIOD") == 0 || + strcasecmp(class, "HS") == 0) + return(C_HS); + if (strcasecmp(class, "CHAOS") == 0) + return(C_CHAOS); + if (strcasecmp(class, "ANY") == 0) + return(C_ANY); + if (errorfile) + fprintf(errorfile, "unknown query class: %s\n", class); + return(dflt); +} + + +/* + ******************************************************************************* + * + * StringToType -- + * + * Converts a string form of a query type name to its + * corresponding integer value. + * + ******************************************************************************* + */ + +int +StringToType(type, dflt, errorfile) + char *type; + int dflt; + FILE *errorfile; +{ + if (strcasecmp(type, "A") == 0) + return(T_A); + if (strcasecmp(type, "NS") == 0) + return(T_NS); /* authoritative server */ + if (strcasecmp(type, "MX") == 0) + return(T_MX); /* mail exchanger */ + if (strcasecmp(type, "CNAME") == 0) + return(T_CNAME); /* canonical name */ + if (strcasecmp(type, "SOA") == 0) + return(T_SOA); /* start of authority zone */ + if (strcasecmp(type, "MB") == 0) + return(T_MB); /* mailbox domain name */ + if (strcasecmp(type, "MG") == 0) + return(T_MG); /* mail group member */ + if (strcasecmp(type, "MR") == 0) + return(T_MR); /* mail rename name */ + if (strcasecmp(type, "WKS") == 0) + return(T_WKS); /* well known service */ + if (strcasecmp(type, "PTR") == 0) + return(T_PTR); /* domain name pointer */ + if (strcasecmp(type, "HINFO") == 0) + return(T_HINFO); /* host information */ + if (strcasecmp(type, "MINFO") == 0) + return(T_MINFO); /* mailbox information */ + if (strcasecmp(type, "AXFR") == 0) + return(T_AXFR); /* zone transfer */ + if (strcasecmp(type, "MAILA") == 0) + return(T_MAILA); /* mail agent */ + if (strcasecmp(type, "MAILB") == 0) + return(T_MAILB); /* mail box */ + if (strcasecmp(type, "ANY") == 0) + return(T_ANY); /* matches any type */ + if (strcasecmp(type, "UINFO") == 0) + return(T_UINFO); /* user info */ + if (strcasecmp(type, "UID") == 0) + return(T_UID); /* user id */ + if (strcasecmp(type, "GID") == 0) + return(T_GID); /* group id */ + if (strcasecmp(type, "TXT") == 0) + return(T_TXT); /* text */ + if (strcasecmp(type, "RP") == 0) + return(T_RP); /* responsible person */ + if (strcasecmp(type, "X25") == 0) + return(T_X25); /* x25 address */ + if (strcasecmp(type, "ISDN") == 0) + return(T_ISDN); /* isdn address */ + if (strcasecmp(type, "RT") == 0) + return(T_RT); /* router */ + if (strcasecmp(type, "AFSDB") == 0) + return(T_AFSDB); /* DCE or AFS server */ + if (strcasecmp(type, "NSAP") == 0) + return(T_NSAP); /* NSAP address */ + if (errorfile) + fprintf(errorfile, "unknown query type: %s\n", type); + return(dflt); +} + +/* + ******************************************************************************* + * + * DecodeType -- + * + * Converts a query type to a descriptive name. + * (A more verbose form of p_type.) + * + * + ******************************************************************************* + */ + +static char nbuf[20]; + +char * +DecodeType(type) + int type; +{ + switch (type) { + case T_A: + return("address"); + case T_NS: + return("name server"); + case T_CNAME: + return("canonical name"); + case T_SOA: + return("start of authority"); + case T_MB: + return("mailbox"); + case T_MG: + return("mail group member"); + case T_MR: + return("mail rename"); + case T_NULL: + return("null"); + case T_WKS: + return("well-known service"); + case T_PTR: + return("domain name pointer"); + case T_HINFO: + return("host information"); + case T_MINFO: + return("mailbox information"); + case T_MX: + return("mail exchanger"); + case T_TXT: + return("text"); + case T_RP: + return("responsible person"); + case T_AFSDB: + return("DCE or AFS server"); + case T_X25: + return("X25 address"); + case T_ISDN: + return("ISDN address"); + case T_RT: + return("router"); + case T_NSAP: + return("nsap address"); + case T_UINFO: + return("user information"); + case T_UID: + return("user ID"); + case T_GID: + return("group ID"); + case T_AXFR: + return("zone transfer"); + case T_MAILB: + return("mailbox-related data"); + case T_MAILA: + return("mail agent"); + case T_ANY: + return("\"any\""); + default: + (void) sprintf(nbuf, "%d", type); + return (nbuf); + } +} -- cgit v1.1