tcpdump.c revision 17680
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 23char copyright[] = 24 "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996\n\ 25The Regents of the University of California. All rights reserved.\n"; 26static 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 54int fflag; /* don't translate "foreign" IP address */ 55int nflag; /* leave addresses as numbers */ 56int Nflag; /* remove domains from printed host names */ 57int pflag; /* don't go promiscuous */ 58int qflag; /* quick (shorter) output */ 59int tflag = 1; /* print packet arrival time */ 60int eflag; /* print ethernet header */ 61int vflag; /* verbose */ 62int xflag; /* print packet in hex */ 63int Oflag = 1; /* run filter code optimizer */ 64int Sflag; /* print raw TCP sequence numbers */ 65int packettype; 66 67int dflag; /* print filter code */ 68 69char *program_name; 70 71int32_t thiszone; /* seconds offset from gmt to local time */ 72 73/* Externs */ 74extern void bpf_dump(struct bpf_program *, int); 75 76/* Forwards */ 77RETSIGTYPE cleanup(int); 78extern __dead void usage(void) __attribute__((volatile)); 79 80/* Length of saved portion of packet. */ 81int snaplen = DEFAULT_SNAPLEN; 82 83struct 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 93static 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 104static pcap_handler 105lookup_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 117static pcap_t *pd; 118 119extern int optind; 120extern int opterr; 121extern char *optarg; 122 123int 124main(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 */ 345RETSIGTYPE 346cleanup(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 */ 368void 369default_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 389void 390default_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 416usage() 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