## utils/whois3/whois3.c

/* [<][>][^][v][top][bottom][index][help] */

## DEFINITIONS

This source file includes following functions.

1. whois_query
2. usage_error
3. main

       1 /*
       2 Copyright (c) 2001,2002                 RIPE NCC
       3
       4
       5 All Rights Reserved
       6
       7 Permission to use, copy, modify, and distribute this software and its
       8 documentation for any purpose and without fee is hereby granted,
       9 provided that the above copyright notice appear in all copies and that
      10 both that copyright notice and this permission notice appear in
      11 supporting documentation, and that the name of the author not be
      12 used in advertising or publicity pertaining to distribution of the
      13 software without specific, written prior permission.
      14
      15 THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
      16 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
      17 AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
      18 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
      19 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      20 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      21 */
      22
      23 /* $Id: whois3.c,v 1.9 2002/07/02 15:56:34 shane Exp $ */
      24
      25 #include <string.h>
      26 #include <stdlib.h>
      27 #include <stdio.h>
      28 #include <limits.h>
      29 #include <netdb.h>
      30 #include <errno.h>
      31 #include <netdb.h>
      32 #include <sys/types.h>
      33 #include <sys/socket.h>
      34 #include <netinet/in.h>
      35 #include <unistd.h>
      36
      37
      38 /* help text is defined in this file as flag_txt[] */
      39 #include "flags.h"
      40
      41 /*
      42  * CONSTANTS
      43  */
      44
      45 /* default name to query - can be set at runtime via the "-h" option */
      46 #define NICHOST "whois.ripe.net"
      47
      48 /* default port - only used if there is no entry for "whois" in the
      49    /etc/services file and no "-p" option is specified */
      50 #define DEFAULT_WHOIS_PORT 43
      51
      52
      53
      54 /*
      55  * FUNCTIONS
      56  */
      57
      58
      59 /*
      60   whois_query
      61
      62   Writes the query string in "query" to the "out" descriptor, and reads
      63   the result in the "in" descriptor.  The "out" buffer may have either no
      64   buffering or line buffering, but must NOT have full buffering.
      65
      66   The routine then outputs each line the server returns, until the server
      67   ends the connection.  If the "check_for_blank" variable is set to
      68   non-zero, then the routine will also return when two consecutive blank
      69   lines appear in the server response.
      70
      71   If an error occurs sending or reading the query, -1 is returned.
      72  */
      73
      74 int
      75 whois_query(FILE *in, FILE *out, const char *query, int check_for_blank)
         /* [<][>][^][v][top][bottom][index][help] */
      76 {
      77     char buf[1024];
      78     int last_line_blank;
      79     char *p;
      80     char *query_copy;
      81
      82     /* manipulate a copy of the query */
      83     query_copy = (char *)malloc(strlen(query) + 3);
      84     strcpy(query_copy, query);
      85
      86     /* remove any newline or carriage return */
      87     p = strchr(query_copy, '\r');
      88     if (p != NULL) {
      89         *p = '\0';
      90     }
      91     p = strchr(query_copy, '\n');
      92     if (p != NULL) {
      93         *p = '\0';
      94     }
      95
      96     /* add CR+LF */
      97     strcat(query_copy, "\r\n");
      98
      99     /* send query */
     100     if (fputs(query_copy, out) == EOF) {
     101         return -1;
     102     }
     103
     104     /* wait for reply to finish, printing until then */
     105     last_line_blank = 0;
     106     for (;;) {
     107         /* read next line */
     108         if (fgets(buf, sizeof(buf), in) == NULL) {
     109             return -1;
     110         }
     111
     112         /* output the line */
     113         fputs(buf, stdout);
     114
     115         /* if entire line fit in buffer */
     116         if (strchr(buf, '\n')) {
     117             /* if line is empty */
     118             if (!strcmp(buf, "\n")) {
     119                 /* if the last line was also blank, we're done */
     120                 if (check_for_blank && last_line_blank) {
     121                     return 1;
     122                 }
     123                 last_line_blank = 1;
     124             }
     125
     126             /* non-empty line */
     127             else {
     128                 last_line_blank = 0;
     129             }
     130         }
     131
     132         /* otherwise read until end of line */
     133         else {
     134             do {
     135                 if (fgets(buf, sizeof(buf), in) == NULL) {
     136                     return 0;
     137                 }
     138                 fputs(buf, stdout);
     139             } while (!strchr(buf, '\n'));
     140             last_line_blank = 0;
     141         }
     142     }
     143 }
     144
     145
     146 /* usage_error - output proper syntax and exit */
     147 void
     148 usage_error(const char *exename)
         /* [<][>][^][v][top][bottom][index][help] */
     149 {
     150     fprintf(stderr,
     151             "%s: [-h host | --host=host] [-p port | --port=port] -k | query\n",
     152             exename);
     153     fprintf(stderr, "\n");
     154     fprintf(stderr,
     155             "When querying a Whois server running RIPE software, you may\n");
     156     fprintf(stderr,
     157             "use the following flags:\n");
     158     fprintf(stderr, "\n");
     159     fputs(flag_txt, stderr);
     160     exit(1);
     161 }
     162
     163
     164 /* main - program entry point */
     165 int
     166 main(int argc, char *argv[])
         /* [<][>][^][v][top][bottom][index][help] */
     167 {
     168     /* name of executable */
     169     char *exename;
     170
     171     /* variables used to parse arguments */
     172     int p;
     173     char *nptr;
     174     char *endptr;
     175
     176     /* arguments to forward to whois server */
     177     char **whois_argv;
     178     int whois_argc;
     179
     180     /* server name and port to query */
     181     char *host;
     182     long port;
     183
     184     /* persistent mode flag and line buffer */
     185     int persistent_mode;
     186     char linebuf[BUFSIZ];
     187
     188     /* connection information */
     189     struct servent *serv;
     190     struct hostent *h;
     191     struct sockaddr_in host_addr;
     192     int whois_fd;
     193     FILE *whois_in, *whois_out;
     194     char whois_in_linebuf[BUFSIZ];
     195
     196     /* query string */
     197     char *query;
     198     int query_len;
     199
     200     /* the all-seeing i */
     201     int i;
     202
     203
     204     /* */
     205     /* parse command line */
     206     /* */
     207
     208     /* get the name of this executable */
     209     if (argc > 0) {
     210         exename = "whois3";
     211     } else {
     212         exename = argv[0];
     213     }
     214
     215     /* set defaults for parameters */
     216     host = NULL;
     217     port = -1;
     218     persistent_mode = 0;
     219
     220     /* allocate enough space for our argument list */
     221     whois_argv = (char **)malloc(sizeof(char *) * (argc+1));
     222     if (whois_argv == NULL) {
     223         fprintf(stderr, "%s: out of memory\n", exename);
     224         exit(1);
     225     }
     226     whois_argc = 0;
     227
     228     /* parse command-line arguments */
     229     p = 1;
     230     while (p < argc) {
     231
     232         /* check for short host name */
     233         if (!strncmp(argv[p], "-h", 2)) {
     234             /* only specify host once */
     235             if (host != NULL) {
     236                 usage_error(exename);
     237             }
     238
     239             /* see if the host was specified after the 'h' */
     240             host = argv[p] + 2;
     241
     242             /* if not, then it must be the next argument */
     243             if (*host == '\0') {
     244                 p++;
     245                 if (p >= argc) {
     246                     usage_error(exename);
     247                 }
     248                 host = argv[p];
     249             }
     250             p++;
     251         }
     252
     253         /* check for long host name */
     254         else if (!strncmp(argv[p], "--host=", 7)) {
     255             /* only specify host once */
     256             if (host != NULL) {
     257                 usage_error(exename);
     258             }
     259
     260             /* grab host name */
     261             host = argv[p] + 7;
     262             if (*host == '\0') {
     263                 usage_error(exename);
     264             }
     265             p++;
     266         }
     267
     268         /* check for short port name */
     269         else if (!strncmp(argv[p], "-p", 2)) {
     270             /* only specify port once */
     271             if (port != -1) {
     272                 usage_error(exename);
     273             }
     274
     275             /* see if the port was specified after the 'p' */
     276             nptr = argv[p] + 2;
     277             if (*nptr == '\0') {
     278                 p++;
     279                 if (p >= argc) {
     280                     usage_error(exename);
     281                 }
     282                 nptr = argv[p];
     283             }
     284
     285             /* see if this is a valid port */
     286             port = strtol(nptr, &endptr, 0);
     287             if ((port < 0) || (port > 65535) || (*endptr != '\0')) {
     288                 serv = getservbyname(nptr, "tcp");
     289                 if (serv == NULL) {
     290                     fprintf(stderr,
     291                             "%s: port must be a number between 0 and 65535, "
     292                             "or the name of a service\n",
     293                             exename);
     294                     exit(1);
     295                 }
     296                 port = ntohs(serv->s_port);
     297             }
     298
     299             p++;
     300         }
     301
     302         /* check for long port name */
     303         else if (!strncmp(argv[p], "--port=", 7)) {
     304             /* only specify port once */
     305             if (port != -1) {
     306                 usage_error(exename);
     307             }
     308
     309             nptr = argv[p] + 7;
     310
     311             /* see if this is a valid port */
     312             port = strtol(nptr, &endptr, 0);
     313             if ((port < 0) || (port > 65535) || (*endptr != '\0')) {
     314                 serv = getservbyname(nptr, "tcp");
     315                 if (serv == NULL) {
     316                     fprintf(stderr,
     317                             "%s: port must be a number between 0 and 65535\n",
     318                             exename);
     319                     exit(1);
     320                 }
     321                 port = ntohs(serv->s_port);
     322             }
     323
     324             p++;
     325         }
     326
     327         /* check for stand-alone persistent flag */
     328         else if (!strcmp(argv[p], "-k")) {
     329             /* note we explicitly allow multiple -k options, as this doesn't
     330                add any ambiguity, even if it is pointless */
     331             persistent_mode = 1;
     332
     333             p++;
     334         }
     335
     336         /* check for help, so we can give local usage */
     337         else if (!strcmp(argv[p], "-?")) {
     338             usage_error(exename);
     339         }
     340
     341         /* other flags or arguments */
     342         else {
     343             /* add our argument in any case */
     344             whois_argv[whois_argc++] = argv[p];
     345             p++;
     346         }
     347     }
     348
     349     /* don't allow any arguments with a persistent mode */
     350     if (persistent_mode) {
     351         if (whois_argc > 0) {
     352             fprintf(stderr,
     353                     "%s: do not specify arguments with -k\n",
     354                     exename);
     355             exit(1);
     356         }
     357         /* set to line buffering if we are in persistent mode,
     358            to allow programs to pipe the result without block buffering */
     359         setvbuf(stdout, linebuf, _IOLBF, BUFSIZ);
     360     }
     361
     362     /* require options otherwise */
     363     else {
     364         if (whois_argc <= 0) {
     365             usage_error(exename);
     366         }
     367     }
     368
     369     /* */
     370     /* arguments look good - connect to server */
     371     /* */
     372
     373     /* blank out our address structure for broken (i.e. BSD) Unix variants */
     374     memset(&host_addr, 0, sizeof(struct sockaddr_in));
     375
     376     /* get port address if not specified */
     377     if (port == -1) {
     378         serv = getservbyname("whois", "tcp");
     379         if (serv == NULL) {
     380             host_addr.sin_port = htons(DEFAULT_WHOIS_PORT);
     381         } else {
     382             host_addr.sin_port = serv->s_port;
     383         }
     384     } else {
     385         host_addr.sin_port = htons(port);
     386     }
     387
     388     /* get server address (checking if it is an IP number first) */
     389     if (host == NULL) {
     390         host = NICHOST;
     391     }
     392     host_addr.sin_addr.s_addr = inet_addr(host);
     393     if (host_addr.sin_addr.s_addr == -1) {
     394         h = gethostbyname(host);
     395         if (h == NULL) {
     396             fprintf(stderr,
     397                     "%s: error %d getting server address\n",
     398                     exename,
     399                     h_errno);
     400             exit(1);
     401         }
     402         memcpy(&host_addr.sin_addr, h->h_addr, sizeof(host_addr.sin_addr));
     403     }
     404
     405     /* fill in the rest of our socket structure */
     406     host_addr.sin_family = AF_INET;
     407
     408     /* create a socket */
     409     whois_fd = socket(AF_INET, SOCK_STREAM, 0);
     410     if (whois_fd == -1) {
     411         fprintf(stderr,
     412                 "%s: error %d creating a socket; %s\n",
     413                 exename,
     414                 errno,
     415                 strerror(errno));
     416         exit(1);
     417     }
     418
     419     /* connect to the server */
     420     if (connect(whois_fd,
     421                 (struct sockaddr *)&host_addr,
     422                 sizeof(struct sockaddr_in)) != 0)
     423     {
     424         fprintf(stderr,
     425                 "%s: error %d connecting to server; %s\n",
     426                 exename,
     427                 errno,
     428                 strerror(errno));
     429         exit(1);
     430     }
     431
     432     /* bind FILE structures to our file descriptor for easy handling */
     433     whois_in = fdopen(whois_fd, "r");
     434     if (whois_in == NULL) {
     435         fprintf(stderr,
     436                 "%s: error %d creating input stream; %s\n",
     437                 exename,
     438                 errno,
     439                 strerror(errno));
     440     }
     441     setvbuf(whois_in, whois_in_linebuf, _IOLBF, sizeof(whois_in_linebuf));
     442     whois_out = fdopen(whois_fd, "w");
     443     if (whois_out == NULL) {
     444         fprintf(stderr,
     445                 "%s: error %d creating input stream; %s\n",
     446                 exename,
     447                 errno,
     448                 strerror(errno));
     449     }
     450     setbuf(whois_out, NULL);
     451
     452
     453     /* */
     454     /* Query away */
     455     /* */
     456
     457     /* if we had flags, we're running in "interactive" mode */
     458     if (whois_argc > 0) {
     459
     460         /* combine our arguments into a single string */
     461         query_len = 0;
     462         for (i=0; i<whois_argc; i++) {
     463             query_len += (1 + strlen(whois_argv[i]));
     464         }
     465         query = (char *)malloc(query_len+1);
     466         if (query == NULL) {
     467             fprintf(stderr, "%s: out of memory\n", exename);
     468             exit(1);
     469         }
     470         strcpy(query, whois_argv[0]);
     471         for (i=1; i<whois_argc; i++) {
     472             strcat(query, " ");
     473             strcat(query, whois_argv[i]);
     474         }
     475
     476         /* now send our query to the server */
     477         whois_query(whois_in, whois_out, query, 0);
     478     }
     479
     480     /* otherwise we're in "batch" mode - read each query a line at a time */
     481     else {
     482
     483         /* make a buffer to read into */
     484         query_len = 8192;
     485         query = (char *)malloc(query_len);
     486         if (query == NULL) {
     487             fprintf(stderr, "%s: out of memory\n", exename);
     488             exit(1);
     489         }
     490
     491         /* enter persistent mode */
     492         if (whois_query(whois_in, whois_out, "-k", 1) == -1) {
     493             fprintf(stderr, "%s: unable to send query\n", exename);
     494             exit(1);
     495         }
     496
     497         /* loop and query */
     498         while (fgets(query, query_len, stdin) != NULL) {
     499             if (strchr(query, '\n') == NULL) {
     500                 fprintf(stderr, "%s: query line too long\n", exename);
     501                 exit(1);
     502             }
     503             if (whois_query(whois_in, whois_out, query, 1) == -1) {
     504                 fprintf(stderr, "%s: unable to send query\n", exename);
     505                 exit(1);
     506             }
     507         }
     508
     509         /* exit persistent mode */
     510         fputs("-k\n", whois_out);
     511     }
     512
     513     /* everything exited fine */
     514     return 0;
     515 }
     516
     517

/* [<][>][^][v][top][bottom][index][help] */