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.2 2001/06/06 16:31:02 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 fprintf(stderr,
292 "%s: port must be a number between 0 and 65535\n",
293 exename);
294 exit(1);
295 }
296
297 p++;
298 }
299
300 /* check for stand-alone persistent flag */
301 else if (!strcmp(argv[p], "-k")) {
302 /* note we explicitly allow multiple -k options, as this doesn't
303 add any ambiguity, even if it is pointless */
304 persistent_mode = 1;
305
306 p++;
307 }
308
309 /* other flags or arguments */
310 else {
311 /* check to see if -k was used - this will cause an error below,
312 as you can only use -k by itself */
313 if ((argv[p][0] == '-') && strchr(argv[p], 'k')) {
314 persistent_mode = 1;
315 }
316
317 /* add our argument in any case */
318 whois_argv[whois_argc++] = argv[p];
319 p++;
320 }
321 }
322
323 /* don't allow any arguments with a persistent mode */
324 if (persistent_mode) {
325 if (whois_argc > 0) {
326 fprintf(stderr,
327 "%s: do not specify arguments with -k\n",
328 exename);
329 exit(1);
330 }
331 }
332
333 /* require options otherwise */
334 else {
335 if (whois_argc <= 0) {
336 usage_error(exename);
337 }
338 }
339
340 /* */
341 /* arguments look good - connect to server */
342 /* */
343
344 /* blank out our address structure for broken (i.e. BSD) Unix variants */
345 memset(&host_addr, 0, sizeof(struct sockaddr_in));
346
347 /* get port address if not specified */
348 if (port == -1) {
349 serv = getservbyname("whois", "tcp");
350 if (serv == NULL) {
351 host_addr.sin_port = htons(DEFAULT_WHOIS_PORT);
352 } else {
353 host_addr.sin_port = serv->s_port;
354 }
355 } else {
356 host_addr.sin_port = htons(port);
357 }
358
359 /* get server address (checking if it is an IP number first) */
360 if (host == NULL) {
361 host = NICHOST;
362 }
363 host_addr.sin_addr.s_addr = inet_addr(host);
364 if (host_addr.sin_addr.s_addr == -1) {
365 h = gethostbyname(host);
366 if (h == NULL) {
367 fprintf(stderr,
368 "%s: error %d getting server address\n",
369 exename,
370 h_errno);
371 exit(1);
372 }
373 memcpy(&host_addr.sin_addr, h->h_addr, sizeof(host_addr.sin_addr));
374 }
375
376 /* fill in the rest of our socket structure */
377 host_addr.sin_family = AF_INET;
378
379 /* create a socket */
380 whois_fd = socket(AF_INET, SOCK_STREAM, 0);
381 if (whois_fd == -1) {
382 fprintf(stderr,
383 "%s: error %d creating a socket; %s\n",
384 exename,
385 errno,
386 strerror(errno));
387 exit(1);
388 }
389
390 /* connect to the server */
391 if (connect(whois_fd,
392 (struct sockaddr *)&host_addr,
393 sizeof(struct sockaddr_in)) != 0)
394 {
395 fprintf(stderr,
396 "%s: error %d connecting to server; %s\n",
397 exename,
398 errno,
399 strerror(errno));
400 exit(1);
401 }
402
403 /* bind FILE structures to our file descriptor for easy handling */
404 whois_in = fdopen(whois_fd, "r");
405 if (whois_in == NULL) {
406 fprintf(stderr,
407 "%s: error %d creating input stream; %s\n",
408 exename,
409 errno,
410 strerror(errno));
411 }
412 setbuf(whois_in, NULL);
413 whois_out = fdopen(whois_fd, "w");
414 if (whois_out == NULL) {
415 fprintf(stderr,
416 "%s: error %d creating input stream; %s\n",
417 exename,
418 errno,
419 strerror(errno));
420 }
421 setbuf(whois_out, NULL);
422
423
424 /* */
425 /* Query away */
426 /* */
427
428 /* if we had flags, we're running in "interactive" mode */
429 if (whois_argc > 0) {
430
431 /* combine our arguments into a single string */
432 query_len = 0;
433 for (i=0; i<whois_argc; i++) {
434 query_len += (1 + strlen(whois_argv[i]));
435 }
436 query = (char *)malloc(query_len+1);
437 if (query == NULL) {
438 fprintf(stderr, "%s: out of memory\n", exename);
439 exit(1);
440 }
441 strcpy(query, whois_argv[0]);
442 for (i=1; i<whois_argc; i++) {
443 strcat(query, " ");
444 strcat(query, whois_argv[i]);
445 }
446
447 /* now send our query to the server */
448 whois_query(whois_in, whois_out, query);
449 }
450
451 /* otherwise we're in "batch" mode - read each query a line at a time */
452 else {
453
454 /* make a buffer to read into */
455 query_len = 8192;
456 query = (char *)malloc(query_len);
457 if (query == NULL) {
458 fprintf(stderr, "%s: out of memory\n", exename);
459 exit(1);
460 }
461
462 /* enter persistent mode */
463 fputs("-k\n", whois_out);
464
465 /* loop and query */
466 while (fgets(query, query_len, stdin) != NULL) {
467 if (strchr(query, '\n') == NULL) {
468 fprintf(stderr, "%s: query line too long\n", exename);
469 exit(1);
470 }
471 whois_query(whois_in, whois_out, query);
472 }
473
474 /* exit persistent mode */
475 fputs("-k\n", whois_out);
476 }
477
478 /* everything exited fine */
479 return 0;
480 }
481
482