/*
* Copyright (c) 1988 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef lint
static char Version[] = "@(#)aslookup.c e07@nikhef.nl (Eric Wassenaar) 991603";
#endif
#if defined(apollo) && defined(lint)
#define __attribute(x)
#endif
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <signal.h>
#include <setjmp.h>
#include <netdb.h>
#include <sys/types.h> /* not always automatically included */
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "port.h"
#include "aslookup.h"
#include "exit.h"
#ifndef MAXDNAME
#define MAXDNAME 256 /* maximum length of domain name */
#endif
#ifdef lint
#define EXTERN
#else
#define EXTERN extern
#endif
EXTERN int errno;
EXTERN int h_errno;
extern char *version; /* program version number */
#define NOT_DOTTED_QUAD ((ipaddr_t)-1)
#define MAXINT16 65535
#define MAXADDRS 35 /* max address count from gethostnamadr.c */
#include "defs.h" /* declarations of functions */
#define sameword(a,b) (strcasecmp(a,b) == 0)
#define is_space(c) (isascii(c) && isspace(c))
#define setalarm(n) (void) alarm((unsigned int)(n))
/*
** AS_LOOKUP -- Lookup the AS-number of the given IP address
** ---------------------------------------------------------
**
** Returns:
** Pointer to AS-number ascii string, if found.
** NULL if it could not be determined.
**
** Side effects:
** Keep the status of the connection cached as follows:
** EX_NOINPUT Not connected (initial state)
** EX_SUCCESS Connected
** EX_TEMPFAIL Temporary failure on previous connect
** EX_NOHOST Permanent failure (unknown server)
** EX_UNAVAILABLE Permanent failure (service not running)
*/
#define MAXAS 80 /* maximum size of AS numbers and names */
char *
as_lookup(inaddr, server, port, keepopen)
struct in_addr inaddr; /* IP address to look up */
char *server; /* explicit whois server */
int port; /* specific tcp port */
bool keepopen; /* keep server connection alive */
{
static int status = EX_NOINPUT; /* cached connection status */
static char *options = NULL; /* default whois server options */
bool newline = FALSE; /* set if newline encountered */
bool inobject = FALSE; /* set if examining db object */
static char numberbuf[MAXAS+1]; /* AS-number string if found */
char *number = NULL; /* set to numberbuf if found */
static char namebuf[MAXAS+1]; /* AS-name string if found */
char *name = NULL; /* set to namebuf if found */
static char buf[2*MAXAS+3+1];
register char *p;
/*
* Determine server if not explicitly given.
*/
if (server == NULL && status != EX_SUCCESS)
{
/* check environment */
p = getenv("AS_SERVER_HOST");
if (p != NULL && *p != '\0')
server = p;
#ifdef AS_SERVER_HOST
/* use default server if defined */
if (server == NULL)
server = AS_SERVER_HOST;
#endif
/* at this point it must exist */
if (server == NULL)
{
/* result = EX_NOINPUT; */
return(NULL);
}
}
/*
* Determine service port if not explicitly given.
* If still unspecified, the default service port will be used.
*/
if (port == 0 && status != EX_SUCCESS)
{
/* check environment */
p = getenv("AS_SERVER_PORT");
if (p != NULL && *p != '\0')
port = atoi(p);
/* ensure it is in range */
if (port < 0 || port > MAXINT16)
port = 0;
}
/*
* Fetch specific whois server options.
* If still unspecified, use default options if available.
*/
if (options == NULL)
{
/* check environment */
p = getenv("AS_SERVER_OPTIONS");
if (p != NULL && *p != '\0')
options = p;
#ifdef AS_SERVER_OPTIONS
/* use default options if defined */
if (options == NULL)
options = AS_SERVER_OPTIONS;
#endif
/* in case there are no options */
if (options == NULL)
options = "";
}
/*
* Connect to the server, unless already connected.
*/
/* do not re-connect after permament failures */
if (status == EX_NOINPUT || status == EX_TEMPFAIL)
status = as_connect(server, port);
/* give up if connect failed -- cache status */
if (status != EX_SUCCESS)
return(NULL);
/*
* Construct and issue the AS-number lookup command.
*/
if ((options[0] == '-' && options[1] == 'k') || !keepopen)
(void) sprintf(buf, "%.80s %s", options, as_netof(inaddr));
else
(void) sprintf(buf, "-k %.80s %s", options, as_netof(inaddr));
if (buf[0] == '-' && buf[1] == 'k')
keepopen = TRUE;
/* send the command */
as_put(buf);
/*
* Try to filter out the AS-number from the reply.
*/
while ((p = as_get(buf, sizeof(buf))) != NULL)
{
while (is_space(buf[0]))
(void) strcpy(buf, buf+1);
/* double newline terminates input */
if ((buf[0] == '\0') && newline)
break;
newline = (buf[0] == '\0') ? TRUE : FALSE;
/* single newline terminates database object */
if (newline)
inobject = FALSE;
/* split keyword and parameters */
p = index(buf, ':');
if (p == NULL)
continue;
*p++ = '\0';
while (is_space(*p))
p++;
/*
* Extract AS-number from the first route object found.
* Kludge: ensure enough CIDR bits, and skip dummy AS-number.
*/
if (!inobject && sameword(buf, "route"))
{
p = rindex(p, '/');
if (p != NULL && atoi(p+1) >= 8)
inobject = TRUE;
}
else if (inobject && sameword(buf, "origin"))
{
if ((number == NULL) && !sameword(p, "AS0"))
number = strncpy(numberbuf, p, MAXAS);
}
else if (inobject && sameword(buf, "descr"))
{
if (name == NULL)
name = strncpy(namebuf, p, MAXAS);
}
}
/*
* Disconnect from server if necessary.
*/
/* always disconnect on errors */
if ((p == NULL) || !keepopen)
{
as_disconnect();
status = EX_NOINPUT;
}
/* return partial result */
if (number == NULL || name == NULL)
return(number != NULL ? number : name);
/* combine both answers */
(void) sprintf(buf, "%s - %s", number, name);
return(buf);
}
/*
** AS_CONNECT -- Establish connection to WHOIS server
** --------------------------------------------------
**
** Returns:
** Status code indicating success or failure.
**
** Outputs:
** Sets OutChannel and InChannel.
*/
int ConnTimeout = CONNTIMEOUT; /* timeout in secs for connect */
int ReadTimeout = READTIMEOUT; /* timeout in secs for read reply */
FILE *InChannel = NULL; /* input channel from server */
FILE *OutChannel = NULL; /* output channel to server */
static jmp_buf Timeout;
static sigtype_t /*ARGSUSED*/
timer(sig)
int sig;
{
longjmp(Timeout, 1);
/*NOTREACHED*/
}
int
as_connect(server, port)
char *server; /* host name to connect to */
int port; /* tcp port on server (host order) */
{
struct in_addr inaddr[MAXADDRS];/* all server addresses */
int naddrs; /* number of server addresses */
struct hostent *hp;
struct sockaddr_in sin;
ipaddr_t addr;
int sock;
register int i;
/*
* Reset state.
*/
bzero((char *)&sin, sizeof(sin));
errno = 0;
h_errno = 0;
if (server == NULL || server[0] == '\0')
server = "localhost";
/* use default port if unspecified */
if (port == 0)
port = AS_SERVER_PORT;
/*
* Fetch the ip addresses of the given host.
*/
addr = inet_addr(server);
if (addr == NOT_DOTTED_QUAD)
{
hp = gethostbyname(server);
if (hp == NULL)
{
/* cannot contact nameserver, force retry */
if (errno == ETIMEDOUT || errno == ECONNREFUSED)
h_errno = TRY_AGAIN;
/* nameserver could not resolve name properly */
if (h_errno == TRY_AGAIN)
return(EX_TEMPFAIL);
/* no address found by nameserver */
return(EX_NOHOST);
}
for (i = 0; i < MAXADDRS && hp->h_addr_list[i]; i++)
bcopy(hp->h_addr_list[i], (char *)&inaddr[i], INADDRSZ);
naddrs = i;
}
else
{
inaddr[0].s_addr = addr;
naddrs = 1;
}
/*
* Try to make connection to each of the addresses in turn.
*/
for (i = 0; i < naddrs; i++)
{
sin.sin_family = AF_INET;
sin.sin_port = htons((u_short)port);
sin.sin_addr = inaddr[i];
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
/* cannot get socket */
return(EX_TEMPFAIL);
}
if (setjmp(Timeout) != 0)
{
(void) close(sock);
errno = ETIMEDOUT;
continue;
}
/*
* Connect to the server using a short timeout.
* Exit immediately if the service is not running on the server.
*/
(void) signal(SIGALRM, timer);
setalarm(ConnTimeout);
if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
int save_errno = errno;
setalarm(0);
(void) close(sock);
errno = save_errno;
if (errno == EINTR)
errno = ETIMEDOUT;
if (errno == ECONNREFUSED)
{
/* service is not running */
return(EX_UNAVAILABLE);
}
continue;
}
setalarm(0);
/*
* Put connection in canonical form.
*/
OutChannel = fdopen(sock, "w");
InChannel = fdopen(dup(sock), "r");
if (InChannel == NULL || OutChannel == NULL)
{
int save_errno = errno;
(void) close(sock);
errno = save_errno;
as_disconnect();
/* could not setup channel */
return(EX_TEMPFAIL);
}
errno = 0;
h_errno = 0;
/* connection established */
return(EX_SUCCESS);
}
/* all connection attempts failed */
return(EX_TEMPFAIL);
}
/*
** AS_DISCONNECT -- Disconnect from WHOIS server
** ---------------------------------------------
**
** Returns:
** None.
**
** Outputs:
** Resets OutChannel and InChannel.
*/
void
as_disconnect()
{
int save_errno = errno; /* preserve state */
if (InChannel != NULL)
{
(void) fclose(InChannel);
InChannel = NULL;
}
if (OutChannel != NULL)
{
(void) fclose(OutChannel);
OutChannel = NULL;
}
/* restore state */
errno = save_errno;
}
/*
** AS_PUT -- Issue command to WHOIS server
** ---------------------------------------
**
** Returns:
** None.
**
** Side effects:
** Appends CRLF to the command.
*/
void
as_put(buf)
char *buf; /* output buffer with command */
{
if (OutChannel != NULL)
{
/* send the message over the channel */
(void) fprintf(OutChannel, "%s\r\n", buf);
/* immediately flush the output channel */
(void) fflush(OutChannel);
}
}
/*
** AS_GET -- Read an input line, using timeout
** -------------------------------------------
**
** Returns:
** Pointer to start of input line, if read ok.
** NULL on error (including timeout).
**
** Side effects:
** Strips trailing CRLF combination.
*/
char *
as_get(buf, size)
char *buf; /* input buffer */
int size; /* size of input buffer */
{
register char *p = NULL;
/* in case not connected */
if (InChannel == NULL)
{
errno = ECONNRESET;
return(NULL);
}
/* arrange for timeout */
if (setjmp(Timeout) != 0)
{
errno = ETIMEDOUT;
return(NULL);
}
/*
* Read a reply from the input channel with timeout.
*/
(void) signal(SIGALRM, timer);
setalarm(ReadTimeout);
while ((p == NULL) && !feof(InChannel) && !ferror(InChannel))
{
errno = 0;
p = fgets(buf, size, InChannel);
if (errno == EINTR)
clearerr(InChannel);
}
setalarm(0);
/*
* Determine possible error condition.
*/
if (p == NULL)
{
if (feof(InChannel) && (errno == 0))
errno = ECONNRESET;
if (ferror(InChannel) && (errno == 0))
errno = EIO;
return(NULL);
}
/*
* Remove trailing CRLF combination.
*/
p = index(buf, '\n');
if (p != NULL)
{
if (p > buf && p[-1] == '\r')
p--;
*p = '\0';
}
/* valid reply received */
return(buf);
}
/*
** AS_NETOF -- Get ascii representation of network number
** ------------------------------------------------------
**
** Returns:
** Pointer to string in static storage.
*/
#define CLASSA(a) (((a) & (ipaddr_t)0x80000000) == (ipaddr_t)0x00000000)
#define CLASSB(a) (((a) & (ipaddr_t)0xC0000000) == (ipaddr_t)0x80000000)
#define CLASSC(a) (((a) & (ipaddr_t)0xE0000000) == (ipaddr_t)0xC0000000)
#define CLASSD(a) (((a) & (ipaddr_t)0xF0000000) == (ipaddr_t)0xE0000000)
#define CLASSE(a) (((a) & (ipaddr_t)0xF0000000) == (ipaddr_t)0xF0000000)
#define CLASSL(a) (((a) & (ipaddr_t)0xFF000000) == (ipaddr_t)0x7F000000)
#define CLASSA_NET (ipaddr_t)0xFF000000
#define CLASSB_NET (ipaddr_t)0xFFFF0000
#define CLASSC_NET (ipaddr_t)0xFFFFFF00
#define CLASSD_NET (ipaddr_t)0xFFFFFFFF /* XXX */
#define CLASSE_NET (ipaddr_t)0xFFFFFFFF /* XXX */
char *
as_netof(inaddr)
struct in_addr inaddr; /* IP address */
{
register ipaddr_t address = ntohl(inaddr.s_addr);
register ipaddr_t netmask;
if (CLASSA(address))
netmask = CLASSA_NET;
else if (CLASSB(address))
netmask = CLASSB_NET;
else if (CLASSC(address))
netmask = CLASSC_NET;
else if (CLASSD(address))
netmask = CLASSD_NET;
else
netmask = CLASSE_NET;
/* mask network part */
address &= netmask;
#ifdef AS_NETMASK
inaddr.s_addr = htonl(address);
#endif
return(inet_ntoa(inaddr));
}
/*
** Special definitions if compiled stand-alone.
*/
#ifdef STANDALONE
/* main.c */
int main PROTO((int, char **));
int lookup PROTO((char *, char *, int, bool));
void fatal PROTO((char *, ...));
void error PROTO((char *, ...));
/* misc.c */
char *itoa PROTO((int));
static char Usage[] = "Usage: %s [-h server] [-k] [-p port] host ...";
/*
** MAIN -- Start of program aslookup
** ---------------------------------
**
** Standalone wrapper test program for as_lookup().
**
** Exits:
** Various possibilities from <sysexits.h>
** EX_SUCCESS if all lookups were successful.
*/
int
main(argc, argv)
int argc;
char *argv[];
{
int excode = EX_NOINPUT; /* overall result status */
int result; /* result status of action taken */
register int optvalue;
register char *option;
register int i;
char *program; /* name of program */
char *server = NULL; /* explicit whois server */
int port = 0; /* specific tcp port */
bool keepopen = FALSE; /* keep connection open */
/*
* Check command line options.
*/
if (argc < 1 || argv[0] == NULL)
exit(EX_USAGE);
program = rindex(argv[0], '/');
if (program++ == NULL)
program = argv[0];
while (argc > 1 && argv[1] != NULL && argv[1][0] == '-')
{
for (option = &argv[1][1]; *option != '\0'; option++)
{
switch (*option)
{
case 'h':
/* name of whois server host */
if (argv[2] == NULL || argv[2][0] == '-')
fatal("Missing server name");
server = argv[2];
argc--, argv++;
break;
case 'k':
/* keep connection to server open */
keepopen = TRUE;
break;
case 'p':
/* port number of whois service */
if (argv[2] == NULL || argv[2][0] == '-')
fatal("Missing port number");
optvalue = atoi(argv[2]);
if (optvalue < 1)
fatal("Invalid port number %s", argv[2]);
if (optvalue > MAXINT16)
fatal("Maximum port number %s", itoa(MAXINT16));
port = optvalue;
argc--, argv++;
break;
case 'V':
printf("Version %s\n", version);
exit(EX_SUCCESS);
default:
fatal(Usage, program);
}
}
argc--, argv++;
}
/*
* Fetch (mandatory) remote host address(es) to look up.
*/
if (argc < 2 || argv[1] == NULL)
fatal(Usage, program);
/* process each of the command line arguments */
for (i = 1; i < argc && argv[i] != NULL; i++)
{
/* single host lookup */
result = lookup(argv[i], server, port, keepopen);
/* maintain overall result */
if (result != EX_SUCCESS || excode == EX_NOINPUT)
excode = result;
}
/* return overall result */
return(excode);
/*NOTREACHED*/
}
/*
** LOOKUP -- Perform AS lookup for given host specification
** --------------------------------------------------------
**
** Returns:
** Overall result of all address lookups.
** EX_SUCCESS if all lookups were successful.
*/
int
lookup(host, server, port, keepopen)
char *host; /* host name/address to look up */
char *server; /* explicit whois server */
int port; /* specific tcp port */
bool keepopen; /* keep server connection alive */
{
int excode = EX_NOINPUT; /* overall result status */
int result; /* result status of action taken */
struct in_addr inaddr[MAXADDRS];/* all host IP addresses */
int naddrs; /* number of host addresses */
char hostbuf[MAXDNAME+1]; /* fully qualified host name */
struct hostent *hp;
ipaddr_t addr;
register int i;
/*
* Fetch the ip address(es) of the given host.
*/
addr = inet_addr(host);
if (addr == NOT_DOTTED_QUAD)
{
hp = gethostbyname(host);
if (hp == NULL)
{
error("Unknown host: %s", host);
return(EX_NOHOST);
}
for (i = 0; i < MAXADDRS && hp->h_addr_list[i]; i++)
bcopy(hp->h_addr_list[i], (char *)&inaddr[i], INADDRSZ);
naddrs = i;
}
else
{
inaddr[0].s_addr = addr;
naddrs = 1;
hp = gethostbyaddr((char *)&inaddr[0], INADDRSZ, AF_INET);
}
/*
* Fetch its canonical name.
*/
if (hp != NULL)
{
host = strncpy(hostbuf, hp->h_name, MAXDNAME);
host[MAXDNAME] = '\0';
}
/*
* Lookup each of the addresses in turn.
*/
for (i = 0; i < naddrs; i++)
{
struct netent *np;
char *asnumber;
/* single address network name lookup */
np = getnetbyaddr(inet_netof(inaddr[i]), AF_INET);
/* single address AS-number lookup */
asnumber = as_lookup(inaddr[i], server, port, keepopen);
result = (asnumber != NULL) ? EX_SUCCESS : EX_UNAVAILABLE;
printf("%s (%s)", host, inet_ntoa(inaddr[i]));
if (np != NULL)
printf(" (%s)", np->n_name);
if (asnumber != NULL)
printf(" [%s]", asnumber);
printf("\n");
/* maintain overall result */
if (result != EX_SUCCESS || excode == EX_NOINPUT)
excode = result;
}
/* return overall result */
return(excode);
}
/*
** FATAL -- Abort program when illegal option encountered
** ------------------------------------------------------
**
** Returns:
** Aborts after issuing error message.
*/
void /*VARARGS1*/
fatal(fmt, a, b, c, d)
char *fmt; /* format of message */
char *a, *b, *c, *d; /* optional arguments */
{
(void) fprintf(stderr, fmt, a, b, c, d);
(void) fprintf(stderr, "\n");
exit(EX_USAGE);
}
/*
** ERROR -- Issue error message to error output
** --------------------------------------------
**
** Returns:
** None.
*/
void /*VARARGS1*/
error(fmt, a, b, c, d)
char *fmt; /* format of message */
char *a, *b, *c, *d; /* optional arguments */
{
(void) fprintf(stderr, fmt, a, b, c, d);
(void) fprintf(stderr, "\n");
}
/*
** ITOA -- Convert integer value to ascii string
** ---------------------------------------------
**
** Returns:
** Pointer to string.
*/
char *
itoa(n)
int n; /* value to convert */
{
static char buf[30]; /* sufficient for 64-bit values */
(void) sprintf(buf, "%d", n);
return(buf);
}
#endif /*STANDALONE*/
syntax highlighted by Code2HTML, v. 0.9.1