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