1 /* $OpenBSD: tcpdump.c,v 1.32 2003/07/17 08:45:37 markus Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that: (1) source code distributions 9 * retain the above copyright notice and this paragraph in its entirety, (2) 10 * distributions including binary code include the above copyright notice and 11 * this paragraph in its entirety in the documentation or other materials 12 * provided with the distribution, and (3) all advertising materials mentioning 13 * features or use of this software display the following acknowledgement: 14 * ``This product includes software developed by the University of California, 15 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 16 * the University nor the names of its contributors may be used to endorse 17 * or promote products derived from this software without specific prior 18 * written permission. 19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 20 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 22 */ 23 24 #ifndef lint 25 static const char copyright[] = 26 "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997\n\ 27 The Regents of the University of California. All rights reserved.\n"; 28 static const char rcsid[] = 29 "@(#) $Header: /home/cvs/src/usr.sbin/tcpdump/tcpdump.c,v 1.32 2003/07/17 08:45:37 markus Exp $ (LBL)"; 30 #endif 31 32 /* 33 * tcpdump - monitor tcp/ip traffic on an ethernet. 34 * 35 * First written in 1987 by Van Jacobson, Lawrence Berkeley Laboratory. 36 * Mercilessly hacked and occasionally improved since then via the 37 * combined efforts of Van, Steve McCanne and Craig Leres of LBL. 38 */ 39 40 #include <sys/types.h> 41 #include <sys/time.h> 42 43 #include <netinet/in.h> 44 45 #include <pcap.h> 46 #include <signal.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <unistd.h> 51 #include <ctype.h> 52 53 #include "interface.h" 54 #include "addrtoname.h" 55 #include "machdep.h" 56 #include "setsignal.h" 57 #include "gmt2local.h" 58 59 int aflag; /* translate network and broadcast addresses */ 60 int dflag; /* print filter code */ 61 int eflag; /* print ethernet header */ 62 int fflag; /* don't translate "foreign" IP address */ 63 int nflag; /* leave addresses as numbers */ 64 int Nflag; /* remove domains from printed host names */ 65 int Oflag = 1; /* run filter code optimizer */ 66 int pflag; /* don't go promiscuous */ 67 int qflag; /* quick (shorter) output */ 68 int Sflag; /* print raw TCP sequence numbers */ 69 int tflag = 1; /* print packet arrival time */ 70 int vflag; /* verbose */ 71 int xflag; /* print packet in hex */ 72 int Xflag; /* print packet in emacs-hexl style */ 73 74 int packettype; 75 76 77 char *program_name; 78 79 int32_t thiszone; /* seconds offset from gmt to local time */ 80 81 /* Externs */ 82 extern void bpf_dump(struct bpf_program *, int); 83 extern int esp_init(char *); 84 85 /* Forwards */ 86 RETSIGTYPE cleanup(int); 87 extern __dead void usage(void) __attribute__((volatile)); 88 89 /* Length of saved portion of packet. */ 90 int snaplen = DEFAULT_SNAPLEN; 91 92 struct printer { 93 pcap_handler f; 94 int type; 95 }; 96 97 /* XXX needed if using old bpf.h */ 98 #ifndef DLT_ATM_RFC1483 99 #define DLT_ATM_RFC1483 11 100 #endif 101 102 static struct printer printers[] = { 103 { ether_if_print, DLT_EN10MB }, 104 { ether_if_print, DLT_IEEE802 }, 105 { sl_if_print, DLT_SLIP }, 106 { sl_bsdos_if_print, DLT_SLIP_BSDOS }, 107 { ppp_if_print, DLT_PPP }, 108 { fddi_if_print, DLT_FDDI }, 109 { null_if_print, DLT_NULL }, 110 { raw_if_print, DLT_RAW }, 111 { atm_if_print, DLT_ATM_RFC1483 }, 112 { loop_if_print, DLT_LOOP }, 113 { enc_if_print, DLT_ENC }, 114 { pflog_if_print, DLT_PFLOG }, 115 { pflog_old_if_print, DLT_OLD_PFLOG }, 116 { pfsync_if_print, DLT_PFSYNC }, 117 { NULL, 0 }, 118 }; 119 120 static pcap_handler 121 lookup_printer(int type) 122 { 123 struct printer *p; 124 125 for (p = printers; p->f; ++p) 126 if (type == p->type) 127 return p->f; 128 129 error("unknown data link type 0x%x", type); 130 /* NOTREACHED */ 131 } 132 133 static pcap_t *pd; 134 135 extern int optind; 136 extern int opterr; 137 extern char *optarg; 138 139 int 140 main(int argc, char **argv) 141 { 142 register int cnt, op, i; 143 bpf_u_int32 localnet, netmask; 144 register char *cp, *infile, *cmdbuf, *device, *RFileName, *WFileName; 145 pcap_handler printer; 146 struct bpf_program fcode; 147 RETSIGTYPE (*oldhandler)(int); 148 u_char *pcap_userdata; 149 char ebuf[PCAP_ERRBUF_SIZE]; 150 151 cnt = -1; 152 device = NULL; 153 infile = NULL; 154 RFileName = NULL; 155 WFileName = NULL; 156 if ((cp = strrchr(argv[0], '/')) != NULL) 157 program_name = cp + 1; 158 else 159 program_name = argv[0]; 160 161 if (abort_on_misalignment(ebuf, sizeof(ebuf)) < 0) 162 error("%s", ebuf); 163 164 opterr = 0; 165 while ((op = getopt(argc, argv, "ac:deE:fF:i:lnNOpqr:s:StT:vw:xXY")) != -1) 166 switch (op) { 167 168 case 'a': 169 ++aflag; 170 break; 171 172 case 'c': 173 cnt = atoi(optarg); 174 if (cnt <= 0) 175 error("invalid packet count %s", optarg); 176 break; 177 178 case 'd': 179 ++dflag; 180 break; 181 182 case 'e': 183 ++eflag; 184 break; 185 186 case 'f': 187 ++fflag; 188 break; 189 190 case 'F': 191 infile = optarg; 192 break; 193 194 case 'i': 195 device = optarg; 196 break; 197 198 case 'l': 199 #ifdef HAVE_SETLINEBUF 200 setlinebuf(stdout); 201 #else 202 setvbuf(stdout, NULL, _IOLBF, 0); 203 #endif 204 break; 205 206 case 'n': 207 ++nflag; 208 break; 209 210 case 'N': 211 ++Nflag; 212 break; 213 214 case 'O': 215 Oflag = 0; 216 break; 217 218 case 'p': 219 ++pflag; 220 break; 221 222 case 'q': 223 ++qflag; 224 break; 225 226 case 'r': 227 RFileName = optarg; 228 break; 229 230 case 's': 231 snaplen = atoi(optarg); 232 if (snaplen <= 0) 233 error("invalid snaplen %s", optarg); 234 break; 235 236 case 'S': 237 ++Sflag; 238 break; 239 240 case 't': 241 --tflag; 242 break; 243 244 case 'T': 245 if (strcasecmp(optarg, "vat") == 0) 246 packettype = PT_VAT; 247 else if (strcasecmp(optarg, "wb") == 0) 248 packettype = PT_WB; 249 else if (strcasecmp(optarg, "rpc") == 0) 250 packettype = PT_RPC; 251 else if (strcasecmp(optarg, "rtp") == 0) 252 packettype = PT_RTP; 253 else if (strcasecmp(optarg, "rtcp") == 0) 254 packettype = PT_RTCP; 255 else if (strcasecmp(optarg, "cnfp") == 0) 256 packettype = PT_CNFP; 257 else if (strcasecmp(optarg, "sack") == 0) 258 snaplen = SACK_SNAPLEN; 259 else 260 error("unknown packet type `%s'", optarg); 261 break; 262 263 case 'v': 264 ++vflag; 265 break; 266 267 case 'w': 268 WFileName = optarg; 269 break; 270 #ifdef YYDEBUG 271 case 'Y': 272 { 273 /* Undocumented flag */ 274 extern int yydebug; 275 yydebug = 1; 276 } 277 break; 278 #endif 279 case 'x': 280 ++xflag; 281 break; 282 283 case 'X': 284 ++Xflag; 285 if (xflag == 0) ++xflag; 286 break; 287 288 case 'E': 289 if (esp_init(optarg) < 0) 290 error("bad esp specification `%s'", optarg); 291 break; 292 293 default: 294 usage(); 295 /* NOTREACHED */ 296 } 297 298 if (aflag && nflag) 299 error("-a and -n options are incompatible"); 300 301 if (tflag > 0) 302 thiszone = gmt2local(0); 303 304 if (RFileName != NULL) { 305 /* 306 * We don't need network access, so set it back to the user id. 307 * Also, this prevents the user from reading anyone's 308 * trace file. 309 */ 310 seteuid(getuid()); 311 setuid(getuid()); 312 313 pd = pcap_open_offline(RFileName, ebuf); 314 if (pd == NULL) 315 error("%s", ebuf); 316 localnet = 0; 317 netmask = 0; 318 if (fflag != 0) 319 error("-f and -r options are incompatible"); 320 } else { 321 if (device == NULL) { 322 device = pcap_lookupdev(ebuf); 323 if (device == NULL) 324 error("%s", ebuf); 325 } 326 pd = pcap_open_live(device, snaplen, !pflag, 1000, ebuf); 327 if (pd == NULL) 328 error("%s", ebuf); 329 i = pcap_snapshot(pd); 330 if (snaplen < i) { 331 warning("snaplen raised from %d to %d", snaplen, i); 332 snaplen = i; 333 } 334 if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { 335 warning("%s", ebuf); 336 localnet = 0; 337 netmask = 0; 338 } 339 340 /* 341 * Let user own process after socket has been opened. 342 */ 343 seteuid(getuid()); 344 setuid(getuid()); 345 } 346 if (infile) 347 cmdbuf = read_infile(infile); 348 else 349 cmdbuf = copy_argv(&argv[optind]); 350 351 if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0) 352 error("%s", pcap_geterr(pd)); 353 if (dflag) { 354 bpf_dump(&fcode, dflag); 355 exit(0); 356 } 357 init_addrtoname(localnet, netmask); 358 359 (void)setsignal(SIGTERM, cleanup); 360 (void)setsignal(SIGINT, cleanup); 361 /* Cooperate with nohup(1) */ 362 if ((oldhandler = setsignal(SIGHUP, cleanup)) != SIG_DFL) 363 (void)setsignal(SIGHUP, oldhandler); 364 365 if (pcap_setfilter(pd, &fcode) < 0) 366 error("%s", pcap_geterr(pd)); 367 if (WFileName) { 368 pcap_dumper_t *p; 369 370 p = pcap_dump_open(pd, WFileName); 371 if (p == NULL) 372 error("%s", pcap_geterr(pd)); 373 { 374 FILE *fp = (FILE *)p; /* XXX touching pcap guts! */ 375 fflush(fp); 376 setvbuf(fp, NULL, _IONBF, 0); 377 } 378 printer = pcap_dump; 379 pcap_userdata = (u_char *)p; 380 } else { 381 printer = lookup_printer(pcap_datalink(pd)); 382 pcap_userdata = 0; 383 } 384 if (RFileName == NULL) { 385 (void)fprintf(stderr, "%s: listening on %s\n", 386 program_name, device); 387 (void)fflush(stderr); 388 } 389 if (pcap_loop(pd, cnt, printer, pcap_userdata) < 0) { 390 (void)fprintf(stderr, "%s: pcap_loop: %s\n", 391 program_name, pcap_geterr(pd)); 392 exit(1); 393 } 394 pcap_close(pd); 395 exit(0); 396 } 397 398 /* make a clean exit on interrupts */ 399 RETSIGTYPE 400 cleanup(int signo) 401 { 402 struct pcap_stat stat; 403 char buf[1024]; 404 405 /* Can't print the summary if reading from a savefile */ 406 if (pd != NULL && pcap_file(pd) == NULL) { 407 #if 0 408 (void)fflush(stdout); /* XXX unsafe */ 409 #endif 410 (void)write(STDERR_FILENO, "\n", 1); 411 if (pcap_stats(pd, &stat) < 0) { 412 (void)snprintf(buf, sizeof buf, 413 "pcap_stats: %s\n", pcap_geterr(pd)); 414 write(STDOUT_FILENO, buf, strlen(buf)); 415 } else { 416 (void)snprintf(buf, sizeof buf, 417 "%d packets received by filter\n", stat.ps_recv); 418 write(STDOUT_FILENO, buf, strlen(buf)); 419 (void)snprintf(buf, sizeof buf, 420 "%d packets dropped by kernel\n", stat.ps_drop); 421 write(STDOUT_FILENO, buf, strlen(buf)); 422 } 423 } 424 _exit(0); 425 } 426 427 /* dump the buffer in `emacs-hexl' style */ 428 void 429 default_print_hexl(const u_char *cp, unsigned int length, unsigned int offset) 430 { 431 unsigned int i, j, jm; 432 int c; 433 char ln[128], buf[128]; 434 435 printf("\n"); 436 for (i = 0; i < length; i += 0x10) { 437 snprintf(ln, sizeof(ln), " %04x: ", 438 (unsigned int)(i + offset)); 439 jm = length - i; 440 jm = jm > 16 ? 16 : jm; 441 442 for (j = 0; j < jm; j++) { 443 if ((j % 2) == 1) 444 snprintf(buf, sizeof(buf), "%02x ", 445 (unsigned int)cp[i+j]); 446 else 447 snprintf(buf, sizeof(buf), "%02x", 448 (unsigned int)cp[i+j]); 449 strlcat(ln, buf, sizeof ln); 450 } 451 for (; j < 16; j++) { 452 if ((j % 2) == 1) 453 snprintf(buf, sizeof buf, " "); 454 else 455 snprintf(buf, sizeof buf, " "); 456 strlcat(ln, buf, sizeof ln); 457 } 458 459 strlcat(ln, " ", sizeof ln); 460 for (j = 0; j < jm; j++) { 461 c = cp[i+j]; 462 c = isprint(c) ? c : '.'; 463 buf[0] = c; 464 buf[1] = '\0'; 465 strlcat(ln, buf, sizeof ln); 466 } 467 printf("%s\n", ln); 468 } 469 } 470 471 /* Like default_print() but data need not be aligned */ 472 void 473 default_print_unaligned(register const u_char *cp, register u_int length) 474 { 475 register u_int i, s; 476 register int nshorts; 477 478 if (Xflag) { 479 /* dump the buffer in `emacs-hexl' style */ 480 default_print_hexl(cp, length, 0); 481 } else { 482 /* dump the buffer in old tcpdump style */ 483 nshorts = (u_int) length / sizeof(u_short); 484 i = 0; 485 while (--nshorts >= 0) { 486 if ((i++ % 8) == 0) 487 (void)printf("\n\t\t\t"); 488 s = *cp++; 489 (void)printf(" %02x%02x", s, *cp++); 490 } 491 if (length & 1) { 492 if ((i % 8) == 0) 493 (void)printf("\n\t\t\t"); 494 (void)printf(" %02x", *cp); 495 } 496 } 497 } 498 499 void 500 default_print(register const u_char *bp, register u_int length) 501 { 502 register const u_short *sp; 503 register u_int i; 504 register int nshorts; 505 506 if (Xflag) { 507 /* dump the buffer in `emacs-hexl' style */ 508 default_print_hexl(bp, length, 0); 509 } else { 510 /* dump the buffer in old tcpdump style */ 511 if ((long)bp & 1) { 512 default_print_unaligned(bp, length); 513 return; 514 } 515 sp = (u_short *)bp; 516 nshorts = (u_int) length / sizeof(u_short); 517 i = 0; 518 while (--nshorts >= 0) { 519 if ((i++ % 8) == 0) 520 (void)printf("\n\t\t\t"); 521 (void)printf(" %04x", ntohs(*sp++)); 522 } 523 if (length & 1) { 524 if ((i % 8) == 0) 525 (void)printf("\n\t\t\t"); 526 (void)printf(" %02x", *(u_char *)sp); 527 } 528 } 529 } 530 531 __dead void 532 usage(void) 533 { 534 extern char version[]; 535 extern char pcap_version[]; 536 537 (void)fprintf(stderr, "%s version %s\n", program_name, version); 538 (void)fprintf(stderr, "libpcap version %s\n", pcap_version); 539 (void)fprintf(stderr, 540 "Usage: %s [-adeflnNOpqStvxX] [-c count] [-F file] [-i interface] [-r file]\n", 541 program_name); 542 (void)fprintf(stderr, 543 "\t\t[-s snaplen] [-T type] [-w file] [-E [espalg:]espkey]\n"); 544 (void)fprintf(stderr, 545 "\t\t[expression]\n"); 546 exit(1); 547 } 548