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 static const 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 const char rcsid[] = 27 "@(#) $Header: /home/cvs/src/usr.sbin/tcpdump/tcpdump.c,v 1.11 1998/09/22 22:03:02 provos 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_if_print, DLT_LOOP }, 102 { enc_if_print, DLT_ENC }, 103 { null_if_print, DLT_LOOP }, 104 { NULL, 0 }, 105 }; 106 107 static pcap_handler 108 lookup_printer(int type) 109 { 110 struct printer *p; 111 112 for (p = printers; p->f; ++p) 113 if (type == p->type) 114 return p->f; 115 116 error("unknown data link type 0x%x", type); 117 /* NOTREACHED */ 118 } 119 120 static pcap_t *pd; 121 122 extern int optind; 123 extern int opterr; 124 extern char *optarg; 125 126 int 127 main(int argc, char **argv) 128 { 129 register int cnt, op, i; 130 bpf_u_int32 localnet, netmask; 131 register char *cp, *infile, *cmdbuf, *device, *RFileName, *WFileName; 132 pcap_handler printer; 133 struct bpf_program fcode; 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 ((op = getopt(argc, argv, "c:defF:i:lnNOpqr:s:StT:vw:xY")) != -1) 152 switch (op) { 153 case 'c': 154 cnt = atoi(optarg); 155 if (cnt <= 0) 156 error("invalid packet count %s", optarg); 157 break; 158 159 case 'd': 160 ++dflag; 161 break; 162 163 case 'e': 164 ++eflag; 165 break; 166 167 case 'f': 168 ++fflag; 169 break; 170 171 case 'F': 172 infile = optarg; 173 break; 174 175 case 'i': 176 device = optarg; 177 break; 178 179 case 'l': 180 #ifdef HAVE_SETLINEBUF 181 setlinebuf(stdout); 182 #else 183 setvbuf(stdout, NULL, _IOLBF, 0); 184 #endif 185 break; 186 187 case 'n': 188 ++nflag; 189 break; 190 191 case 'N': 192 ++Nflag; 193 break; 194 195 case 'O': 196 Oflag = 0; 197 break; 198 199 case 'p': 200 ++pflag; 201 break; 202 203 case 'q': 204 ++qflag; 205 break; 206 207 case 'r': 208 RFileName = optarg; 209 break; 210 211 case 's': 212 snaplen = atoi(optarg); 213 if (snaplen <= 0) 214 error("invalid snaplen %s", optarg); 215 break; 216 217 case 'S': 218 ++Sflag; 219 break; 220 221 case 't': 222 --tflag; 223 break; 224 225 case 'T': 226 if (strcasecmp(optarg, "vat") == 0) 227 packettype = PT_VAT; 228 else if (strcasecmp(optarg, "wb") == 0) 229 packettype = PT_WB; 230 else if (strcasecmp(optarg, "rpc") == 0) 231 packettype = PT_RPC; 232 else if (strcasecmp(optarg, "rtp") == 0) 233 packettype = PT_RTP; 234 else if (strcasecmp(optarg, "rtcp") == 0) 235 packettype = PT_RTCP; 236 else if (strcasecmp(optarg, "cnfp") == 0) 237 packettype = PT_CNFP; 238 else if (strcasecmp(optarg, "sack") == 0) 239 snaplen = SACK_SNAPLEN; 240 else 241 error("unknown packet type `%s'", optarg); 242 break; 243 244 case 'v': 245 ++vflag; 246 break; 247 248 case 'w': 249 WFileName = optarg; 250 break; 251 #ifdef YYDEBUG 252 case 'Y': 253 { 254 /* Undocumented flag */ 255 extern int yydebug; 256 yydebug = 1; 257 } 258 break; 259 #endif 260 case 'x': 261 ++xflag; 262 break; 263 264 default: 265 usage(); 266 /* NOTREACHED */ 267 } 268 269 if (tflag > 0) 270 thiszone = gmt2local(); 271 272 if (RFileName != NULL) { 273 /* 274 * We don't need network access, so set it back to the user id. 275 * Also, this prevents the user from reading anyone's 276 * trace file. 277 */ 278 setuid(getuid()); 279 280 pd = pcap_open_offline(RFileName, ebuf); 281 if (pd == NULL) 282 error("%s", ebuf); 283 localnet = 0; 284 netmask = 0; 285 if (fflag != 0) 286 error("-f and -r options are incompatible"); 287 } else { 288 if (device == NULL) { 289 device = pcap_lookupdev(ebuf); 290 if (device == NULL) 291 error("%s", ebuf); 292 } 293 pd = pcap_open_live(device, snaplen, !pflag, 1000, ebuf); 294 if (pd == NULL) 295 error("%s", ebuf); 296 i = pcap_snapshot(pd); 297 if (snaplen < i) { 298 warning("snaplen raised from %d to %d", snaplen, i); 299 snaplen = i; 300 } 301 if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) 302 error("%s", ebuf); 303 /* 304 * Let user own process after socket has been opened. 305 */ 306 setuid(getuid()); 307 } 308 if (infile) 309 cmdbuf = read_infile(infile); 310 else 311 cmdbuf = copy_argv(&argv[optind]); 312 313 if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0) 314 error("%s", pcap_geterr(pd)); 315 if (dflag) { 316 bpf_dump(&fcode, dflag); 317 exit(0); 318 } 319 init_addrtoname(fflag, localnet, netmask); 320 321 (void)signal(SIGTERM, cleanup); 322 (void)signal(SIGINT, cleanup); 323 (void)signal(SIGHUP, cleanup); 324 325 if (pcap_setfilter(pd, &fcode) < 0) 326 error("%s", pcap_geterr(pd)); 327 if (WFileName) { 328 pcap_dumper_t *p = pcap_dump_open(pd, WFileName); 329 if (p == NULL) 330 error("%s", pcap_geterr(pd)); 331 printer = pcap_dump; 332 pcap_userdata = (u_char *)p; 333 } else { 334 printer = lookup_printer(pcap_datalink(pd)); 335 pcap_userdata = 0; 336 } 337 if (RFileName == NULL) { 338 (void)fprintf(stderr, "%s: listening on %s\n", 339 program_name, device); 340 (void)fflush(stderr); 341 } 342 if (pcap_loop(pd, cnt, printer, pcap_userdata) < 0) { 343 (void)fprintf(stderr, "%s: pcap_loop: %s\n", 344 program_name, pcap_geterr(pd)); 345 exit(1); 346 } 347 pcap_close(pd); 348 exit(0); 349 } 350 351 /* make a clean exit on interrupts */ 352 RETSIGTYPE 353 cleanup(int signo) 354 { 355 struct pcap_stat stat; 356 357 /* Can't print the summary if reading from a savefile */ 358 if (pd != NULL && pcap_file(pd) == NULL) { 359 (void)fflush(stdout); 360 putc('\n', stderr); 361 if (pcap_stats(pd, &stat) < 0) 362 (void)fprintf(stderr, "pcap_stats: %s\n", 363 pcap_geterr(pd)); 364 else { 365 (void)fprintf(stderr, "%d packets received by filter\n", 366 stat.ps_recv); 367 (void)fprintf(stderr, "%d packets dropped by kernel\n", 368 stat.ps_drop); 369 } 370 } 371 exit(0); 372 } 373 374 /* Like default_print() but data need not be aligned */ 375 void 376 default_print_unaligned(register const u_char *cp, register u_int length) 377 { 378 register u_int i, s; 379 register int nshorts; 380 381 nshorts = (u_int) length / sizeof(u_short); 382 i = 0; 383 while (--nshorts >= 0) { 384 if ((i++ % 8) == 0) 385 (void)printf("\n\t\t\t"); 386 s = *cp++; 387 (void)printf(" %02x%02x", s, *cp++); 388 } 389 if (length & 1) { 390 if ((i % 8) == 0) 391 (void)printf("\n\t\t\t"); 392 (void)printf(" %02x", *cp); 393 } 394 } 395 396 void 397 default_print(register const u_char *bp, register u_int length) 398 { 399 register const u_short *sp; 400 register u_int i; 401 register int nshorts; 402 403 if ((long)bp & 1) { 404 default_print_unaligned(bp, length); 405 return; 406 } 407 sp = (u_short *)bp; 408 nshorts = (u_int) length / sizeof(u_short); 409 i = 0; 410 while (--nshorts >= 0) { 411 if ((i++ % 8) == 0) 412 (void)printf("\n\t\t\t"); 413 (void)printf(" %04x", ntohs(*sp++)); 414 } 415 if (length & 1) { 416 if ((i % 8) == 0) 417 (void)printf("\n\t\t\t"); 418 (void)printf(" %02x", *(u_char *)sp); 419 } 420 } 421 422 __dead void 423 usage(void) 424 { 425 extern char version[]; 426 427 (void)fprintf(stderr, "Version %s\n", version); 428 (void)fprintf(stderr, 429 "Usage: tcpdump [-deflnNOpqStvx] [-c count] [ -F file ]\n"); 430 (void)fprintf(stderr, 431 "\t\t[ -i interface ] [ -r file ] [ -s snaplen ]\n"); 432 (void)fprintf(stderr, 433 "\t\t[ -T type ] [ -w file ] [ expression ]\n"); 434 exit(-1); 435 } 436