1 /*
2 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22 #include "varattrs.h"
23
24 #ifndef lint
25 static const char copyright[] _U_ =
26 "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
27 The Regents of the University of California. All rights reserved.\n";
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdarg.h>
34 #include <limits.h>
35 #ifdef _WIN32
36 #include "getopt.h"
37 #else
38 #include <unistd.h>
39 #endif
40 #include <errno.h>
41 #ifndef _WIN32
42 #include <signal.h>
43 #endif
44 #include <sys/types.h>
45
46 #include <pcap.h>
47
48 #include "pcap/funcattrs.h"
49
50 #ifdef _WIN32
51 #include "portability.h"
52 #endif
53
54 static char *program_name;
55
56 /* Forwards */
57 static void PCAP_NORETURN usage(void);
58 static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2);
59 static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2);
60 static char *copy_argv(char **);
61
62 static pcap_t *pd;
63
64 #ifdef _WIN32
65 static BOOL WINAPI
stop_capture(DWORD ctrltype _U_)66 stop_capture(DWORD ctrltype _U_)
67 {
68 pcap_breakloop(pd);
69 return TRUE;
70 }
71 #else
72 static void
stop_capture(int signum _U_)73 stop_capture(int signum _U_)
74 {
75 pcap_breakloop(pd);
76 }
77 #endif
78
79 static long
parse_interface_number(const char * device)80 parse_interface_number(const char *device)
81 {
82 const char *p;
83 long devnum;
84 char *end;
85
86 /*
87 * Search for a colon, terminating any scheme at the beginning
88 * of the device.
89 */
90 p = strchr(device, ':');
91 if (p != NULL) {
92 /*
93 * We found it. Is it followed by "//"?
94 */
95 p++; /* skip the : */
96 if (strncmp(p, "//", 2) == 0) {
97 /*
98 * Yes. Search for the next /, at the end of the
99 * authority part of the URL.
100 */
101 p += 2; /* skip the // */
102 p = strchr(p, '/');
103 if (p != NULL) {
104 /*
105 * OK, past the / is the path.
106 */
107 device = p + 1;
108 }
109 }
110 }
111 devnum = strtol(device, &end, 10);
112 if (device != end && *end == '\0') {
113 /*
114 * It's all-numeric, but is it a valid number?
115 */
116 if (devnum <= 0) {
117 /*
118 * No, it's not an ordinal.
119 */
120 error("Invalid adapter index");
121 }
122 return (devnum);
123 } else {
124 /*
125 * It's not all-numeric; return -1, so our caller
126 * knows that.
127 */
128 return (-1);
129 }
130 }
131
132 static char *
find_interface_by_number(long devnum)133 find_interface_by_number(long devnum)
134 {
135 pcap_if_t *dev, *devlist;
136 long i;
137 char ebuf[PCAP_ERRBUF_SIZE];
138 char *device;
139 int status;
140
141 status = pcap_findalldevs(&devlist, ebuf);
142 if (status < 0)
143 error("%s", ebuf);
144 /*
145 * Look for the devnum-th entry in the list of devices (1-based).
146 */
147 for (i = 0, dev = devlist; i < devnum-1 && dev != NULL;
148 i++, dev = dev->next)
149 ;
150 if (dev == NULL)
151 error("Invalid adapter index");
152 device = strdup(dev->name);
153 pcap_freealldevs(devlist);
154 return (device);
155 }
156
157 static pcap_t *
open_interface(const char * device,int snaplen_set,int snaplen,char * ebuf)158 open_interface(const char *device, int snaplen_set, int snaplen, char *ebuf)
159 {
160 pcap_t *pc;
161 int status;
162 char *cp;
163
164 pc = pcap_create(device, ebuf);
165 if (pc == NULL) {
166 /*
167 * If this failed with "No such device", that means
168 * the interface doesn't exist; return NULL, so that
169 * the caller can see whether the device name is
170 * actually an interface index.
171 */
172 if (strstr(ebuf, "No such device") != NULL)
173 return (NULL);
174 error("%s", ebuf);
175 }
176 if (snaplen_set) {
177 status = pcap_set_snaplen(pc, snaplen);
178 if (status != 0)
179 error("%s: pcap_set_snaplen failed: %s",
180 device, pcap_statustostr(status));
181 }
182 status = pcap_set_timeout(pc, 100);
183 if (status != 0)
184 error("%s: pcap_set_timeout failed: %s",
185 device, pcap_statustostr(status));
186 status = pcap_activate(pc);
187 if (status < 0) {
188 /*
189 * pcap_activate() failed.
190 */
191 cp = pcap_geterr(pc);
192 if (status == PCAP_ERROR)
193 error("%s", cp);
194 else if (status == PCAP_ERROR_NO_SUCH_DEVICE) {
195 /*
196 * Return an error for our caller to handle.
197 */
198 snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s\n(%s)",
199 device, pcap_statustostr(status), cp);
200 } else if (status == PCAP_ERROR_PERM_DENIED && *cp != '\0')
201 error("%s: %s\n(%s)", device,
202 pcap_statustostr(status), cp);
203 else
204 error("%s: %s", device,
205 pcap_statustostr(status));
206 pcap_close(pc);
207 return (NULL);
208 } else if (status > 0) {
209 /*
210 * pcap_activate() succeeded, but it's warning us
211 * of a problem it had.
212 */
213 cp = pcap_geterr(pc);
214 if (status == PCAP_WARNING)
215 warning("%s", cp);
216 else if (status == PCAP_WARNING_PROMISC_NOTSUP &&
217 *cp != '\0')
218 warning("%s: %s\n(%s)", device,
219 pcap_statustostr(status), cp);
220 else
221 warning("%s: %s", device,
222 pcap_statustostr(status));
223 }
224 return (pc);
225 }
226
227 #define COMMAND_OPTIONS "DLi:s:w:y:"
228
229 int
main(int argc,char ** argv)230 main(int argc, char **argv)
231 {
232 int op;
233 char *cp, *cmdbuf = NULL, *device, *end, *savefile = NULL;
234 int snaplen = 0;
235 int snaplen_set = 0;
236 pcap_if_t *devlist;
237 long devnum;
238 int show_interfaces = 0;
239 int show_dlt_types = 0;
240 int ndlts;
241 int *dlts;
242 bpf_u_int32 localnet, netmask;
243 struct bpf_program fcode;
244 char ebuf[PCAP_ERRBUF_SIZE];
245 #ifndef _WIN32
246 struct sigaction action;
247 #endif
248 int dlt;
249 const char *dlt_name = NULL;
250 int status;
251 pcap_dumper_t *pdd;
252
253 device = NULL;
254 if ((cp = strrchr(argv[0], '/')) != NULL)
255 program_name = cp + 1;
256 else
257 program_name = argv[0];
258
259 opterr = 0;
260 while ((op = getopt(argc, argv, COMMAND_OPTIONS)) != -1) {
261 switch (op) {
262
263 case 'D':
264 show_interfaces = 1;
265 break;
266
267 case 'L':
268 show_dlt_types = 1;
269 break;
270
271 case 'i':
272 device = optarg;
273 break;
274
275 case 's':
276 snaplen = (int)strtol(optarg, &end, 0);
277 if (optarg == end || *end != '\0' || snaplen < 0)
278 error("invalid snaplen %s (must be >= 0)",
279 optarg);
280 snaplen_set = 1;
281 break;
282
283 case 'w':
284 savefile = optarg;
285 break;
286
287 case 'y':
288 dlt_name = optarg;
289 break;
290
291 default:
292 usage();
293 /* NOTREACHED */
294 }
295 }
296
297 if (show_interfaces) {
298 pcap_if_t *dev;
299 int i;
300
301 if (pcap_findalldevs(&devlist, ebuf) < 0)
302 error("%s", ebuf);
303 for (i = 0, dev = devlist; dev != NULL; i++, dev = dev->next) {
304 printf("%d.%s", i+1, dev->name);
305 if (dev->description != NULL)
306 printf(" (%s)", dev->description);
307 printf("\n");
308 }
309 pcap_freealldevs(devlist);
310 return (0);
311 }
312
313 if (device == NULL) {
314 if (pcap_findalldevs(&devlist, ebuf) == -1)
315 error("%s", ebuf);
316 if (devlist == NULL)
317 error("no interfaces available for capture");
318 device = strdup(devlist->name);
319 pcap_freealldevs(devlist);
320 }
321 if (show_dlt_types) {
322 pd = pcap_create(device, ebuf);
323 if (pd == NULL)
324 error("%s", ebuf);
325 status = pcap_activate(pd);
326 if (status < 0) {
327 /*
328 * pcap_activate() failed.
329 */
330 error("%s: %s\n(%s)", device,
331 pcap_statustostr(status), pcap_geterr(pd));
332 }
333 ndlts = pcap_list_datalinks(pd, &dlts);
334 if (ndlts < 0) {
335 /*
336 * pcap_list_datalinks() failed.
337 */
338 error("%s: %s\n(%s)", device,
339 pcap_statustostr(status), pcap_geterr(pd));
340 }
341 for (int i = 0; i < ndlts; i++) {
342 dlt_name = pcap_datalink_val_to_name(dlts[i]);
343 if (dlt_name == NULL)
344 printf("DLT %d", dlts[i]);
345 else
346 printf("%s", dlt_name);
347 printf("\n");
348 }
349 pcap_free_datalinks(dlts);
350 pcap_close(pd);
351 return 0;
352 }
353
354 if (savefile == NULL)
355 error("no savefile specified");
356
357 *ebuf = '\0';
358
359 pd = open_interface(device, snaplen_set, snaplen, ebuf);
360 if (pd == NULL) {
361 /*
362 * That failed because the interface couldn't be found.
363 *
364 * If we can get a list of interfaces, and the interface name
365 * is purely numeric, try to use it as a 1-based index
366 * in the list of interfaces.
367 */
368 devnum = parse_interface_number(device);
369 if (devnum == -1) {
370 /*
371 * It's not a number; just report
372 * the open error and fail.
373 */
374 error("%s", ebuf);
375 }
376
377 /*
378 * OK, it's a number; try to find the
379 * interface with that index, and try
380 * to open it.
381 *
382 * find_interface_by_number() exits if it
383 * couldn't be found.
384 */
385 device = find_interface_by_number(devnum);
386 pd = open_interface(device, snaplen_set, snaplen, ebuf);
387 if (pd == NULL)
388 error("%s", ebuf);
389 }
390
391 if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
392 localnet = 0;
393 netmask = 0;
394 warning("%s", ebuf);
395 }
396
397 if (dlt_name != NULL) {
398 dlt = pcap_datalink_name_to_val(dlt_name);
399 if (dlt == PCAP_ERROR)
400 error("%s isn't a valid DLT name", dlt_name);
401 if (pcap_set_datalink(pd, dlt) == PCAP_ERROR)
402 error("%s: %s", device, pcap_geterr(pd));
403 }
404
405 /*
406 * Don't set a filter unless we were given one on the
407 * command line; if capturing doesn't work, or doesn't
408 * use the snapshot length, without a filter, that's
409 * a bug.
410 */
411 if (optind < argc) {
412 cmdbuf = copy_argv(&argv[optind]);
413
414 if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0)
415 error("%s", pcap_geterr(pd));
416
417 if (pcap_setfilter(pd, &fcode) < 0)
418 error("%s", pcap_geterr(pd));
419 }
420
421 pdd = pcap_dump_open(pd, savefile);
422 if (pdd == NULL)
423 error("%s", pcap_geterr(pd));
424
425 #ifdef _WIN32
426 SetConsoleCtrlHandler(stop_capture, TRUE);
427 #else
428 action.sa_handler = stop_capture;
429 sigemptyset(&action.sa_mask);
430 action.sa_flags = 0;
431 if (sigaction(SIGINT, &action, NULL) == -1)
432 error("Can't catch SIGINT: %s\n", strerror(errno));
433 #endif
434
435 printf("Listening on %s, link-type ", device);
436 dlt = pcap_datalink(pd);
437 dlt_name = pcap_datalink_val_to_name(dlt);
438 if (dlt_name == NULL)
439 printf("DLT %d", dlt);
440 else
441 printf("%s", dlt_name);
442 printf("\n");
443 for (;;) {
444 status = pcap_dispatch(pd, -1, pcap_dump, (u_char *)pdd);
445 if (status < 0)
446 break;
447 if (status != 0) {
448 printf("%d packets seen\n", status);
449 struct pcap_stat ps;
450 pcap_stats(pd, &ps);
451 printf("%d ps_recv, %d ps_drop, %d ps_ifdrop\n",
452 ps.ps_recv, ps.ps_drop, ps.ps_ifdrop);
453 }
454 }
455 if (status == -2) {
456 /*
457 * We got interrupted, so perhaps we didn't
458 * manage to finish a line we were printing.
459 * Print an extra newline, just in case.
460 */
461 putchar('\n');
462 printf("Broken out of loop from SIGINT handler\n");
463 }
464 (void)fflush(stdout);
465 if (status == -1) {
466 /*
467 * Error. Report it.
468 */
469 (void)fprintf(stderr, "%s: pcap_dispatch: %s\n",
470 program_name, pcap_geterr(pd));
471 }
472 pcap_close(pd);
473 if (cmdbuf != NULL) {
474 pcap_freecode(&fcode);
475 free(cmdbuf);
476 }
477 exit(status == -1 ? 1 : 0);
478 }
479
480 static void
usage(void)481 usage(void)
482 {
483 (void)fprintf(stderr, "Usage: %s -D -L [ -i interface ] [ -s snaplen ] [ -w file ] [ -y dlt ] [expression]\n",
484 program_name);
485 exit(1);
486 }
487
488 /* VARARGS */
489 static void
error(const char * fmt,...)490 error(const char *fmt, ...)
491 {
492 va_list ap;
493
494 (void)fprintf(stderr, "%s: ", program_name);
495 va_start(ap, fmt);
496 (void)vfprintf(stderr, fmt, ap);
497 va_end(ap);
498 if (*fmt) {
499 fmt += strlen(fmt);
500 if (fmt[-1] != '\n')
501 (void)fputc('\n', stderr);
502 }
503 exit(1);
504 /* NOTREACHED */
505 }
506
507 /* VARARGS */
508 static void
warning(const char * fmt,...)509 warning(const char *fmt, ...)
510 {
511 va_list ap;
512
513 (void)fprintf(stderr, "%s: WARNING: ", program_name);
514 va_start(ap, fmt);
515 (void)vfprintf(stderr, fmt, ap);
516 va_end(ap);
517 if (*fmt) {
518 fmt += strlen(fmt);
519 if (fmt[-1] != '\n')
520 (void)fputc('\n', stderr);
521 }
522 }
523
524 /*
525 * Copy arg vector into a new buffer, concatenating arguments with spaces.
526 */
527 static char *
copy_argv(register char ** argv)528 copy_argv(register char **argv)
529 {
530 register char **p;
531 register size_t len = 0;
532 char *buf;
533 char *src, *dst;
534
535 p = argv;
536 if (*p == 0)
537 return 0;
538
539 while (*p)
540 len += strlen(*p++) + 1;
541
542 buf = (char *)malloc(len);
543 if (buf == NULL)
544 error("copy_argv: malloc");
545
546 p = argv;
547 dst = buf;
548 while ((src = *p++) != NULL) {
549 while ((*dst++ = *src++) != '\0')
550 ;
551 dst[-1] = ' ';
552 }
553 dst[-1] = '\0';
554
555 return buf;
556 }
557