1334 lines
37 KiB
C
1334 lines
37 KiB
C
/* $NetBSD: main.c,v 1.3 2002/06/20 11:43:00 itojun Exp $ */
|
||
|
||
/*
|
||
* 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.
|
||
*/
|
||
|
||
/*
|
||
* Portions Copyright (c) 1996-1999 by Internet Software Consortium.
|
||
*
|
||
* Permission to use, copy, modify, and distribute this software for any
|
||
* purpose with or without fee is hereby granted, provided that the above
|
||
* copyright notice and this permission notice appear in all copies.
|
||
*
|
||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
||
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
||
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||
* SOFTWARE.
|
||
*/
|
||
|
||
#ifndef lint
|
||
char copyright[] =
|
||
"@(#) Copyright (c) 1985,1989 Regents of the University of California.\n\
|
||
All rights reserved.\n\
|
||
@(#) Portions Copyright (c) 1996-1999 Internet Software Consortium.\n";
|
||
#endif /* not lint */
|
||
|
||
#ifndef lint
|
||
static const char sccsid[] = "@(#)main.c 5.42 (Berkeley) 3/3/91";
|
||
static const char rcsid[] = "Id: main.c,v 8.24 2002/05/26 03:12:20 marka 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 "port_before.h"
|
||
|
||
#include <sys/param.h>
|
||
#include <sys/socket.h>
|
||
|
||
#include <netinet/in.h>
|
||
#include <arpa/nameser.h>
|
||
#include <arpa/inet.h>
|
||
|
||
#include <ctype.h>
|
||
#include <errno.h>
|
||
#include <limits.h>
|
||
#include <netdb.h>
|
||
#include <setjmp.h>
|
||
#include <signal.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <unistd.h>
|
||
|
||
#include "port_after.h"
|
||
|
||
#include <resolv.h>
|
||
|
||
#include "res.h"
|
||
#include "pathnames.h"
|
||
|
||
int yylex(void);
|
||
|
||
/*
|
||
* Name of a top-level name server. Can be changed with
|
||
* the "set root" command.
|
||
*/
|
||
|
||
#ifndef ROOT_SERVER
|
||
#define ROOT_SERVER "f.root-servers.net."
|
||
#endif
|
||
char rootServerName[NAME_LEN] = ROOT_SERVER;
|
||
|
||
/*
|
||
* Declare a resolver context.
|
||
*/
|
||
|
||
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];
|
||
union res_sockaddr_union 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(int);
|
||
FILE *filePtr;
|
||
jmp_buf env;
|
||
|
||
|
||
/*
|
||
* Browser command for help.
|
||
*/
|
||
const char *pager;
|
||
|
||
static void CvtAddrToPtr(char *name);
|
||
static void ReadRC(void);
|
||
|
||
/*
|
||
* Forward declarations.
|
||
*/
|
||
static void LocalServer(HostInfo *defaultPtr);
|
||
static void res_re_init(void);
|
||
static void res_dnsrch(char *cp);
|
||
static void Usage(void);
|
||
static void ShowOptions(void);
|
||
|
||
static void
|
||
UnionFromAddr(union res_sockaddr_union *u, int family, void *addr) {
|
||
memset(u, 0, sizeof *u);
|
||
switch (family) {
|
||
case AF_INET:
|
||
u->sin.sin_family = AF_INET;
|
||
u->sin.sin_port = htons(nsport);
|
||
memcpy(&u->sin.sin_addr, addr, 4);
|
||
#ifdef HAVE_SA_LEN
|
||
u->sin.sin_len = sizeof(u->sin);
|
||
#endif
|
||
break;
|
||
case AF_INET6:
|
||
u->sin6.sin6_family = AF_INET6;
|
||
u->sin6.sin6_port = htons(nsport);
|
||
memcpy(&u->sin6.sin6_addr, addr, 16);
|
||
#ifdef HAVE_SA_LEN
|
||
u->sin6.sin6_len = sizeof(u->sin6);
|
||
#endif
|
||
break;
|
||
default:
|
||
abort();
|
||
}
|
||
}
|
||
|
||
/*
|
||
******************************************************************************
|
||
*
|
||
* main --
|
||
*
|
||
* Initializes the resolver library and determines the address
|
||
* of the initial name server. The yylex routine is used to
|
||
* read and perform commands.
|
||
*
|
||
******************************************************************************
|
||
*/
|
||
|
||
int
|
||
main(int argc, char **argv) {
|
||
char *wantedHost = NULL;
|
||
Boolean useLocalServer;
|
||
int result;
|
||
int i;
|
||
|
||
/*
|
||
* Initialize the resolver library routines.
|
||
*/
|
||
|
||
if (res_ninit(&res) == -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) {
|
||
int nscount = 0;
|
||
union res_sockaddr_union u[MAXNS];
|
||
struct addrinfo *answer = NULL;
|
||
struct addrinfo *cur = NULL;
|
||
struct addrinfo hint;
|
||
|
||
/*
|
||
* Use an explicit name server. If the hostname lookup fails,
|
||
* default to the server(s) in resolv.conf.
|
||
*/
|
||
|
||
memset(u, 0, sizeof(u));
|
||
memset(&hint, 0, sizeof(hint));
|
||
hint.ai_socktype = SOCK_DGRAM;
|
||
if (!getaddrinfo(*++argv, NULL, &hint, &answer)) {
|
||
for (cur = answer; cur != NULL; cur = cur->ai_next) {
|
||
if (nscount == MAXNS)
|
||
break;
|
||
switch (cur->ai_addr->sa_family) {
|
||
case AF_INET6:
|
||
u[nscount].sin6 = *(struct sockaddr_in6*)cur->ai_addr;
|
||
u[nscount++].sin6.sin6_port = htons(nsport);
|
||
break;
|
||
case AF_INET:
|
||
u[nscount].sin = *(struct sockaddr_in*)cur->ai_addr;
|
||
u[nscount++].sin.sin_port = htons(nsport);
|
||
break;
|
||
}
|
||
}
|
||
if (nscount != 0)
|
||
res_setservers(&res, u, nscount);
|
||
freeaddrinfo(answer);;
|
||
}
|
||
}
|
||
|
||
|
||
if (res.nscount == 0 || useLocalServer) {
|
||
LocalServer(defaultPtr);
|
||
} else {
|
||
int nscount = 0;
|
||
union res_sockaddr_union u[MAXNS];
|
||
|
||
nscount = res_getservers(&res, u, MAXNS);
|
||
for (i = 0; i < nscount; i++) {
|
||
if (u[i].sin.sin_family == AF_INET &&
|
||
u[i].sin.sin_addr.s_addr == INADDR_ANY) {
|
||
LocalServer(defaultPtr);
|
||
break;
|
||
} else {
|
||
result = GetHostInfoByAddr(&u[i], &u[i], defaultPtr);
|
||
if (result != SUCCESS) {
|
||
char t[80];
|
||
switch (u[i].sin.sin_family) {
|
||
case AF_INET:
|
||
inet_ntop(AF_INET, &u[i].sin.sin_addr, t, sizeof(t));
|
||
break;
|
||
case AF_INET6:
|
||
inet_ntop(AF_INET6, &u[i].sin6.sin6_addr, t, sizeof(t));
|
||
break;
|
||
default:
|
||
strcpy(t, "<UNKNOWN>");
|
||
break;
|
||
}
|
||
fprintf(stderr,
|
||
"*** Can't find server name for address %s: %s\n",
|
||
t, DecodeError(result));
|
||
} else {
|
||
defaultAddr = u[i];
|
||
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);
|
||
}
|
||
|
||
|
||
static void
|
||
LocalServer(defaultPtr)
|
||
HostInfo *defaultPtr;
|
||
{
|
||
char hostName[NAME_LEN];
|
||
|
||
(void) gethostname(hostName, sizeof(hostName));
|
||
|
||
memset(&defaultAddr, 0, sizeof(defaultAddr));
|
||
defaultAddr.sin.sin_addr.s_addr = htonl(INADDR_ANY);
|
||
defaultAddr.sin.sin_family = AF_INET;
|
||
defaultAddr.sin.sin_port = htons(nsport);
|
||
#ifdef HAVE_SA_LEN
|
||
defaultAddr.sin.sin_len = sizeof(defaultAddr.sin);
|
||
#endif
|
||
(void) GetHostInfoByName(&defaultAddr, C_IN, T_A,
|
||
"0.0.0.0", defaultPtr, 1, 0);
|
||
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.
|
||
*
|
||
******************************************************************************
|
||
*/
|
||
|
||
static void
|
||
Usage(void) {
|
||
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)
|
||
const char *host;
|
||
union res_sockaddr_union *addrPtr;
|
||
/* If return TRUE, contains IP address */
|
||
{
|
||
if (inet_pton(AF_INET6, host, &addrPtr->sin6.sin6_addr) == 1) {
|
||
addrPtr->sin6.sin6_family = AF_INET6;
|
||
addrPtr->sin6.sin6_port = htons(nsport);
|
||
#ifdef HAVE_SA_LEN
|
||
addrPtr->sin6.sin6_len = sizeof(addrPtr->sin6);
|
||
#endif
|
||
} else if (inet_pton(AF_INET, host, &addrPtr->sin.sin_addr) == 1) {
|
||
addrPtr->sin.sin_family = AF_INET;
|
||
addrPtr->sin.sin_port = htons(nsport);
|
||
#ifdef HAVE_SA_LEN
|
||
addrPtr->sin.sin_len = sizeof(addrPtr->sin);
|
||
#endif
|
||
} else
|
||
return FALSE;
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
/*
|
||
******************************************************************************
|
||
*
|
||
* 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;
|
||
union res_sockaddr_union servAddr;
|
||
union res_sockaddr_union addr;
|
||
char newServer[NAME_LEN];
|
||
int result;
|
||
int tresult;
|
||
int i;
|
||
int j;
|
||
|
||
/*
|
||
* Parse the command line. It maybe of the form "server name",
|
||
* "lserver name" or just "name".
|
||
*/
|
||
|
||
if (local) {
|
||
i = matchString (" lserver ", string);
|
||
if (i > 0) {
|
||
j = pickString(string + i, newServer, sizeof newServer);
|
||
if (j == 0) { /* value was too big for newServer variable */
|
||
fprintf(stderr,
|
||
"SetDefaultServer: invalid name: %s\n",
|
||
string + i);
|
||
return(ERROR);
|
||
}
|
||
}
|
||
} else {
|
||
i = matchString(" server ", string);
|
||
if (i > 0) {
|
||
j = pickString(string + i, newServer, sizeof newServer);
|
||
if (j == 0) { /* value was too big for newServer variable */
|
||
fprintf(stderr,
|
||
"SetDefaultServer: invalid name: %s\n",
|
||
string + i);
|
||
return(ERROR);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (i == 0) {
|
||
i = pickString(string, newServer, sizeof newServer);
|
||
if (i == 0) { /* value was too big for newServer variable */
|
||
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) {
|
||
servAddr = defaultAddr;
|
||
} else if (defaultPtr->addrList != NULL) {
|
||
UnionFromAddr(&servAddr, defaultPtr->addrList[0]->addrType,
|
||
defaultPtr->addrList[0]->addr);
|
||
} else {
|
||
UnionFromAddr(&servAddr, defaultPtr->addrList[0]->addrType,
|
||
defaultPtr->servers[0]->addrList[0]->addr);
|
||
}
|
||
|
||
result = ERROR;
|
||
if (IsAddr(newServer, &addr)) {
|
||
result = GetHostInfoByAddr(&servAddr, &addr, newDefPtr);
|
||
/* If we can't get the name, fall through... */
|
||
}
|
||
if (result != SUCCESS && result != NONAUTH) {
|
||
result = GetHostInfoByName(&servAddr, C_IN, T_A,
|
||
newServer, newDefPtr, 1, 0);
|
||
if (result == SUCCESS || result == NONAUTH || result == NO_INFO)
|
||
tresult = GetHostInfoByName(&servAddr, C_IN, T_AAAA,
|
||
newServer, newDefPtr, 1, 1);
|
||
if (result == NO_INFO)
|
||
result = tresult;
|
||
}
|
||
|
||
/* If we ask for an A record and get none back, but get an NS
|
||
record for the NS server, this is the NONAUTH case.
|
||
We must check whether we got an IP address for the NS
|
||
server or not. */
|
||
if ((result == SUCCESS || result == NONAUTH) &&
|
||
((newDefPtr->addrList && newDefPtr->addrList[0] != 0) ||
|
||
(newDefPtr->servers && newDefPtr->servers[0] &&
|
||
newDefPtr->servers[0]->addrList[0] != 0))) {
|
||
/*
|
||
* 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;
|
||
union res_sockaddr_union servAddr;
|
||
union res_sockaddr_union 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) {
|
||
UnionFromAddr(&servAddr, servPtr->addrList[0]->addrType,
|
||
servPtr->addrList[0]->addr);
|
||
} else {
|
||
UnionFromAddr(&servAddr, servPtr->servers[0]->addrList[0]->addrType,
|
||
servPtr->servers[0]->addrList[0]->addr);
|
||
}
|
||
|
||
/*
|
||
* RFC1123 says we "SHOULD check the string syntactically for a
|
||
* dotted-decimal number before looking it up [...]" (p. 13).
|
||
*/
|
||
if ((queryType == T_A || queryType == T_AAAA) && IsAddr(host, &addr)) {
|
||
result = GetHostInfoByAddr(&servAddr, &addr, &curHostInfo);
|
||
} else {
|
||
if (queryType == T_PTR) {
|
||
CvtAddrToPtr(host);
|
||
}
|
||
result = GetHostInfoByName(&servAddr, queryClass, queryType, host,
|
||
&curHostInfo, 0, 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 || queryType == T_AAAA) {
|
||
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;
|
||
int i;
|
||
|
||
/*
|
||
* 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.
|
||
*
|
||
*/
|
||
|
||
i = pickString(string, host, sizeof host);
|
||
if (i == 0) { /* string was too long for host variable */
|
||
fprintf(stderr, "*** invalid name: %s\n", string);
|
||
return(ERROR);
|
||
}
|
||
|
||
if (!putToFile) {
|
||
filePtr = stdout;
|
||
} else {
|
||
filePtr = OpenFile(string, file, sizeof 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(char *string, Boolean putToFile) {
|
||
char file[PATH_MAX];
|
||
char host[NAME_LEN];
|
||
char server[NAME_LEN];
|
||
int result;
|
||
static HostInfo serverInfo;
|
||
int i;
|
||
int j;
|
||
union res_sockaddr_union u;
|
||
|
||
curHostValid = FALSE;
|
||
|
||
i = pickString(string, host, sizeof host);
|
||
if (i == 0) { /* value was too big for host variable */
|
||
fprintf(stderr, "*** invalid name: %s\n", string);
|
||
return(ERROR);
|
||
}
|
||
|
||
j = pickString(string + i, server, sizeof server);
|
||
if (j == 0) { /* value was too big for server variable */
|
||
fprintf(stderr, "*** invalid server name: %s\n", string + i);
|
||
return(ERROR);
|
||
}
|
||
|
||
if (!putToFile) {
|
||
filePtr = stdout;
|
||
} else {
|
||
filePtr = OpenFile(string, file, sizeof file);
|
||
if (filePtr == NULL) {
|
||
fprintf(stderr, "*** Can't open %s for writing\n", file);
|
||
return(ERROR);
|
||
}
|
||
fprintf(filePtr,"> %s\n", string);
|
||
}
|
||
|
||
if (defaultPtr->addrList != NULL)
|
||
UnionFromAddr(&u, defaultPtr->addrList[0]->addrType,
|
||
defaultPtr->addrList[0]->addr);
|
||
else
|
||
UnionFromAddr(&u, defaultPtr->servers[0]->addrList[0]->addrType,
|
||
defaultPtr->servers[0]->addrList[0]->addr);
|
||
result = GetHostInfoByName(&u, C_IN, T_A, server, &serverInfo, 1, 0);
|
||
if (result == NO_INFO)
|
||
result = GetHostInfoByName(&u, C_IN, T_AAAA, server,
|
||
&serverInfo, 1, 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;
|
||
int i;
|
||
|
||
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) {
|
||
i = pickString(++ptr, res.defdname, sizeof res.defdname);
|
||
if (i == 0) { /* name too long or nothing there */
|
||
fprintf(stderr, "** invalid 'domain' value: %s\n",
|
||
ptr) ;
|
||
return(ERROR);
|
||
}
|
||
|
||
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) {
|
||
i = pickString(++ptr, type, sizeof type);
|
||
if (i == 0) { /* value too big or nothing there */
|
||
fprintf(stderr, "*** invalid type value: %s\n",
|
||
ptr) ;
|
||
return(ERROR);
|
||
}
|
||
|
||
i = StringToType(type, queryType, stderr);
|
||
if (ns_t_xfr_p(i)) {
|
||
fprintf(stderr, "*** qtype may not be a zone transfer\n");
|
||
return(ERROR);
|
||
}
|
||
|
||
queryType = i;
|
||
}
|
||
} else if (strncmp(option, "cl", 2) == 0) { /* query class */
|
||
ptr = strchr(option, '=');
|
||
if (ptr != NULL) {
|
||
i = pickString(++ptr, type, sizeof type);
|
||
if (i == 0) { /* value too big or nothing there */
|
||
fprintf(stderr, "*** invalid class : %s\n",
|
||
ptr) ;
|
||
return(ERROR);
|
||
}
|
||
|
||
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) {
|
||
i = pickString(++ptr, rootServerName, sizeof rootServerName);
|
||
if (i == 0) { /* value too big or nothing there */
|
||
fprintf(stderr, "*** invalid root server name : %s\n",
|
||
ptr) ;
|
||
return(ERROR) ;
|
||
}
|
||
}
|
||
} 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.
|
||
*/
|
||
static void
|
||
res_re_init(void) {
|
||
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 '/'
|
||
|
||
static void
|
||
res_dnsrch(char *cp) {
|
||
char **pp;
|
||
int n;
|
||
|
||
(void)strncpy(res.defdname, cp, sizeof(res.defdname) - 1);
|
||
res.defdname[sizeof(res.defdname) - 1] = '\0';
|
||
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.
|
||
*
|
||
******************************************************************************
|
||
*/
|
||
|
||
static void
|
||
ShowOptions(void)
|
||
{
|
||
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);
|
||
|
||
cp = res.dnsrch;
|
||
if (cp != NULL) {
|
||
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(void)
|
||
{
|
||
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;
|
||
{
|
||
const char *p;
|
||
int ip[4];
|
||
union res_sockaddr_union addr;
|
||
|
||
if (IsAddr(name, &addr)) {
|
||
switch (addr.sin.sin_family) {
|
||
case AF_INET:
|
||
p = inet_ntoa(addr.sin.sin_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]);
|
||
break;
|
||
case AF_INET6:
|
||
sprintf(name,
|
||
"%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
|
||
"%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
|
||
"ip6.arpa",
|
||
addr.sin6.sin6_addr.s6_addr[15] & 0xf,
|
||
(addr.sin6.sin6_addr.s6_addr[15] >> 4) & 0xf,
|
||
addr.sin6.sin6_addr.s6_addr[14] & 0xf,
|
||
(addr.sin6.sin6_addr.s6_addr[14] >> 4) & 0xf,
|
||
addr.sin6.sin6_addr.s6_addr[13] & 0xf,
|
||
(addr.sin6.sin6_addr.s6_addr[13] >> 4) & 0xf,
|
||
addr.sin6.sin6_addr.s6_addr[12] & 0xf,
|
||
(addr.sin6.sin6_addr.s6_addr[12] >> 4) & 0xf,
|
||
addr.sin6.sin6_addr.s6_addr[11] & 0xf,
|
||
(addr.sin6.sin6_addr.s6_addr[11] >> 4) & 0xf,
|
||
addr.sin6.sin6_addr.s6_addr[10] & 0xf,
|
||
(addr.sin6.sin6_addr.s6_addr[10] >> 4) & 0xf,
|
||
addr.sin6.sin6_addr.s6_addr[9] & 0xf,
|
||
(addr.sin6.sin6_addr.s6_addr[9] >> 4) & 0xf,
|
||
addr.sin6.sin6_addr.s6_addr[8] & 0xf,
|
||
(addr.sin6.sin6_addr.s6_addr[8] >> 4) & 0xf,
|
||
addr.sin6.sin6_addr.s6_addr[7] & 0xf,
|
||
(addr.sin6.sin6_addr.s6_addr[7] >> 4) & 0xf,
|
||
addr.sin6.sin6_addr.s6_addr[6] & 0xf,
|
||
(addr.sin6.sin6_addr.s6_addr[6] >> 4) & 0xf,
|
||
addr.sin6.sin6_addr.s6_addr[5] & 0xf,
|
||
(addr.sin6.sin6_addr.s6_addr[5] >> 4) & 0xf,
|
||
addr.sin6.sin6_addr.s6_addr[4] & 0xf,
|
||
(addr.sin6.sin6_addr.s6_addr[4] >> 4) & 0xf,
|
||
addr.sin6.sin6_addr.s6_addr[3] & 0xf,
|
||
(addr.sin6.sin6_addr.s6_addr[3] >> 4) & 0xf,
|
||
addr.sin6.sin6_addr.s6_addr[2] & 0xf,
|
||
(addr.sin6.sin6_addr.s6_addr[2] >> 4) & 0xf,
|
||
addr.sin6.sin6_addr.s6_addr[1] & 0xf,
|
||
(addr.sin6.sin6_addr.s6_addr[1] >> 4) & 0xf,
|
||
addr.sin6.sin6_addr.s6_addr[0] & 0xf,
|
||
(addr.sin6.sin6_addr.s6_addr[0] >> 4) & 0xf);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
******************************************************************************
|
||
*
|
||
* ReadRC --
|
||
*
|
||
* Use the contents of ~/.nslookuprc as options.
|
||
*
|
||
******************************************************************************
|
||
*/
|
||
|
||
static void
|
||
ReadRC(void)
|
||
{
|
||
register FILE *fp;
|
||
register char *cp;
|
||
char buf[PATH_MAX];
|
||
|
||
if ((cp = getenv("HOME")) != NULL &&
|
||
(strlen(cp) + strlen(_PATH_NSLOOKUPRC)) < sizeof(buf)) {
|
||
|
||
(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);
|
||
}
|
||
}
|
||
}
|