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