/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following functions.
- whois_query
- usage_error
- 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