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