1 /* $OpenBSD: tcpdump.c,v 1.30 2002/11/30 13:56:23 mickey 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.30 2002/11/30 13:56:23 mickey 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 84 /* Forwards */ 85 RETSIGTYPE cleanup(int); 86 extern __dead void usage(void) __attribute__((volatile)); 87 88 /* Length of saved portion of packet. */ 89 int snaplen = DEFAULT_SNAPLEN; 90 91 struct printer { 92 pcap_handler f; 93 int type; 94 }; 95 96 /* XXX needed if using old bpf.h */ 97 #ifndef DLT_ATM_RFC1483 98 #define DLT_ATM_RFC1483 11 99 #endif 100 101 static struct printer printers[] = { 102 { ether_if_print, DLT_EN10MB }, 103 { ether_if_print, DLT_IEEE802 }, 104 { sl_if_print, DLT_SLIP }, 105 { sl_bsdos_if_print, DLT_SLIP_BSDOS }, 106 { ppp_if_print, DLT_PPP }, 107 { fddi_if_print, DLT_FDDI }, 108 { null_if_print, DLT_NULL }, 109 { raw_if_print, DLT_RAW }, 110 { atm_if_print, DLT_ATM_RFC1483 }, 111 { loop_if_print, DLT_LOOP }, 112 { enc_if_print, DLT_ENC }, 113 { pflog_if_print, DLT_PFLOG }, 114 { pfsync_if_print, DLT_PFSYNC }, 115 { NULL, 0 }, 116 }; 117 118 static pcap_handler 119 lookup_printer(int type) 120 { 121 struct printer *p; 122 123 for (p = printers; p->f; ++p) 124 if (type == p->type) 125 return p->f; 126 127 error("unknown data link type 0x%x", type); 128 /* NOTREACHED */ 129 } 130 131 static pcap_t *pd; 132 133 extern int optind; 134 extern int opterr; 135 extern char *optarg; 136 137 int 138 main(int argc, char **argv) 139 { 140 register int cnt, op, i; 141 bpf_u_int32 localnet, netmask; 142 register char *cp, *infile, *cmdbuf, *device, *RFileName, *WFileName; 143 pcap_handler printer; 144 struct bpf_program fcode; 145 RETSIGTYPE (*oldhandler)(int); 146 u_char *pcap_userdata; 147 char ebuf[PCAP_ERRBUF_SIZE]; 148 149 cnt = -1; 150 device = NULL; 151 infile = NULL; 152 RFileName = NULL; 153 WFileName = NULL; 154 if ((cp = strrchr(argv[0], '/')) != NULL) 155 program_name = cp + 1; 156 else 157 program_name = argv[0]; 158 159 if (abort_on_misalignment(ebuf, sizeof(ebuf)) < 0) 160 error("%s", ebuf); 161 162 opterr = 0; 163 while ((op = getopt(argc, argv, "ac:defF:i:lnNOpqr:s:StT:vw:xXY")) != -1) 164 switch (op) { 165 166 case 'a': 167 ++aflag; 168 break; 169 170 case 'c': 171 cnt = atoi(optarg); 172 if (cnt <= 0) 173 error("invalid packet count %s", optarg); 174 break; 175 176 case 'd': 177 ++dflag; 178 break; 179 180 case 'e': 181 ++eflag; 182 break; 183 184 case 'f': 185 ++fflag; 186 break; 187 188 case 'F': 189 infile = optarg; 190 break; 191 192 case 'i': 193 device = optarg; 194 break; 195 196 case 'l': 197 #ifdef HAVE_SETLINEBUF 198 setlinebuf(stdout); 199 #else 200 setvbuf(stdout, NULL, _IOLBF, 0); 201 #endif 202 break; 203 204 case 'n': 205 ++nflag; 206 break; 207 208 case 'N': 209 ++Nflag; 210 break; 211 212 case 'O': 213 Oflag = 0; 214 break; 215 216 case 'p': 217 ++pflag; 218 break; 219 220 case 'q': 221 ++qflag; 222 break; 223 224 case 'r': 225 RFileName = optarg; 226 break; 227 228 case 's': 229 snaplen = atoi(optarg); 230 if (snaplen <= 0) 231 error("invalid snaplen %s", optarg); 232 break; 233 234 case 'S': 235 ++Sflag; 236 break; 237 238 case 't': 239 --tflag; 240 break; 241 242 case 'T': 243 if (strcasecmp(optarg, "vat") == 0) 244 packettype = PT_VAT; 245 else if (strcasecmp(optarg, "wb") == 0) 246 packettype = PT_WB; 247 else if (strcasecmp(optarg, "rpc") == 0) 248 packettype = PT_RPC; 249 else if (strcasecmp(optarg, "rtp") == 0) 250 packettype = PT_RTP; 251 else if (strcasecmp(optarg, "rtcp") == 0) 252 packettype = PT_RTCP; 253 else if (strcasecmp(optarg, "cnfp") == 0) 254 packettype = PT_CNFP; 255 else if (strcasecmp(optarg, "sack") == 0) 256 snaplen = SACK_SNAPLEN; 257 else 258 error("unknown packet type `%s'", optarg); 259 break; 260 261 case 'v': 262 ++vflag; 263 break; 264 265 case 'w': 266 WFileName = optarg; 267 break; 268 #ifdef YYDEBUG 269 case 'Y': 270 { 271 /* Undocumented flag */ 272 extern int yydebug; 273 yydebug = 1; 274 } 275 break; 276 #endif 277 case 'x': 278 ++xflag; 279 break; 280 281 case 'X': 282 ++Xflag; 283 if (xflag == 0) ++xflag; 284 break; 285 286 default: 287 usage(); 288 /* NOTREACHED */ 289 } 290 291 if (aflag && nflag) 292 error("-a and -n options are incompatible"); 293 294 if (tflag > 0) 295 thiszone = gmt2local(0); 296 297 if (RFileName != NULL) { 298 /* 299 * We don't need network access, so set it back to the user id. 300 * Also, this prevents the user from reading anyone's 301 * trace file. 302 */ 303 seteuid(getuid()); 304 setuid(getuid()); 305 306 pd = pcap_open_offline(RFileName, ebuf); 307 if (pd == NULL) 308 error("%s", ebuf); 309 localnet = 0; 310 netmask = 0; 311 if (fflag != 0) 312 error("-f and -r options are incompatible"); 313 } else { 314 if (device == NULL) { 315 device = pcap_lookupdev(ebuf); 316 if (device == NULL) 317 error("%s", ebuf); 318 } 319 pd = pcap_open_live(device, snaplen, !pflag, 1000, ebuf); 320 if (pd == NULL) 321 error("%s", ebuf); 322 i = pcap_snapshot(pd); 323 if (snaplen < i) { 324 warning("snaplen raised from %d to %d", snaplen, i); 325 snaplen = i; 326 } 327 if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { 328 warning("%s", ebuf); 329 localnet = 0; 330 netmask = 0; 331 } 332 333 /* 334 * Let user own process after socket has been opened. 335 */ 336 seteuid(getuid()); 337 setuid(getuid()); 338 } 339 if (infile) 340 cmdbuf = read_infile(infile); 341 else 342 cmdbuf = copy_argv(&argv[optind]); 343 344 if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0) 345 error("%s", pcap_geterr(pd)); 346 if (dflag) { 347 bpf_dump(&fcode, dflag); 348 exit(0); 349 } 350 init_addrtoname(localnet, netmask); 351 352 (void)setsignal(SIGTERM, cleanup); 353 (void)setsignal(SIGINT, cleanup); 354 /* Cooperate with nohup(1) */ 355 if ((oldhandler = setsignal(SIGHUP, cleanup)) != SIG_DFL) 356 (void)setsignal(SIGHUP, oldhandler); 357 358 if (pcap_setfilter(pd, &fcode) < 0) 359 error("%s", pcap_geterr(pd)); 360 if (WFileName) { 361 pcap_dumper_t *p; 362 363 p = pcap_dump_open(pd, WFileName); 364 if (p == NULL) 365 error("%s", pcap_geterr(pd)); 366 { 367 FILE *fp = (FILE *)p; /* XXX touching pcap guts! */ 368 fflush(fp); 369 setvbuf(fp, NULL, _IONBF, 0); 370 } 371 printer = pcap_dump; 372 pcap_userdata = (u_char *)p; 373 } else { 374 printer = lookup_printer(pcap_datalink(pd)); 375 pcap_userdata = 0; 376 } 377 if (RFileName == NULL) { 378 (void)fprintf(stderr, "%s: listening on %s\n", 379 program_name, device); 380 (void)fflush(stderr); 381 } 382 if (pcap_loop(pd, cnt, printer, pcap_userdata) < 0) { 383 (void)fprintf(stderr, "%s: pcap_loop: %s\n", 384 program_name, pcap_geterr(pd)); 385 exit(1); 386 } 387 pcap_close(pd); 388 exit(0); 389 } 390 391 /* make a clean exit on interrupts */ 392 RETSIGTYPE 393 cleanup(int signo) 394 { 395 struct pcap_stat stat; 396 char buf[1024]; 397 398 /* Can't print the summary if reading from a savefile */ 399 if (pd != NULL && pcap_file(pd) == NULL) { 400 #if 0 401 (void)fflush(stdout); /* XXX unsafe */ 402 #endif 403 (void)write(STDERR_FILENO, "\n", 1); 404 if (pcap_stats(pd, &stat) < 0) { 405 (void)snprintf(buf, sizeof buf, 406 "pcap_stats: %s\n", pcap_geterr(pd)); 407 write(STDOUT_FILENO, buf, strlen(buf)); 408 } else { 409 (void)snprintf(buf, sizeof buf, 410 "%d packets received by filter\n", stat.ps_recv); 411 write(STDOUT_FILENO, buf, strlen(buf)); 412 (void)snprintf(buf, sizeof buf, 413 "%d packets dropped by kernel\n", stat.ps_drop); 414 write(STDOUT_FILENO, buf, strlen(buf)); 415 } 416 } 417 _exit(0); 418 } 419 420 /* dump the buffer in `emacs-hexl' style */ 421 void 422 default_print_hexl(const u_char *cp, unsigned int length, unsigned int offset) 423 { 424 unsigned int i, j, jm; 425 int c; 426 char ln[128], buf[128]; 427 428 printf("\n"); 429 for (i = 0; i < length; i += 0x10) { 430 snprintf(ln, sizeof(ln), " %04x: ", 431 (unsigned int)(i + offset)); 432 jm = length - i; 433 jm = jm > 16 ? 16 : jm; 434 435 for (j = 0; j < jm; j++) { 436 if ((j % 2) == 1) 437 snprintf(buf, sizeof(buf), "%02x ", 438 (unsigned int)cp[i+j]); 439 else 440 snprintf(buf, sizeof(buf), "%02x", 441 (unsigned int)cp[i+j]); 442 strlcat(ln, buf, sizeof ln); 443 } 444 for (; j < 16; j++) { 445 if ((j % 2) == 1) 446 snprintf(buf, sizeof buf, " "); 447 else 448 snprintf(buf, sizeof buf, " "); 449 strlcat(ln, buf, sizeof ln); 450 } 451 452 strlcat(ln, " ", sizeof ln); 453 for (j = 0; j < jm; j++) { 454 c = cp[i+j]; 455 c = isprint(c) ? c : '.'; 456 buf[0] = c; 457 buf[1] = '\0'; 458 strlcat(ln, buf, sizeof ln); 459 } 460 printf("%s\n", ln); 461 } 462 } 463 464 /* Like default_print() but data need not be aligned */ 465 void 466 default_print_unaligned(register const u_char *cp, register u_int length) 467 { 468 register u_int i, s; 469 register int nshorts; 470 471 if (Xflag) { 472 /* dump the buffer in `emacs-hexl' style */ 473 default_print_hexl(cp, length, 0); 474 } else { 475 /* dump the buffer in old tcpdump style */ 476 nshorts = (u_int) length / sizeof(u_short); 477 i = 0; 478 while (--nshorts >= 0) { 479 if ((i++ % 8) == 0) 480 (void)printf("\n\t\t\t"); 481 s = *cp++; 482 (void)printf(" %02x%02x", s, *cp++); 483 } 484 if (length & 1) { 485 if ((i % 8) == 0) 486 (void)printf("\n\t\t\t"); 487 (void)printf(" %02x", *cp); 488 } 489 } 490 } 491 492 void 493 default_print(register const u_char *bp, register u_int length) 494 { 495 register const u_short *sp; 496 register u_int i; 497 register int nshorts; 498 499 if (Xflag) { 500 /* dump the buffer in `emacs-hexl' style */ 501 default_print_hexl(bp, length, 0); 502 } else { 503 /* dump the buffer in old tcpdump style */ 504 if ((long)bp & 1) { 505 default_print_unaligned(bp, length); 506 return; 507 } 508 sp = (u_short *)bp; 509 nshorts = (u_int) length / sizeof(u_short); 510 i = 0; 511 while (--nshorts >= 0) { 512 if ((i++ % 8) == 0) 513 (void)printf("\n\t\t\t"); 514 (void)printf(" %04x", ntohs(*sp++)); 515 } 516 if (length & 1) { 517 if ((i % 8) == 0) 518 (void)printf("\n\t\t\t"); 519 (void)printf(" %02x", *(u_char *)sp); 520 } 521 } 522 } 523 524 __dead void 525 usage(void) 526 { 527 extern char version[]; 528 extern char pcap_version[]; 529 530 (void)fprintf(stderr, "%s version %s\n", program_name, version); 531 (void)fprintf(stderr, "libpcap version %s\n", pcap_version); 532 (void)fprintf(stderr, 533 "Usage: %s [-adeflnNOpqStvxX] [-c count] [ -F file ]\n", program_name); 534 (void)fprintf(stderr, 535 "\t\t[ -i interface ] [ -r file ] [ -s snaplen ]\n"); 536 (void)fprintf(stderr, 537 "\t\t[ -T type ] [ -w file ] [ expression ]\n"); 538 exit(1); 539 } 540