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