tcpdump.c revision 39297
1132718Skan/*
2132718Skan * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
3169689Skan *	The Regents of the University of California.  All rights reserved.
4132718Skan *
5132718Skan * Redistribution and use in source and binary forms, with or without
6132718Skan * modification, are permitted provided that: (1) source code distributions
7132718Skan * retain the above copyright notice and this paragraph in its entirety, (2)
8132718Skan * distributions including binary code include the above copyright notice and
9132718Skan * this paragraph in its entirety in the documentation or other materials
10132718Skan * provided with the distribution, and (3) all advertising materials mentioning
11132718Skan * features or use of this software display the following acknowledgement:
12132718Skan * ``This product includes software developed by the University of California,
13132718Skan * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14132718Skan * the University nor the names of its contributors may be used to endorse
15132718Skan * or promote products derived from this software without specific prior
16132718Skan * written permission.
17132718Skan * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18132718Skan * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19169689Skan * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20169689Skan */
21132718Skan
22132718Skan#ifndef lint
23132718Skanstatic const char copyright[] =
24169689Skan    "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997\n\
25169689SkanThe Regents of the University of California.  All rights reserved.\n";
26static 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
56int aflag;			/* translate network and broadcast addresses */
57int dflag;			/* print filter code */
58int eflag;			/* print ethernet header */
59int fflag;			/* don't translate "foreign" IP address */
60int nflag;			/* leave addresses as numbers */
61int Nflag;			/* remove domains from printed host names */
62int Oflag = 1;			/* run filter code optimizer */
63int pflag;			/* don't go promiscuous */
64int qflag;			/* quick (shorter) output */
65int Sflag;			/* print raw TCP sequence numbers */
66int tflag = 1;			/* print packet arrival time */
67int vflag;			/* verbose */
68int xflag;			/* print packet in hex */
69
70int packettype;
71
72
73char *program_name;
74
75int32_t thiszone;		/* seconds offset from gmt to local time */
76
77/* Externs */
78extern void bpf_dump(struct bpf_program *, int);
79
80/* Forwards */
81RETSIGTYPE cleanup(int);
82extern __dead void usage(void) __attribute__((volatile));
83
84/* Length of saved portion of packet. */
85int snaplen = DEFAULT_SNAPLEN;
86
87struct printer {
88	pcap_handler f;
89	int type;
90};
91
92static struct printer printers[] = {
93	{ ether_if_print,	DLT_EN10MB },
94	{ ether_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
106static pcap_handler
107lookup_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
119static pcap_t *pd;
120
121extern int optind;
122extern int opterr;
123extern char *optarg;
124
125int
126main(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 */
362RETSIGTYPE
363cleanup(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 */
385void
386default_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 */
411void
412default_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
438usage(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