* Copyright (c) 1986 Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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
* 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
"@(#) Copyright (c) 1986 Regents of the University of California.\n\
portions Copyright (c) 1993 Digital Equipment Corporation\n\
* Actually, this program is from Rutgers University, however it is
* based on nslookup and other pieces of named tools, so it needs
static char rcsid
[] = "$Id: host.c,v 1.1 1993/06/01 00:51:11 vixie Exp vixie $";
#include <arpa/nameser.h>
#define NO_DATA NO_ADDRESS
static struct __res_state orig
;
extern struct __res_state _res
;
static char *cname
= NULL
;
int server_specified
= 0;
char *pr_class(), *pr_rr(), *pr_cdname(), *pr_type();
extern char *hostalias();
register struct hostent
*hp
;
fprintf(stderr
, "Usage: host [-w] [-v] [-r] [-d] [-t querytype] [-c class] [-a] host [server]\n -w to wait forever until reply\n -v for verbose output\n -r to disable recursive processing\n -d to turn on debugging output\n -t querytype to look for a specific type of information\n -c class to look for non-Internet data\n -a is equivalent to '-v -t *'\n");
while (c
> 2 && v
[1][0] == '-') {
if (strcmp (v
[1], "-w") == 0) {
else if (strcmp (v
[1], "-r") == 0) {
_res
.options
&= ~RES_RECURSE
;
else if (strcmp (v
[1], "-d") == 0) {
_res
.options
|= RES_DEBUG
;
else if (strcmp (v
[1], "-v") == 0) {
else if (strcmp (v
[1], "-l") == 0) {
else if (strncmp (v
[1], "-t", 2) == 0) {
gettype
= parsetype(v
[1]);
else if (strncmp (v
[1], "-c", 2) == 0) {
getclass
= parseclass(v
[1]);
else if (strcmp (v
[1], "-a") == 0) {
fprintf(stderr
,"Error in looking up server name:\n");
_res
.nsaddr
.sin_addr
= *(struct in_addr
*)hp
->h_addr
;
printf("Using domain server:\n");
_res
.nsaddr
.sin_family
= AF_INET
;
_res
.nsaddr
.sin_addr
.s_addr
= addr
;
_res
.nsaddr
.sin_port
= htons(NAMESERVER_PORT
);
printf("Using domain server %s:\n",
inet_ntoa(_res
.nsaddr
.sin_addr
));
if (strcmp (v
[1], ".") == 0)
* we handle default domains ourselves, thank you
_res
.options
&= ~RES_DEFNAMES
;
exit(ListHosts(v
[1], gettype
? gettype
: T_A
));
while (hp
== NULL
&& h_errno
== TRY_AGAIN
) {
hp
= (struct hostent
*)gethostinfo(v
[1]);
hp
= (struct hostent
*)gethostinfo(oldcname
);
printf("Too many cnames. Possible loop.\n");
hp
= gethostbyaddr((char*)&addr
, 4, AF_INET
);
if (strcmp(s
,"cname") == 0)
if (strcmp(s
,"soa") == 0)
if (strcmp(s
,"null") == 0)
if (strcmp(s
,"wks") == 0)
if (strcmp(s
,"ptr") == 0)
if (strcmp(s
,"hinfo") == 0)
if (strcmp(s
,"minfo") == 0)
if (strcmp(s
,"txt") == 0) /* Roy */
if (strcmp(s
,"uinfo") == 0)
if (strcmp(s
,"uid") == 0)
if (strcmp(s
,"gid") == 0)
if (strcmp(s
,"unspec") == 0)
if (strcmp(s
,"any") == 0)
fprintf(stderr
, "Invalid query type: %s\n", s
);
if (strcmp(s
,"any") == 0)
fprintf(stderr
, "Invalid query class: %s\n", s
);
register struct hostent
*hp
;
printf("Name: %s\n", hp
->h_name
);
for (hptr
= (long **)hp
->h_addr_list
; *hptr
; hptr
++)
printf(" %s", inet_ntoa(*(struct in_addr
*)*hptr
));
for (cp
= hp
->h_aliases
; cp
&& *cp
&& **cp
; cp
++)
fprintf(stderr
,"Host not found.\n");
fprintf(stderr
,"Host not found, try again.\n");
fprintf(stderr
,"No recovery, Host not found.\n");
fprintf(stderr
,"There is an entry for this host, but it doesn't have an Internet address.\n");
static char hostbuf
[BUFSIZ
+1];
register char *cp
, **domain
;
if (strcmp(name
, ".") == 0)
return(getdomaininfo(name
, NULL
));
for (cp
= name
, n
= 0; *cp
; cp
++)
if (n
&& cp
[-1] == '.') {
hp
= getdomaininfo(name
, (char *)NULL
);
if (n
== 0 && (cp
= hostalias(name
))) {
printf("Aliased to \"%s\"\n", cp
);
_res
.options
|= RES_DEFNAMES
;
return (getdomaininfo(cp
, (char *)NULL
));
_res
.defdname_list
[nDomain
][0] != 0;
for (domain
= _res
.dnsrch_list
[nDomain
]; *domain
; domain
++) {
printf("Trying domain \"%s\"\n", *domain
);
hp
= getdomaininfo(name
, *domain
);
for (domain
= _res
.dnsrch
; *domain
; domain
++) {
printf("Trying domain \"%s\"\n", *domain
);
hp
= getdomaininfo(name
, *domain
);
if (h_errno
!= HOST_NOT_FOUND
||
(_res
.options
& RES_DNSRCH
) == 0)
printf("Trying null domain\n");
return (getdomaininfo(name
, (char *)NULL
));
getdomaininfo(name
, domain
)
return getinfo(name
, domain
, gettype
);
val1
= getinfo(name
, domain
, T_A
);
val2
= getinfo(name
, domain
, T_MX
);
getinfo(name
, domain
, type
)
int n
, n1
, i
, j
, nmx
, ancount
, nscount
, arcount
, qdcount
, buflen
;
(void)sprintf(host
, "%.*s", MAXDNAME
, name
);
(void)sprintf(host
, "%.*s.%.*s", MAXDNAME
, name
, MAXDNAME
, domain
);
n
= res_mkquery(QUERY
, host
, getclass
, type
, (char *)NULL
, 0, NULL
,
(char *)&buf
, sizeof(buf
));
if (_res
.options
& RES_DEBUG
)
printf("res_mkquery failed\n");
n
= res_send((char *)&buf
, n
, (char *)&answer
, sizeof(answer
));
if (_res
.options
& RES_DEBUG
)
printf("res_send failed\n");
eom
= (char *)&answer
+ n
;
return(printinfo(&answer
, eom
, T_ANY
, 0));
printinfo(answer
, eom
, filter
, isls
)
int n
, n1
, i
, j
, nmx
, ancount
, nscount
, arcount
, qdcount
, buflen
;
* find first satisfactory answer
ancount
= ntohs(hp
->ancount
);
qdcount
= ntohs(hp
->qdcount
);
nscount
= ntohs(hp
->nscount
);
arcount
= ntohs(hp
->arcount
);
if (_res
.options
& RES_DEBUG
|| (verbose
&& isls
== 0))
printf("rcode = %d (%s), ancount=%d\n",
hp
->rcode
, DecodeError(hp
->rcode
), ancount
);
if (hp
->rcode
!= NOERROR
|| (ancount
+nscount
+arcount
) == 0) {
/* Check if it's an authoritive answer */
h_errno
= HOST_NOT_FOUND
;
* Jeeves (TOPS-20 server) still does not
* support MX records. For the time being,
* we must accept FORMERRs as the same as
/* TpB - set a return error for this case. NO_DATA */
return(0); /* was 1,but now indicates exception */
buflen
= sizeof(hostbuf
);
cp
= (char *)answer
+ sizeof(HEADER
);
cp
+= dn_skipname(cp
,eom
) + QFIXEDSZ
;
cp
+= dn_skipname(cp
,eom
) + QFIXEDSZ
;
if (verbose
&& isls
== 0)
printf("The following answer is not authoritative:\n");
while (--ancount
>= 0 && cp
&& cp
< eom
) {
cp
= pr_rr(cp
, answer
, stdout
, filter
);
* When we ask for address and there is a CNAME, it seems to return
* both the CNAME and the address. Since we trace down the CNAME
* chain ourselves, we don't really want to print the address at
printf("For authoritative answers, see:\n");
while (--nscount
>= 0 && cp
&& cp
< eom
) {
cp
= pr_rr(cp
, answer
, stdout
, filter
);
printf("Additional information:\n");
while (--arcount
>= 0 && cp
&& cp
< eom
) {
cp
= pr_rr(cp
, answer
, stdout
, filter
);
static char cnamebuf
[MAXDNAME
];
* Print resource record fields in human readable form.
pr_rr(cp
, msg
, file
, filter
)
int type
, class, dlen
, n
, c
, proto
, ttl
;
if ((cp
= pr_cdname(cp
, msg
, name
, sizeof(name
))) == NULL
)
return (NULL
); /* compression error */
if (filter
== type
|| filter
== T_ANY
||
(filter
== T_A
&& (type
== T_PTR
|| type
== T_NS
)))
fprintf(file
,"%s\t%d%s\t%s",
name
, ttl
, pr_class(class), pr_type(type
));
fprintf(file
,"%s%s %s",name
, pr_class(class), pr_type(type
));
* Print type specific data, if appropriate
bcopy(cp
, (char *)&inaddr
, sizeof(inaddr
));
fprintf(file
,"%c%s", punc
,
fprintf(file
,"%c%s", punc
,
fprintf(file
,", protocol = %d", cp
[4]);
fprintf(file
,", port = %d",
if (dn_expand(msg
, msg
+ 512, cp
, cnamebuf
,
cp
= pr_cdname(cp
, msg
, name
, sizeof(name
));
fprintf(file
,"%c%s",punc
, name
);
fprintf(file
,"%c%.*s", punc
, n
, cp
);
fprintf(file
,"%c%.*s", punc
, n
, cp
);
cp
= pr_cdname(cp
, msg
, name
, sizeof(name
));
fprintf(file
,"\t%s", name
);
cp
= pr_cdname(cp
, msg
, name
, sizeof(name
));
fprintf(file
," %s", name
);
fprintf(file
,"(\n\t\t\t%ld\t;serial (version)", _getlong(cp
));
fprintf(file
,"\n\t\t\t%ld\t;refresh period", _getlong(cp
));
fprintf(file
,"\n\t\t\t%ld\t;retry refresh this often", _getlong(cp
));
fprintf(file
,"\n\t\t\t%ld\t;expiration period", _getlong(cp
));
fprintf(file
,"\n\t\t\t%ld\t;minimum TTL\n\t\t\t)", _getlong(cp
));
fprintf(file
,"\t%ld ",_getshort(cp
));
cp
= pr_cdname(cp
, msg
, name
, sizeof(name
));
fprintf(file
, "%s", name
);
cp
= pr_cdname(cp
, msg
, name
, sizeof(name
));
fprintf(file
, "%c%s", punc
, name
);
cp
= pr_cdname(cp
, msg
, name
, sizeof(name
));
fprintf(file
, " %s", name
);
fprintf(file
,"%c%.*s", punc
, dlen
, cp
);
fprintf(file
,"%c%s", punc
, cp
);
fprintf(file
,"%c%ld", punc
, _getlong(cp
));
if (dlen
< sizeof(u_long
) + 1)
bcopy(cp
, (char *)&inaddr
, sizeof(inaddr
));
protop
= getprotobynumber(proto
);
fprintf(file
,"%c%s %s", punc
,
inet_ntoa(inaddr
), protop
->p_name
);
fprintf(file
,"%c%s %d", punc
,
inet_ntoa(inaddr
), proto
);
while (cp
< cp1
+ dlen
) {
servp
= getservbyport (htons(n
),
fprintf(file
, " %s", servp
->s_name
);
fprintf(file
,"%c???", punc
);
fprintf(file
,"packet size error (%#x != %#x)\n", cp
, cp1
+dlen
);
* Return a string for the type
return(verbose
? "A" : "has address");
case T_NS
: /* authoritative server */
case T_MD
: /* mail destination */
case T_MF
: /* mail forwarder */
case T_CNAME
: /* connonical name */
return(verbose
? "CNAME" : "is a nickname for");
case T_SOA
: /* start of authority zone */
case T_MB
: /* mailbox domain name */
case T_MG
: /* mail group member */
case T_MX
: /* mail routing info */
return(verbose
? "MX" : "mail is handled by");
case T_TXT
: /* TXT - descriptive info */
return(verbose
? "TXT" : "descriptive text");
case T_MR
: /* mail rename name */
case T_NULL
: /* null resource record */
case T_WKS
: /* well known service */
case T_PTR
: /* domain name pointer */
case T_HINFO
: /* host information */
case T_MINFO
: /* mailbox information */
case T_AXFR
: /* zone transfer */
case T_MAILB
: /* mail box */
case T_MAILA
: /* mail address */
case T_ANY
: /* matches any type */
sprintf(nbuf
, "%d", type
);
* Return a mnemonic for class
case C_IN
: /* internet class */
return(verbose
? " IN" : "");
case C_HS
: /* internet class */
return(verbose
? " HS" : "");
case C_ANY
: /* matches any class */
(void) sprintf(nbuf
," %d", class);
pr_cdname(cp
, msg
, name
, namelen
)
if ((n
= dn_expand(msg
, msg
+ 512, cp
, name
, namelen
- 2)) < 0)
******************************************************************************
* Requests the name server to do a zone transfer so we
* find out what hosts it knows about.
* 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
******************************************************************************
ListHosts(namePtr
, queryType
)
int queryType
; /* e.g. T_A */
/* names and addresses of name servers to try */
char nsname
[NUMNS
][NAME_LEN
];
char nsipaddr
[NUMNSADDR
][IPADDRSIZE
];
* normalize to not have trailing dot. We do string compares below
* of info from name server, and it won't have trailing dots.
bcopy(&_res
.nsaddr
.sin_addr
, nsipaddr
[0], IPADDRSIZE
);
* First we have to find out where to look. This needs a NS query,
* possibly followed by looking up addresses for some of the names.
msglen
= res_mkquery(QUERY
, namePtr
, C_IN
, T_NS
,
(char *) &buf
, sizeof(buf
));
printf("res_mkquery failed\n");
msglen
= res_send((char *)&buf
,msglen
,(char *)&answer
, sizeof(answer
));
printf("Unable to get to nameserver -- try again later\n");
if (_res
.options
& RES_DEBUG
|| verbose
)
printf("rcode = %d (%s), ancount=%d\n",
answer
.qb1
.rcode
, DecodeError(answer
.qb1
.rcode
),
ntohs(answer
.qb1
.ancount
));
* Analyze response to our NS lookup
nscount
= ntohs(answer
.qb1
.ancount
) + ntohs(answer
.qb1
.nscount
) +
ntohs(answer
.qb1
.arcount
);
if (answer
.qb1
.rcode
!= NOERROR
|| nscount
== 0) {
switch (answer
.qb1
.rcode
) {
/* Check if it's an authoritive answer */
printf("No such domain\n");
printf("Unable to get information about domain -- try again later.\n");
printf("Unable to get information about that domain -- try again later.\n");
printf("That domain exists, but seems to be a leaf node.\n");
printf("Unrecoverable error looking up domain name.\n");
cp
= answer
.qb2
+ sizeof(HEADER
);
if (ntohs(answer
.qb1
.qdcount
) > 0)
cp
+= dn_skipname(cp
, answer
.qb2
+ msglen
) + QFIXEDSZ
;
* Look at response from NS lookup for NS and A records.
for (;nscount
; nscount
--) {
cp
+= dn_expand(answer
.qb2
, answer
.qb2
+ msglen
, cp
,
cp
+= sizeof(u_short
) + sizeof(u_short
) + sizeof(u_long
);
if (dn_expand(answer
.qb2
, answer
.qb2
+ msglen
, cp
,
name
, sizeof(name
)) >= 0) {
if (numns
< NUMNS
&& strcasecmp(domain
, namePtr
) == 0) {
for (i
= 0; i
< numns
; i
++)
if (strcasecmp(nsname
[i
], name
) == 0)
strncpy(nsname
[numns
], name
, sizeof(name
));
if (numnsaddr
< NUMNSADDR
)
for (i
= 0; i
< numns
; i
++) {
if (strcasecmp(nsname
[i
], domain
) == 0) {
bcopy(cp
, nsipaddr
[numnsaddr
],IPADDRSIZE
);
* Usually we'll get addresses for all the servers in the additional
* info section. But in case we don't, look up their addresses.
for (i
= 0; i
< numns
; i
++) {
hp
= gethostbyname(nsname
[i
]);
for (hptr
= (long **)hp
->h_addr_list
; *hptr
; hptr
++)
if (numnsaddr
< NUMNSADDR
) {
bcopy((char *)*hptr
, nsipaddr
[numnsaddr
],IPADDRSIZE
);
if (_res
.options
& RES_DEBUG
|| verbose
)
printf("Found %d addresses for %s by extra query\n",
if (_res
.options
& RES_DEBUG
|| verbose
)
printf("Found %d addresses for %s\n",
nshaveaddr
[i
], nsname
[i
]);
* Now nsipaddr has numnsaddr addresses for name servers that
* serve the requested domain. Now try to find one that will
* accept a zone transfer.
* Create a query packet for the requested domain name.
msglen
= res_mkquery(QUERY
, namePtr
, getclass
, T_AXFR
,
(char *) &buf
, sizeof(buf
));
if (_res
.options
& RES_DEBUG
) {
fprintf(stderr
, "ListHosts: Res_mkquery failed\n");
bzero((char *)&sin
, sizeof(sin
));
sin
.sin_family
= AF_INET
;
sin
.sin_port
= htons(NAMESERVER_PORT
);
* Set up a virtual circuit to the server.
for (;thisns
< numnsaddr
; thisns
++) {
if ((sockFD
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
bcopy(nsipaddr
[thisns
], &sin
.sin_addr
, IPADDRSIZE
);
if (_res
.options
& RES_DEBUG
|| verbose
)
printf("Trying %s\n", inet_ntoa(sin
.sin_addr
));
if (connect(sockFD
, (struct sockaddr
*)&sin
, sizeof(sin
)) >= 0)
perror("Connection failed, trying next server");
if (thisns
>= numnsaddr
) {
printf("No server for that domain responded\n");
perror("Error from the last server was");
* Send length & message for zone transfer
if (write(sockFD
, (char *)&len
, sizeof(len
)) != sizeof(len
) ||
write(sockFD
, (char *) &buf
, msglen
) != msglen
) {
* Read the length of the response.
amtToRead
= sizeof(u_short
);
while(amtToRead
> 0 && (numRead
= read(sockFD
, cp
, amtToRead
)) > 0){
if ((len
= htons(*(u_short
*)&buf
)) == 0) {
break; /* nothing left to read */
while(amtToRead
> 0 && (numRead
= read(sockFD
, cp
, amtToRead
)) > 0){
if (i
!= NOERROR
|| ntohs(buf
.qb1
.ancount
) == 0) {
if ((thisns
+1) < numnsaddr
&&
(i
== SERVFAIL
|| i
== NOTIMP
|| i
== REFUSED
)) {
if (_res
.options
& RES_DEBUG
|| verbose
)
printf("Server failed, trying next server: %s\n",
DecodeError(i
) : "Premature end of data");
printf("Server failed: %s\n",
i
!= NOERROR
? DecodeError(i
) : "Premature end of data");
result
= printinfo(&buf
, cp
, queryType
, 1);
cp
= buf
.qb2
+ sizeof(HEADER
);
if (ntohs(buf
.qb1
.qdcount
) > 0)
cp
+= dn_skipname(cp
, buf
.qb2
+ len
) + QFIXEDSZ
;
cp
+= dn_skipname(cp
, (u_char
*)&buf
+ len
);
if ((_getshort(cp
) == T_SOA
)) {
dn_expand(buf
.qb2
, buf
.qb2
+ len
, nmp
, dname
[soacnt
],
if (strcmp(dname
[0], dname
[1]) == 0)
fprintf(stderr
,"*** Error during listing of %s: %s\n",
namePtr
, DecodeError(result
));
headerPtr
= (HEADER
*) &buf
;
fprintf(stderr
,"ListHosts: error receiving zone transfer:\n");
" result: %s, answers = %d, authority = %d, additional = %d\n",
resultcodes
[headerPtr
->rcode
],
ntohs(headerPtr
->ancount
), ntohs(headerPtr
->nscount
),
ntohs(headerPtr
->arcount
));
case NOERROR
: return("Success"); break;
case FORMERR
: return("Format error"); break;
case SERVFAIL
: return("Server failed"); break;
case NXDOMAIN
: return("Non-existent domain"); break;
case NOTIMP
: return("Not implemented"); break;
case REFUSED
: return("Query refused"); break;
case NOCHANGE
: return("No change"); break;
case NO_INFO
: return("No information"); break;
case ERROR
: return("Unspecified error"); break;
case TIME_OUT
: return("Timed out"); break;
case NONAUTH
: return("Non-authoritative answer"); break;
return("BAD ERROR VALUE");