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 66 stop_capture(DWORD ctrltype _U_) 67 { 68 pcap_breakloop(pd); 69 return TRUE; 70 } 71 #else 72 static void 73 stop_capture(int signum _U_) 74 { 75 pcap_breakloop(pd); 76 } 77 #endif 78 79 static long 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 * 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 * 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 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 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 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 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 * 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