/* * 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 #include #include #include #include #include #include /* not always automatically included */ #include #include #include #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 ** 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*/