]> The Tcpdump Group git mirrors - tcpdump/blob - tcpdump.c
patches to help build on Linux 2.2
[tcpdump] / tcpdump.c
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.130 1999-10-17 21:37:17 mcr 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
56 int aflag; /* translate network and broadcast addresses */
57 int dflag; /* print filter code */
58 int eflag; /* print ethernet header */
59 int fflag; /* don't translate "foreign" IP address */
60 int nflag; /* leave addresses as numbers */
61 int Nflag; /* remove domains from printed host names */
62 int Oflag = 1; /* run filter code optimizer */
63 int pflag; /* don't go promiscuous */
64 int qflag; /* quick (shorter) output */
65 int Sflag; /* print raw TCP sequence numbers */
66 int tflag = 1; /* print packet arrival time */
67 int vflag; /* verbose */
68 int xflag; /* print packet in hex */
69
70 int packettype;
71
72
73 char *program_name;
74
75 int32_t thiszone; /* seconds offset from gmt to local time */
76
77 /* Externs */
78 extern void bpf_dump(struct bpf_program *, int);
79
80 /* Forwards */
81 RETSIGTYPE cleanup(int);
82 extern __dead void usage(void) __attribute__((volatile));
83
84 /* Length of saved portion of packet. */
85 int snaplen = DEFAULT_SNAPLEN;
86
87 struct printer {
88 pcap_handler f;
89 int type;
90 };
91
92 static 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
106 static pcap_handler
107 lookup_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
119 static pcap_t *pd;
120
121 extern int optind;
122 extern int opterr;
123 extern char *optarg;
124
125 int
126 main(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 if (strcasecmp(optarg, "snmp") == 0)
243 packettype = PT_SNMP;
244 else
245 error("unknown packet type `%s'", optarg);
246 break;
247
248 case 'v':
249 ++vflag;
250 break;
251
252 case 'w':
253 WFileName = optarg;
254 break;
255 #ifdef YYDEBUG
256 case 'Y':
257 {
258 /* Undocumented flag */
259 extern int yydebug;
260 yydebug = 1;
261 }
262 break;
263 #endif
264 case 'x':
265 ++xflag;
266 break;
267
268 default:
269 usage();
270 /* NOTREACHED */
271 }
272
273 if (aflag && nflag)
274 error("-a and -n options are incompatible");
275
276 if (tflag > 0)
277 thiszone = gmt2local(0);
278
279 if (RFileName != NULL) {
280 /*
281 * We don't need network access, so set it back to the user id.
282 * Also, this prevents the user from reading anyone's
283 * trace file.
284 */
285 setuid(getuid());
286
287 pd = pcap_open_offline(RFileName, ebuf);
288 if (pd == NULL)
289 error("%s", ebuf);
290 localnet = 0;
291 netmask = 0;
292 if (fflag != 0)
293 error("-f and -r options are incompatible");
294 } else {
295 if (device == NULL) {
296 device = pcap_lookupdev(ebuf);
297 if (device == NULL)
298 error("%s", ebuf);
299 }
300 pd = pcap_open_live(device, snaplen, !pflag, 1000, ebuf);
301 if (pd == NULL)
302 error("%s", ebuf);
303 i = pcap_snapshot(pd);
304 if (snaplen < i) {
305 warning("snaplen raised from %d to %d", snaplen, i);
306 snaplen = i;
307 }
308 if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
309 localnet = 0;
310 netmask = 0;
311 warning("%s", ebuf);
312 }
313 /*
314 * Let user own process after socket has been opened.
315 */
316 setuid(getuid());
317 }
318 if (infile)
319 cmdbuf = read_infile(infile);
320 else
321 cmdbuf = copy_argv(&argv[optind]);
322
323 if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
324 error("%s", pcap_geterr(pd));
325 if (dflag) {
326 bpf_dump(&fcode, dflag);
327 exit(0);
328 }
329 init_addrtoname(localnet, netmask);
330
331 (void)setsignal(SIGTERM, cleanup);
332 (void)setsignal(SIGINT, cleanup);
333 /* Cooperate with nohup(1) */
334 if ((oldhandler = setsignal(SIGHUP, cleanup)) != SIG_DFL)
335 (void)setsignal(SIGHUP, oldhandler);
336
337 if (pcap_setfilter(pd, &fcode) < 0)
338 error("%s", pcap_geterr(pd));
339 if (WFileName) {
340 pcap_dumper_t *p = pcap_dump_open(pd, WFileName);
341 if (p == NULL)
342 error("%s", pcap_geterr(pd));
343 printer = pcap_dump;
344 pcap_userdata = (u_char *)p;
345 } else {
346 printer = lookup_printer(pcap_datalink(pd));
347 pcap_userdata = 0;
348 }
349 if (RFileName == NULL) {
350 (void)fprintf(stderr, "%s: listening on %s\n",
351 program_name, device);
352 (void)fflush(stderr);
353 }
354 if (pcap_loop(pd, cnt, printer, pcap_userdata) < 0) {
355 (void)fprintf(stderr, "%s: pcap_loop: %s\n",
356 program_name, pcap_geterr(pd));
357 exit(1);
358 }
359 pcap_close(pd);
360 exit(0);
361 }
362
363 /* make a clean exit on interrupts */
364 RETSIGTYPE
365 cleanup(int signo)
366 {
367 struct pcap_stat stat;
368
369 /* Can't print the summary if reading from a savefile */
370 if (pd != NULL && pcap_file(pd) == NULL) {
371 (void)fflush(stdout);
372 putc('\n', stderr);
373 if (pcap_stats(pd, &stat) < 0)
374 (void)fprintf(stderr, "pcap_stats: %s\n",
375 pcap_geterr(pd));
376 else {
377 (void)fprintf(stderr, "%d packets received by filter\n",
378 stat.ps_recv);
379 (void)fprintf(stderr, "%d packets dropped by kernel\n",
380 stat.ps_drop);
381 }
382 }
383 exit(0);
384 }
385
386 /* Like default_print() but data need not be aligned */
387 void
388 default_print_unaligned(register const u_char *cp, register u_int length)
389 {
390 register u_int i, s;
391 register int nshorts;
392
393 nshorts = (u_int) length / sizeof(u_short);
394 i = 0;
395 while (--nshorts >= 0) {
396 if ((i++ % 8) == 0)
397 (void)printf("\n\t\t\t");
398 s = *cp++;
399 (void)printf(" %02x%02x", s, *cp++);
400 }
401 if (length & 1) {
402 if ((i % 8) == 0)
403 (void)printf("\n\t\t\t");
404 (void)printf(" %02x", *cp);
405 }
406 }
407
408 /*
409 * By default, print the packet out in hex.
410 *
411 * (BTW, please don't send us patches to print the packet out in ascii)
412 */
413 void
414 default_print(register const u_char *bp, register u_int length)
415 {
416 register const u_short *sp;
417 register u_int i;
418 register int nshorts;
419
420 if ((long)bp & 1) {
421 default_print_unaligned(bp, length);
422 return;
423 }
424 sp = (u_short *)bp;
425 nshorts = (u_int) length / sizeof(u_short);
426 i = 0;
427 while (--nshorts >= 0) {
428 if ((i++ % 8) == 0)
429 (void)printf("\n\t\t\t");
430 (void)printf(" %04x", ntohs(*sp++));
431 }
432 if (length & 1) {
433 if ((i % 8) == 0)
434 (void)printf("\n\t\t\t");
435 (void)printf(" %02x", *(u_char *)sp);
436 }
437 }
438
439 __dead void
440 usage(void)
441 {
442 extern char version[];
443 extern char pcap_version[];
444
445 (void)fprintf(stderr, "%s version %s\n", program_name, version);
446 (void)fprintf(stderr, "libpcap version %s\n", pcap_version);
447 (void)fprintf(stderr,
448 "Usage: %s [-adeflnNOpqStvx] [-c count] [ -F file ]\n", program_name);
449 (void)fprintf(stderr,
450 "\t\t[ -i interface ] [ -r file ] [ -s snaplen ]\n");
451 (void)fprintf(stderr,
452 "\t\t[ -T type ] [ -w file ] [ expression ]\n");
453 exit(-1);
454 }