1 /* $OpenBSD: tcpdump.c,v 1.22 2001/06/25 23:05:17 provos 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.22 2001/06/25 23:05:17 provos 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 = pcap_dump_open(pd, WFileName); 361 if (p == NULL) 362 error("%s", pcap_geterr(pd)); 363 printer = pcap_dump; 364 pcap_userdata = (u_char *)p; 365 } else { 366 printer = lookup_printer(pcap_datalink(pd)); 367 pcap_userdata = 0; 368 } 369 if (RFileName == NULL) { 370 (void)fprintf(stderr, "%s: listening on %s\n", 371 program_name, device); 372 (void)fflush(stderr); 373 } 374 if (pcap_loop(pd, cnt, printer, pcap_userdata) < 0) { 375 (void)fprintf(stderr, "%s: pcap_loop: %s\n", 376 program_name, pcap_geterr(pd)); 377 exit(1); 378 } 379 pcap_close(pd); 380 exit(0); 381 } 382 383 /* make a clean exit on interrupts */ 384 RETSIGTYPE 385 cleanup(int signo) 386 { 387 struct pcap_stat stat; 388 389 /* Can't print the summary if reading from a savefile */ 390 if (pd != NULL && pcap_file(pd) == NULL) { 391 /* XXX unsafe */ 392 (void)fflush(stdout); 393 putc('\n', stderr); 394 if (pcap_stats(pd, &stat) < 0) 395 (void)fprintf(stderr, "pcap_stats: %s\n", 396 pcap_geterr(pd)); 397 else { 398 (void)fprintf(stderr, "%d packets received by filter\n", 399 stat.ps_recv); 400 (void)fprintf(stderr, "%d packets dropped by kernel\n", 401 stat.ps_drop); 402 } 403 } 404 exit(0); 405 } 406 407 /* dump the buffer in `emacs-hexl' style */ 408 void 409 default_print_hexl(const u_char *cp, unsigned int length, unsigned int offset) 410 { 411 unsigned int i, j, jm; 412 int c; 413 char ln[128]; 414 415 printf("\n"); 416 for (i = 0; i < length; i += 0x10) { 417 snprintf(ln, 418 sizeof(ln), 419 " %04x: ", (unsigned int)(i + offset)); 420 jm = length - i; 421 jm = jm > 16 ? 16 : jm; 422 423 for (j = 0; j < jm; j++) { 424 if ((j % 2) == 1) 425 snprintf(ln + strlen(ln), 426 sizeof(ln) - strlen(ln), 427 "%02x ", (unsigned int)cp[i+j]); 428 else 429 snprintf(ln + strlen(ln), 430 sizeof(ln) - strlen(ln), 431 "%02x", (unsigned int)cp[i+j]); 432 } 433 for (; j < 16; j++) { 434 if ((j % 2) == 1) 435 snprintf(ln + strlen(ln), 436 sizeof(ln) - strlen(ln), 437 " "); 438 else 439 snprintf(ln + strlen(ln), 440 sizeof(ln) - strlen(ln), 441 " "); 442 } 443 444 snprintf(ln + strlen(ln), sizeof(ln) - strlen(ln), " "); 445 for (j = 0; j < jm; j++) { 446 c = cp[i+j]; 447 c = isprint(c) ? c : '.'; 448 snprintf(ln + strlen(ln), 449 sizeof(ln) - strlen(ln), 450 "%c", c); 451 } 452 printf("%s\n", ln); 453 } 454 } 455 456 /* Like default_print() but data need not be aligned */ 457 void 458 default_print_unaligned(register const u_char *cp, register u_int length) 459 { 460 register u_int i, s; 461 register int nshorts; 462 463 if (Xflag) { 464 /* dump the buffer in `emacs-hexl' style */ 465 default_print_hexl(cp, length, 0); 466 } else { 467 /* dump the buffer in old tcpdump style */ 468 nshorts = (u_int) length / sizeof(u_short); 469 i = 0; 470 while (--nshorts >= 0) { 471 if ((i++ % 8) == 0) 472 (void)printf("\n\t\t\t"); 473 s = *cp++; 474 (void)printf(" %02x%02x", s, *cp++); 475 } 476 if (length & 1) { 477 if ((i % 8) == 0) 478 (void)printf("\n\t\t\t"); 479 (void)printf(" %02x", *cp); 480 } 481 } 482 } 483 484 void 485 default_print(register const u_char *bp, register u_int length) 486 { 487 register const u_short *sp; 488 register u_int i; 489 register int nshorts; 490 491 if (Xflag) { 492 /* dump the buffer in `emacs-hexl' style */ 493 default_print_hexl(bp, length, 0); 494 } else { 495 /* dump the buffer in old tcpdump style */ 496 if ((long)bp & 1) { 497 default_print_unaligned(bp, length); 498 return; 499 } 500 sp = (u_short *)bp; 501 nshorts = (u_int) length / sizeof(u_short); 502 i = 0; 503 while (--nshorts >= 0) { 504 if ((i++ % 8) == 0) 505 (void)printf("\n\t\t\t"); 506 (void)printf(" %04x", ntohs(*sp++)); 507 } 508 if (length & 1) { 509 if ((i % 8) == 0) 510 (void)printf("\n\t\t\t"); 511 (void)printf(" %02x", *(u_char *)sp); 512 } 513 } 514 } 515 516 __dead void 517 usage(void) 518 { 519 extern char version[]; 520 extern char pcap_version[]; 521 522 (void)fprintf(stderr, "%s version %s\n", program_name, version); 523 (void)fprintf(stderr, "libpcap version %s\n", pcap_version); 524 (void)fprintf(stderr, 525 "Usage: %s [-adeflnNOpqStvxX] [-c count] [ -F file ]\n", program_name); 526 (void)fprintf(stderr, 527 "\t\t[ -i interface ] [ -r file ] [ -s snaplen ]\n"); 528 (void)fprintf(stderr, 529 "\t\t[ -T type ] [ -w file ] [ expression ]\n"); 530 exit(1); 531 } 532