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