utils/whois3/whois3.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
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.6 2002/02/19 17:22:59 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
72 int
73 whois_query(FILE *in, FILE *out, char *query, int check_for_blank)
/* [<][>][^][v][top][bottom][index][help] */
74 {
75 char buf[1024];
76 int last_line_blank;
77 char *p;
78
79 /* remove any newline or carriage return */
80 p = strchr(query, '\r');
81 if (p != NULL) {
82 *p = '\0';
83 }
84 p = strchr(query, '\n');
85 if (p != NULL) {
86 *p = '\0';
87 }
88
89 /* send query */
90 fputs(query, out);
91 fputs("\r\n", out);
92
93 /* wait for reply to finish, printing until then */
94 last_line_blank = 0;
95 for (;;) {
96 /* read next line */
97 if (fgets(buf, sizeof(buf), in) == NULL) {
98 return 0;
99 }
100
101 /* output the line */
102 fputs(buf, stdout);
103
104 /* if entire line fit in buffer */
105 if (strchr(buf, '\n')) {
106 /* if line is empty */
107 if (!strcmp(buf, "\n")) {
108 /* if the last line was also blank, we're done */
109 if (check_for_blank && last_line_blank) {
110 return 1;
111 }
112 last_line_blank = 1;
113 }
114
115 /* non-empty line */
116 else {
117 last_line_blank = 0;
118 }
119 }
120
121 /* otherwise read until end of line */
122 else {
123 do {
124 if (fgets(buf, sizeof(buf), in) == NULL) {
125 return 0;
126 }
127 fputs(buf, stdout);
128 } while (!strchr(buf, '\n'));
129 last_line_blank = 0;
130 }
131 }
132 }
133
134
135 /* usage_error - output proper syntax and exit */
136 void
137 usage_error(const char *exename)
/* [<][>][^][v][top][bottom][index][help] */
138 {
139 fprintf(stderr,
140 "%s: [-h host | --host=host] [-p port | --port=port] -k | query\n",
141 exename);
142 fprintf(stderr, "\n");
143 fprintf(stderr,
144 "When querying a Whois server running RIPE software, you may\n");
145 fprintf(stderr,
146 "use the following flags:\n");
147 fprintf(stderr, "\n");
148 fputs(flag_txt, stderr);
149 exit(1);
150 }
151
152
153 /* main - program entry point */
154 int
155 main(int argc, char *argv[])
/* [<][>][^][v][top][bottom][index][help] */
156 {
157 /* name of executable */
158 char *exename;
159
160 /* variables used to parse arguments */
161 int p;
162 char *nptr;
163 char *endptr;
164
165 /* arguments to forward to whois server */
166 char **whois_argv;
167 int whois_argc;
168
169 /* server name and port to query */
170 char *host;
171 long port;
172
173 /* persistent mode flag */
174 int persistent_mode;
175
176 /* connection information */
177 struct servent *serv;
178 struct hostent *h;
179 struct sockaddr_in host_addr;
180 int whois_fd;
181 FILE *whois_in, *whois_out;
182
183 /* query string */
184 char *query;
185 int query_len;
186
187 /* the all-seeing i */
188 int i;
189
190
191 /* */
192 /* parse command line */
193 /* */
194
195 /* get the name of this executable */
196 if (argc > 0) {
197 exename = "whois3";
198 } else {
199 exename = argv[0];
200 }
201
202 /* set defaults for parameters */
203 host = NULL;
204 port = -1;
205 persistent_mode = 0;
206
207 /* allocate enough space for our argument list */
208 whois_argv = (char **)malloc(sizeof(char *) * (argc+1));
209 if (whois_argv == NULL) {
210 fprintf(stderr, "%s: out of memory\n", exename);
211 exit(1);
212 }
213 whois_argc = 0;
214
215 /* parse command-line arguments */
216 p = 1;
217 while (p < argc) {
218
219 /* check for short host name */
220 if (!strncmp(argv[p], "-h", 2)) {
221 /* only specify host once */
222 if (host != NULL) {
223 usage_error(exename);
224 }
225
226 /* see if the host was specified after the 'h' */
227 host = argv[p] + 2;
228
229 /* if not, then it must be the next argument */
230 if (*host == '\0') {
231 p++;
232 if (p >= argc) {
233 usage_error(exename);
234 }
235 host = argv[p];
236 }
237 p++;
238 }
239
240 /* check for long host name */
241 else if (!strncmp(argv[p], "--host=", 7)) {
242 /* only specify host once */
243 if (host != NULL) {
244 usage_error(exename);
245 }
246
247 /* grab host name */
248 host = argv[p] + 7;
249 if (*host == '\0') {
250 usage_error(exename);
251 }
252 p++;
253 }
254
255 /* check for short port name */
256 else if (!strncmp(argv[p], "-p", 2)) {
257 /* only specify port once */
258 if (port != -1) {
259 usage_error(exename);
260 }
261
262 /* see if the port was specified after the 'p' */
263 nptr = argv[p] + 2;
264 if (*nptr == '\0') {
265 p++;
266 if (p >= argc) {
267 usage_error(exename);
268 }
269 nptr = argv[p];
270 }
271
272 /* see if this is a valid port */
273 port = strtol(nptr, &endptr, 0);
274 if ((port < 0) || (port > 65535) || (*endptr != '\0')) {
275 serv = getservbyname(nptr, "tcp");
276 if (serv == NULL) {
277 fprintf(stderr,
278 "%s: port must be a number between 0 and 65535, "
279 "or the name of a service\n",
280 exename);
281 exit(1);
282 }
283 port = ntohs(serv->s_port);
284 }
285
286 p++;
287 }
288
289 /* check for long port name */
290 else if (!strncmp(argv[p], "--port=", 7)) {
291 /* only specify port once */
292 if (port != -1) {
293 usage_error(exename);
294 }
295
296 nptr = argv[p] + 7;
297
298 /* see if this is a valid port */
299 port = strtol(nptr, &endptr, 0);
300 if ((port < 0) || (port > 65535) || (*endptr != '\0')) {
301 serv = getservbyname(nptr, "tcp");
302 if (serv == NULL) {
303 fprintf(stderr,
304 "%s: port must be a number between 0 and 65535\n",
305 exename);
306 exit(1);
307 }
308 port = ntohs(serv->s_port);
309 }
310
311 p++;
312 }
313
314 /* check for stand-alone persistent flag */
315 else if (!strcmp(argv[p], "-k")) {
316 /* note we explicitly allow multiple -k options, as this doesn't
317 add any ambiguity, even if it is pointless */
318 persistent_mode = 1;
319
320 p++;
321 }
322
323 /* check for help, so we can give local usage */
324 else if (!strcmp(argv[p], "-?")) {
325 usage_error(exename);
326 }
327
328 /* other flags or arguments */
329 else {
330 /* check to see if -k was used - this will cause an error below,
331 as you can only use -k by itself */
332 if ((argv[p][0] == '-') && strchr(argv[p], 'k')) {
333 persistent_mode = 1;
334 }
335
336 /* add our argument in any case */
337 whois_argv[whois_argc++] = argv[p];
338 p++;
339 }
340 }
341
342 /* don't allow any arguments with a persistent mode */
343 if (persistent_mode) {
344 if (whois_argc > 0) {
345 fprintf(stderr,
346 "%s: do not specify arguments with -k\n",
347 exename);
348 exit(1);
349 }
350 }
351
352 /* require options otherwise */
353 else {
354 if (whois_argc <= 0) {
355 usage_error(exename);
356 }
357 }
358
359 /* */
360 /* arguments look good - connect to server */
361 /* */
362
363 /* blank out our address structure for broken (i.e. BSD) Unix variants */
364 memset(&host_addr, 0, sizeof(struct sockaddr_in));
365
366 /* get port address if not specified */
367 if (port == -1) {
368 serv = getservbyname("whois", "tcp");
369 if (serv == NULL) {
370 host_addr.sin_port = htons(DEFAULT_WHOIS_PORT);
371 } else {
372 host_addr.sin_port = serv->s_port;
373 }
374 } else {
375 host_addr.sin_port = htons(port);
376 }
377
378 /* get server address (checking if it is an IP number first) */
379 if (host == NULL) {
380 host = NICHOST;
381 }
382 host_addr.sin_addr.s_addr = inet_addr(host);
383 if (host_addr.sin_addr.s_addr == -1) {
384 h = gethostbyname(host);
385 if (h == NULL) {
386 fprintf(stderr,
387 "%s: error %d getting server address\n",
388 exename,
389 h_errno);
390 exit(1);
391 }
392 memcpy(&host_addr.sin_addr, h->h_addr, sizeof(host_addr.sin_addr));
393 }
394
395 /* fill in the rest of our socket structure */
396 host_addr.sin_family = AF_INET;
397
398 /* create a socket */
399 whois_fd = socket(AF_INET, SOCK_STREAM, 0);
400 if (whois_fd == -1) {
401 fprintf(stderr,
402 "%s: error %d creating a socket; %s\n",
403 exename,
404 errno,
405 strerror(errno));
406 exit(1);
407 }
408
409 /* connect to the server */
410 if (connect(whois_fd,
411 (struct sockaddr *)&host_addr,
412 sizeof(struct sockaddr_in)) != 0)
413 {
414 fprintf(stderr,
415 "%s: error %d connecting to server; %s\n",
416 exename,
417 errno,
418 strerror(errno));
419 exit(1);
420 }
421
422 /* bind FILE structures to our file descriptor for easy handling */
423 whois_in = fdopen(whois_fd, "r");
424 if (whois_in == NULL) {
425 fprintf(stderr,
426 "%s: error %d creating input stream; %s\n",
427 exename,
428 errno,
429 strerror(errno));
430 }
431 setbuf(whois_in, NULL);
432 whois_out = fdopen(whois_fd, "w");
433 if (whois_out == NULL) {
434 fprintf(stderr,
435 "%s: error %d creating input stream; %s\n",
436 exename,
437 errno,
438 strerror(errno));
439 }
440 setbuf(whois_out, NULL);
441
442
443 /* */
444 /* Query away */
445 /* */
446
447 /* if we had flags, we're running in "interactive" mode */
448 if (whois_argc > 0) {
449
450 /* combine our arguments into a single string */
451 query_len = 0;
452 for (i=0; i<whois_argc; i++) {
453 query_len += (1 + strlen(whois_argv[i]));
454 }
455 query = (char *)malloc(query_len+1);
456 if (query == NULL) {
457 fprintf(stderr, "%s: out of memory\n", exename);
458 exit(1);
459 }
460 strcpy(query, whois_argv[0]);
461 for (i=1; i<whois_argc; i++) {
462 strcat(query, " ");
463 strcat(query, whois_argv[i]);
464 }
465
466 /* now send our query to the server */
467 whois_query(whois_in, whois_out, query, 0);
468 }
469
470 /* otherwise we're in "batch" mode - read each query a line at a time */
471 else {
472
473 /* make a buffer to read into */
474 query_len = 8192;
475 query = (char *)malloc(query_len);
476 if (query == NULL) {
477 fprintf(stderr, "%s: out of memory\n", exename);
478 exit(1);
479 }
480
481 /* enter persistent mode */
482 fputs("-k\n", whois_out);
483
484 /* loop and query */
485 while (fgets(query, query_len, stdin) != NULL) {
486 if (strchr(query, '\n') == NULL) {
487 fprintf(stderr, "%s: query line too long\n", exename);
488 exit(1);
489 }
490 whois_query(whois_in, whois_out, query, 1);
491 }
492
493 /* exit persistent mode */
494 fputs("-k\n", whois_out);
495 }
496
497 /* everything exited fine */
498 return 0;
499 }
500
501