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