* Copyright (c) 1985,1989 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted provided
* that: (1) source distributions retain this entire copyright notice and
* comment, and (2) distributions including binaries display the following
* acknowledgement: ``This product includes software developed by the
* University of California, Berkeley and its contributors'' in the
* documentation or other materials provided with the distribution and in
* all advertising materials mentioning features or use of this software.
* 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
static char sccsid
[] = "@(#)list.c 5.20 (Berkeley) 6/1/90";
*******************************************************************************
* Routines to obtain info from name and finger servers.
* Adapted from 4.3BSD BIND ns_init.c and from finger.c.
*******************************************************************************
#include <arpa/nameser.h>
* Imported from res_debug.c
extern char *_res_resultcodes
[];
extern HostInfo
*defaultPtr
;
extern HostInfo curHostInfo
;
* During a listing to a file, hash marks are printed
* every HASH_SIZE records.
*******************************************************************************
* 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
* To see all types of information sorted by name, do the following:
* ls -d domain.edu > file
* 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
*******************************************************************************
ListHostsByType(string
, putToFile
)
* 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] == '>') {
qtype
= StringToType(option
, -1);
fprintf(stderr
, "*** ls: invalid request %s\n",string
);
result
= ListSubr(qtype
, namePtr
, putToFile
? string
: NULL
);
fprintf(stderr
, "*** Can't list domain %s: %s\n",
namePtr
, DecodeError(result
));
ListHosts(string
, putToFile
)
* Parse the command line. It maybe of the form "ls domain",
i
= sscanf(string
, " ls %s %s", option
, name
);
if (putToFile
&& i
== 2 && name
[0] == '>') {
if (strcmp("-a", option
) == 0) {
} else if (strcmp("-h", option
) == 0) {
} else if (strcmp("-m", option
) == 0) {
} else if (strcmp("-s", option
) == 0) {
} else if (strcmp("-d", option
) == 0) {
fprintf(stderr
, "*** ls: invalid request %s\n",string
);
result
= ListSubr(qtype
, namePtr
, putToFile
? string
: NULL
);
fprintf(stderr
, "*** Can't list domain %s: %s\n",
namePtr
, DecodeError(result
));
ListSubr(qtype
, domain
, cmd
)
static char *answer
= NULL
;
static int answerLen
= 0;
* Create a query packet for the requested domain name.
msglen
= res_mkquery(QUERY
, domain
, queryClass
, T_AXFR
,
(char *) &buf
, sizeof(buf
));
if (_res
.options
& RES_DEBUG
) {
fprintf(stderr
, "*** ls: res_mkquery failed\n");
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];
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) {
if (connect(sockFD
, &sin
, sizeof(sin
)) < 0) {
if (errno
== ECONNREFUSED
) {
* Send length & message for zone transfer
if (write(sockFD
, (char *)&len
, sizeof(len
)) != sizeof(len
) ||
write(sockFD
, (char *) &buf
, msglen
) != msglen
) {
(defaultPtr
->addrList
!= NULL
) ? defaultPtr
->name
:
defaultPtr
->servers
[0]->name
);
filePtr
= OpenFile(cmd
, file
);
fprintf(stderr
, "*** Can't open %s for writing\n", file
);
fprintf(filePtr
, "> %s\n", cmd
);
fprintf(filePtr
,"[%s]\n",
(defaultPtr
->addrList
!= NULL
) ? defaultPtr
->name
:
defaultPtr
->servers
[0]->name
);
fprintf(filePtr
, "%-30s", "Alias");
} else if (qtype
== T_TXT
) {
fprintf(filePtr
, "%-30s", "Key");
fprintf(filePtr
, "%-30s", "Host or domain name");
fprintf(filePtr
, " %-30s\n", "Internet Address");
fprintf(filePtr
, " %-30s\n", "CPU & OS");
fprintf(filePtr
, " %-30s\n", "Canonical Name");
fprintf(filePtr
, " %-30s\n", "Metric & Host");
fprintf(filePtr
, " %-4s %s\n", "Protocol", "Services");
fprintf(filePtr
, " %-30s\n", "Mailbox");
fprintf(filePtr
, " %-30s\n", "Mail Group");
fprintf(filePtr
, " %-30s\n", "Mail Rename");
fprintf(filePtr
, " %-30s\n", "Mail List Requests & Errors");
fprintf(filePtr
, " %-30s\n", "User Information");
fprintf(filePtr
, " %-30s\n", "User ID");
fprintf(filePtr
, " %-30s\n", "Group ID");
fprintf(filePtr
, " %-30s\n", "Text");
fprintf(filePtr
, " %-30s\n", "Name Servers");
fprintf(filePtr
, " %-30s\n", "Pointers");
fprintf(filePtr
, " %-30s\n", "Start of Authority");
fprintf(filePtr
, " %-30s\n", "Resource Record Info.");
* Read the length of the response.
amtToRead
= sizeof(u_short
);
while (amtToRead
> 0 && (numRead
=read(sockFD
, cp
, amtToRead
)) > 0) {
if ((len
= htons(tmp
)) == 0) {
break; /* nothing left to read */
* The server sent too much data to fit the existing buffer --
answer
= Malloc(answerLen
);
while (amtToRead
> 0 && (numRead
=read(sockFD
, cp
, amtToRead
)) > 0) {
result
= PrintListInfo(filePtr
, answer
, cp
, qtype
, dname
[0]);
if (cmd
!= NULL
&& ((numAnswers
% HASH_SIZE
) == 0)) {
cp
= answer
+ sizeof(HEADER
);
if (ntohs(((HEADER
* )answer
)->qdcount
) > 0)
cp
+= dn_skipname(cp
, answer
+ len
) + QFIXEDSZ
;
cp
+= dn_skipname(cp
, (u_char
*)answer
+ len
);
if ((_getshort(cp
) == T_SOA
)) {
dn_expand(answer
, answer
+ len
, nmp
, dname
[soacnt
],
if (strcmp(dname
[0], dname
[1]) == 0)
fprintf(stdout
, "%sReceived %d record%s.\n",
(numAnswers
>= HASH_SIZE
) ? "\n" : "",
(numAnswers
!= 1) ? "s" : "");
if (cmd
!= NULL
&& filePtr
!= NULL
) {
headerPtr
= (HEADER
*) answer
;
fprintf(stderr
,"*** ls: error receiving zone transfer:\n");
" result: %s, answers = %d, authority = %d, additional = %d\n",
_res_resultcodes
[headerPtr
->rcode
],
ntohs(headerPtr
->ancount
), ntohs(headerPtr
->nscount
),
ntohs(headerPtr
->arcount
));
*******************************************************************************
* Used by the ListInfo routine to print the answer
* received from the name server. Only the desired
* information is printed.
* 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"
strip_domain(string
, domain
)
while ((dot
= strchr(dot
, '.')) != NULL
&& strcasecmp(domain
, ++dot
))
PrintListInfo(file
, msg
, eom
, qtype
, domain
)
int type
, class, dlen
, nameLen
;
* Read the header fields.
headerPtr
= (HEADER
*)msg
;
cp
= msg
+ sizeof(HEADER
);
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) {
if (ntohs(headerPtr
->qdcount
) > 0) {
nameLen
= dn_skipname(cp
, eom
);
cp
+= nameLen
+ QFIXEDSZ
;
if ((nameLen
= dn_expand(msg
, eom
, cp
, name
, sizeof(name
))) < 0)
if (!(type
== qtype
|| qtype
== T_ANY
) &&
!((type
== T_NS
|| type
== T_PTR
) && qtype
== T_A
))
/* Strip the domain name from the data, if desired. */
if ((_res
.options
& RES_DEBUG
) == 0) {
stripped
= strip_domain(name
, domain
);
if (!stripped
&& nameLen
< sizeof(name
)-1) {
fprintf(file
, NAME_FORMAT
, name
);
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 */
bcopy(cp
, (char *)&inaddr
, sizeof(inaddr
));
fprintf(file
," %s", inet_ntoa(inaddr
));
fprintf(file
," %s", inet_ntoa(inaddr
));
fprintf(file
," (%d, %d)", cp
[4],(cp
[5] << 8) + cp
[6]);
fprintf(file
, " (dlen = %d?)", dlen
);
dn_expand(msg
, eom
, cp
, name2
, sizeof(name2
))) < 0) {
fprintf(file
, " %s", name2
);
fprintf(file
,"%s = ", type
== T_PTR
? "host" : "server");
cp
= Print_cdname2(cp
, msg
, eom
, file
);
(void)sprintf(name
,"%.*s", n
, cp
);
fprintf(file
," %-10s", name
);
fprintf(file
," %-10s", " ");
fprintf(file
," %.*s", n
, cp
);
dn_expand(msg
, eom
, cp
, name2
, sizeof(name2
))) < 0) {
fprintf(file
, " %s", name2
);
dn_expand(msg
, eom
, cp
, name2
, sizeof(name2
))) < 0) {
fprintf(file
, " %s. (", name2
);
for (n
= 0; n
< 5; n
++) {
fprintf(file
,"%s%lu", n
? " " : "", u
);
fprintf(file
," %-3d ",pref
);
dn_expand(msg
, eom
, cp
, name2
, sizeof(name2
))) < 0) {
fprintf(file
, " %s", name2
);
(void) fputs(" \"", file
);
if (n
= (unsigned char) *cp
++) {
for (c
= n
; c
> 0 && cp
< cp2
; c
--)
(void) putc(*cp
++, file
);
(void) putc(*cp
++, file
);
cp
= Print_cdname(cp
, msg
, eom
, file
);
cp
= Print_cdname(cp
, msg
, eom
, file
);
fprintf(file
, " %s", cp
);
fprintf(file
, " %lu", _getlong(cp
));
cp
+= 4; /* skip inet address */
pp
= getprotobynumber(n
);
fprintf(file
," %-3d ", n
);
fprintf(file
," %-3s ", pp
->p_name
);
ss
= getservbyport((int)htons(port
),
fprintf(file
," %u", port
);
fprintf(file
," %s", ss
->s_name
);
*******************************************************************************
* A hack to view the output of the ls command in sorted
*******************************************************************************
sscanf(string
, " view %s", file
);
(void)sprintf(command
, "grep \"^ \" %s | sort | more", file
);
*******************************************************************************
* 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).
* 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
)
* We need a valid current host info to get an inet address.
fprintf(stderr
, "Finger: no current host defined.\n");
if (sscanf(string
, " finger %s", name
) == 1) {
if (putToFile
&& (name
[0] == '>')) {
sp
= getservbyname("finger", "tcp");
fprintf(stderr
, "Finger: unknown service\n");
bzero((char *)&sin
, sizeof(sin
));
sin
.sin_family
= curHostInfo
.addrType
;
sin
.sin_port
= sp
->s_port
;
bcopy(curHostInfo
.addrList
[0], (char *)&sin
.sin_addr
,
* Set up a virtual circuit to the host.
sockFD
= socket(curHostInfo
.addrType
, SOCK_STREAM
, 0);
perror("finger: socket");
if (connect(sockFD
, (char *)&sin
, sizeof (sin
)) < 0) {
perror("finger: connect");
filePtr
= OpenFile(string
, file
);
fprintf(stderr
, "*** Can't open %s for writing\n", file
);
fprintf(filePtr
,"> %s\n", string
);
fprintf(filePtr
, "[%s]\n", curHostInfo
.name
);
write(sockFD
, name
, strlen(name
));
write(sockFD
, "\r\n", 2);
while ((c
= getc(f
)) != EOF
) {
putc(lastc
= c
, filePtr
);