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