]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcpdump/tcpdump.c
Catch up with "base" telnet.
[FreeBSD/FreeBSD.git] / contrib / tcpdump / tcpdump.c
1 /*
2  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
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  * Support for splitting captures into multiple files with a maximum
22  * file size:
23  *
24  * Copyright (c) 2001
25  *      Seth Webster <swebster@sst.ll.mit.edu>
26  */
27
28 #ifndef lint
29 static const char copyright[] =
30     "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
31 The Regents of the University of California.  All rights reserved.\n";
32 static const char rcsid[] =
33     "@(#) $Header: /tcpdump/master/tcpdump/tcpdump.c,v 1.173 2001/12/22 22:12:23 guy Exp $ (LBL)";
34 #endif
35
36 /* $FreeBSD$ */
37
38 /*
39  * tcpdump - monitor tcp/ip traffic on an ethernet.
40  *
41  * First written in 1987 by Van Jacobson, Lawrence Berkeley Laboratory.
42  * Mercilessly hacked and occasionally improved since then via the
43  * combined efforts of Van, Steve McCanne and Craig Leres of LBL.
44  */
45
46 #ifdef HAVE_CONFIG_H
47 #include "config.h"
48 #endif
49
50 #include <sys/types.h>
51 #include <sys/time.h>
52
53 #include <netinet/in.h>
54
55 #include <pcap.h>
56 #include <signal.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <unistd.h>
61 #include <ctype.h>
62
63
64 #include "interface.h"
65 #include "addrtoname.h"
66 #include "machdep.h"
67 #include "setsignal.h"
68 #include "gmt2local.h"
69
70 int aflag;                      /* translate network and broadcast addresses */
71 int dflag;                      /* print filter code */
72 int eflag;                      /* print ethernet header */
73 int fflag;                      /* don't translate "foreign" IP address */
74 int nflag;                      /* leave addresses as numbers */
75 int Nflag;                      /* remove domains from printed host names */
76 int Oflag = 1;                  /* run filter code optimizer */
77 int pflag;                      /* don't go promiscuous */
78 int qflag;                      /* quick (shorter) output */
79 int Rflag = 1;                  /* print sequence # field in AH/ESP*/
80 int sflag = 0;                  /* use the libsmi to translate OIDs */
81 int Sflag;                      /* print raw TCP sequence numbers */
82 int tflag = 1;                  /* print packet arrival time */
83 int uflag = 0;                  /* Print undecoded NFS handles */
84 int vflag;                      /* verbose */
85 int xflag;                      /* print packet in hex */
86 int Xflag;                      /* print packet in ascii as well as hex */
87 off_t Cflag = 0;                /* rotate dump files after this many bytes */
88
89 char *espsecret = NULL;         /* ESP secret key */
90
91 int packettype;
92
93 int infodelay;
94 int infoprint;
95
96 char *program_name;
97
98 int32_t thiszone;               /* seconds offset from gmt to local time */
99
100 /* Forwards */
101 static RETSIGTYPE cleanup(int);
102 static void usage(void) __attribute__((noreturn));
103
104 static void dump_and_trunc(u_char *, const struct pcap_pkthdr *, const u_char *);
105
106 #ifdef SIGINFO
107 RETSIGTYPE requestinfo(int);
108 #endif
109
110 /* Length of saved portion of packet. */
111 int snaplen = DEFAULT_SNAPLEN;
112
113 struct printer {
114         pcap_handler f;
115         int type;
116 };
117
118 static struct printer printers[] = {
119         { arcnet_if_print,      DLT_ARCNET },
120         { ether_if_print,       DLT_EN10MB },
121         { token_if_print,       DLT_IEEE802 },
122 #ifdef DLT_LANE8023
123         { lane_if_print,        DLT_LANE8023 },
124 #endif
125 #ifdef DLT_CIP
126         { cip_if_print,         DLT_CIP },
127 #endif
128 #ifdef DLT_ATM_CLIP
129         { cip_if_print,         DLT_ATM_CLIP },
130 #endif
131         { sl_if_print,          DLT_SLIP },
132         { sl_bsdos_if_print,    DLT_SLIP_BSDOS },
133         { ppp_if_print,         DLT_PPP },
134         { ppp_bsdos_if_print,   DLT_PPP_BSDOS },
135         { fddi_if_print,        DLT_FDDI },
136         { null_if_print,        DLT_NULL },
137 #ifdef DLT_LOOP
138         { null_if_print,        DLT_LOOP },
139 #endif
140         { raw_if_print,         DLT_RAW },
141         { atm_if_print,         DLT_ATM_RFC1483 },
142 #ifdef DLT_C_HDLC
143         { chdlc_if_print,       DLT_C_HDLC },
144 #endif
145 #ifdef DLT_HDLC
146         { chdlc_if_print,       DLT_HDLC },
147 #endif
148 #ifdef DLT_PPP_SERIAL
149         { ppp_hdlc_if_print,    DLT_PPP_SERIAL },
150 #endif
151 #ifdef DLT_PPP_ETHER
152         { pppoe_if_print,       DLT_PPP_ETHER },
153 #endif
154 #ifdef DLT_LINUX_SLL
155         { sll_if_print,         DLT_LINUX_SLL },
156 #endif
157 #ifdef DLT_IEEE802_11
158         { ieee802_11_if_print,  DLT_IEEE802_11},
159 #endif
160 #ifdef DLT_LTALK
161         { ltalk_if_print,       DLT_LTALK },
162 #endif
163         { NULL,                 0 },
164 };
165
166 static pcap_handler
167 lookup_printer(int type)
168 {
169         struct printer *p;
170
171         for (p = printers; p->f; ++p)
172                 if (type == p->type)
173                         return p->f;
174
175         error("unknown data link type %d", type);
176         /* NOTREACHED */
177 }
178
179 static pcap_t *pd;
180
181 extern int optind;
182 extern int opterr;
183 extern char *optarg;
184
185 struct dump_info {
186         char    *WFileName;
187         pcap_t  *pd;
188         pcap_dumper_t *p;
189 };
190
191 int
192 main(int argc, char **argv)
193 {
194         register int cnt, op, i;
195         bpf_u_int32 localnet, netmask;
196         register char *cp, *infile, *cmdbuf, *device, *RFileName, *WFileName;
197         pcap_handler printer;
198         struct bpf_program fcode;
199         RETSIGTYPE (*oldhandler)(int);
200         struct dump_info dumpinfo;
201         u_char *pcap_userdata;
202         char ebuf[PCAP_ERRBUF_SIZE];
203
204         cnt = -1;
205         device = NULL;
206         infile = NULL;
207         RFileName = NULL;
208         WFileName = NULL;
209         if ((cp = strrchr(argv[0], '/')) != NULL)
210                 program_name = cp + 1;
211         else
212                 program_name = argv[0];
213
214         if (abort_on_misalignment(ebuf, sizeof(ebuf)) < 0)
215                 error("%s", ebuf);
216
217 #ifdef LIBSMI
218         smiInit("tcpdump");
219 #endif
220         
221         opterr = 0;
222         while (
223             (op = getopt(argc, argv, "ac:C:deE:fF:i:lm:nNOpqr:Rs:StT:uvw:xXY")) != -1)
224                 switch (op) {
225
226                 case 'a':
227                         ++aflag;
228                         break;
229
230                 case 'c':
231                         cnt = atoi(optarg);
232                         if (cnt <= 0)
233                                 error("invalid packet count %s", optarg);
234                         break;
235
236                 case 'C':
237                         Cflag = atoi(optarg) * 1000000;
238                         if (Cflag < 0) 
239                                 error("invalid file size %s", optarg);
240                         break;
241
242                 case 'd':
243                         ++dflag;
244                         break;
245
246                 case 'e':
247                         ++eflag;
248                         break;
249
250                 case 'E':
251 #ifndef HAVE_LIBCRYPTO
252                         warning("crypto code not compiled in");
253 #endif
254                         espsecret = optarg;
255                         break;
256
257                 case 'f':
258                         ++fflag;
259                         break;
260
261                 case 'F':
262                         infile = optarg;
263                         break;
264
265                 case 'i':
266                         device = optarg;
267                         break;
268
269                 case 'l':
270 #ifdef HAVE_SETLINEBUF
271                         setlinebuf(stdout);
272 #else
273                         setvbuf(stdout, NULL, _IOLBF, 0);
274 #endif
275                         break;
276
277                 case 'n':
278                         ++nflag;
279                         break;
280
281                 case 'N':
282                         ++Nflag;
283                         break;
284
285                 case 'm':
286 #ifdef LIBSMI
287                         if (smiLoadModule(optarg) == 0) {
288                                 error("could not load MIB module %s", optarg);
289                         }
290                         sflag = 1;
291 #else
292                         (void)fprintf(stderr, "%s: ignoring option `-m %s' ",
293                                       program_name, optarg);
294                         (void)fprintf(stderr, "(no libsmi support)\n");
295 #endif
296                         
297                 case 'O':
298                         Oflag = 0;
299                         break;
300
301                 case 'p':
302                         ++pflag;
303                         break;
304
305                 case 'q':
306                         ++qflag;
307                         break;
308
309                 case 'r':
310                         RFileName = optarg;
311                         break;
312
313                 case 'R':
314                         Rflag = 0;
315                         break;
316
317                 case 's': {
318                         char *end;
319
320                         snaplen = strtol(optarg, &end, 0);
321                         if (optarg == end || *end != '\0'
322                             || snaplen < 0 || snaplen > 65535)
323                                 error("invalid snaplen %s", optarg);
324                         else if (snaplen == 0)
325                                 snaplen = 65535;
326                         break;
327                 }
328
329                 case 'S':
330                         ++Sflag;
331                         break;
332
333                 case 't':
334                         --tflag;
335                         break;
336
337                 case 'T':
338                         if (strcasecmp(optarg, "vat") == 0)
339                                 packettype = PT_VAT;
340                         else if (strcasecmp(optarg, "wb") == 0)
341                                 packettype = PT_WB;
342                         else if (strcasecmp(optarg, "rpc") == 0)
343                                 packettype = PT_RPC;
344                         else if (strcasecmp(optarg, "rtp") == 0)
345                                 packettype = PT_RTP;
346                         else if (strcasecmp(optarg, "rtcp") == 0)
347                                 packettype = PT_RTCP;
348                         else if (strcasecmp(optarg, "snmp") == 0)
349                                 packettype = PT_SNMP;
350                         else if (strcasecmp(optarg, "cnfp") == 0)
351                                 packettype = PT_CNFP;
352                         else
353                                 error("unknown packet type `%s'", optarg);
354                         break;
355
356                 case 'u':
357                         ++uflag;
358                         break;
359                         
360                 case 'v':
361                         ++vflag;
362                         break;
363
364                 case 'w':
365                         WFileName = optarg;
366                         break;
367
368                 case 'x':
369                         ++xflag;
370                         break;
371
372                 case 'X':
373                         ++xflag;
374                         ++Xflag;
375                         break;
376
377 #ifdef YYDEBUG
378                 case 'Y':
379                         {
380                         /* Undocumented flag */
381                         extern int yydebug;
382                         yydebug = 1;
383                         }
384                         break;
385 #endif
386                 default:
387                         usage();
388                         /* NOTREACHED */
389                 }
390
391         if (aflag && nflag)
392                 error("-a and -n options are incompatible");
393
394         if (tflag > 0)
395                 thiszone = gmt2local(0);
396
397         if (RFileName != NULL) {
398                 /*
399                  * We don't need network access, so set it back to the user id.
400                  * Also, this prevents the user from reading anyone's
401                  * trace file.
402                  */
403                 setuid(getuid());
404
405                 pd = pcap_open_offline(RFileName, ebuf);
406                 if (pd == NULL)
407                         error("%s", ebuf);
408                 localnet = 0;
409                 netmask = 0;
410                 if (fflag != 0)
411                         error("-f and -r options are incompatible");
412         } else {
413                 if (device == NULL) {
414                         device = pcap_lookupdev(ebuf);
415                         if (device == NULL)
416                                 error("%s", ebuf);
417                 }
418                 *ebuf = '\0';
419                 pd = pcap_open_live(device, snaplen, !pflag, 1000, ebuf);
420                 if (pd == NULL)
421                         error("%s", ebuf);
422                 else if (*ebuf)
423                         warning("%s", ebuf);
424                 i = pcap_snapshot(pd);
425                 if (snaplen < i) {
426                         warning("snaplen raised from %d to %d", snaplen, i);
427                         snaplen = i;
428                 }
429                 if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
430                         localnet = 0;
431                         netmask = 0;
432                         warning("%s", ebuf);
433                 }
434                 /*
435                  * Let user own process after socket has been opened.
436                  */
437                 setuid(getuid());
438         }
439         if (infile)
440                 cmdbuf = read_infile(infile);
441         else
442                 cmdbuf = copy_argv(&argv[optind]);
443
444         if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
445                 error("%s", pcap_geterr(pd));
446         if (dflag) {
447                 bpf_dump(&fcode, dflag);
448                 exit(0);
449         }
450         init_addrtoname(localnet, netmask);
451
452         (void)setsignal(SIGTERM, cleanup);
453         (void)setsignal(SIGINT, cleanup);
454         /* Cooperate with nohup(1) */
455         if ((oldhandler = setsignal(SIGHUP, cleanup)) != SIG_DFL)
456                 (void)setsignal(SIGHUP, oldhandler);
457
458         if (pcap_setfilter(pd, &fcode) < 0)
459                 error("%s", pcap_geterr(pd));
460         if (WFileName) {
461                 pcap_dumper_t *p = pcap_dump_open(pd, WFileName);
462                 if (p == NULL)
463                         error("%s", pcap_geterr(pd));
464                 if (Cflag != 0) {
465                         printer = dump_and_trunc;
466                         dumpinfo.WFileName = WFileName;
467                         dumpinfo.pd = pd;
468                         dumpinfo.p = p;
469                         pcap_userdata = (u_char *)&dumpinfo;
470                 } else {
471                         printer = pcap_dump;
472                         pcap_userdata = (u_char *)p;
473                 }
474         } else {
475                 printer = lookup_printer(pcap_datalink(pd));
476                 pcap_userdata = 0;
477 #ifdef SIGINFO
478                 (void)setsignal(SIGINFO, requestinfo);
479 #endif
480         }
481         if (RFileName == NULL) {
482                 (void)fprintf(stderr, "%s: listening on %s\n",
483                     program_name, device);
484                 (void)fflush(stderr);
485         }
486         if (pcap_loop(pd, cnt, printer, pcap_userdata) < 0) {
487                 (void)fprintf(stderr, "%s: pcap_loop: %s\n",
488                     program_name, pcap_geterr(pd));
489                 exit(1);
490         }
491         if (RFileName == NULL)
492                 info(1);
493         pcap_close(pd);
494         exit(0);
495 }
496
497 /* make a clean exit on interrupts */
498 static RETSIGTYPE
499 cleanup(int signo)
500 {
501
502         /* Can't print the summary if reading from a savefile */
503         if (pd != NULL && pcap_file(pd) == NULL) {
504                 (void)fflush(stdout);
505                 putc('\n', stderr);
506                 info(1);
507         }
508         exit(0);
509 }
510
511 void
512 info(register int verbose)
513 {
514         struct pcap_stat stat;
515
516         if (pcap_stats(pd, &stat) < 0) {
517                 (void)fprintf(stderr, "pcap_stats: %s\n", pcap_geterr(pd));
518                 return;
519         }
520         if (!verbose)
521                 fprintf(stderr, "%s: ", program_name);
522         (void)fprintf(stderr, "%d packets received by filter", stat.ps_recv);
523         if (!verbose)
524                 fputs(", ", stderr);
525         else
526                 putc('\n', stderr);
527         (void)fprintf(stderr, "%d packets dropped by kernel\n", stat.ps_drop);
528         infoprint = 0;
529 }
530
531 static void
532 reverse(char *s)
533 {
534         int i, j, c;
535
536         for (i = 0, j = strlen(s) - 1; i < j; i++, j--) {
537                 c = s[i];
538                 s[i] = s[j];
539                 s[j] = c;
540         }
541 }
542
543
544 static void
545 swebitoa(unsigned int n, char *s)
546 {
547         unsigned int i;
548
549         i = 0;
550         do {
551                 s[i++] = n % 10 + '0';
552         } while ((n /= 10) > 0);
553
554         s[i] = '\0';
555         reverse(s);
556 }
557
558 static void
559 dump_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
560 {
561         struct dump_info *info;
562         static uint cnt = 2;
563         char *name;
564
565         info = (struct dump_info *)user;
566         
567         /*
568          * XXX - this won't prevent capture files from getting
569          * larger than Cflag - the last packet written to the
570          * file could put it over Cflag.
571          */
572         if (ftell((FILE *)info->p) > Cflag) {
573                 name = (char *) malloc(strlen(info->WFileName) + 4);
574                 if (name == NULL)
575                         error("dump_and_trunc: malloc");
576                 strcpy(name, info->WFileName);
577                 swebitoa(cnt, name + strlen(info->WFileName));
578                 cnt++;
579                 pcap_dump_close(info->p);
580                 info->p = pcap_dump_open(info->pd, name);
581                 free(name);
582                 if (info->p == NULL)
583                         error("%s", pcap_geterr(pd));
584         }
585
586         pcap_dump((u_char *)info->p, h, sp);
587 }
588
589 /* Like default_print() but data need not be aligned */
590 void
591 default_print_unaligned(register const u_char *cp, register u_int length)
592 {
593         register u_int i, s;
594         register int nshorts;
595
596         if (Xflag) {
597                 ascii_print(cp, length);
598                 return;
599         }
600         nshorts = (u_int) length / sizeof(u_short);
601         i = 0;
602         while (--nshorts >= 0) {
603                 if ((i++ % 8) == 0)
604                         (void)printf("\n\t\t\t");
605                 s = *cp++;
606                 (void)printf(" %02x%02x", s, *cp++);
607         }
608         if (length & 1) {
609                 if ((i % 8) == 0)
610                         (void)printf("\n\t\t\t");
611                 (void)printf(" %02x", *cp);
612         }
613 }
614
615 /*
616  * By default, print the packet out in hex.
617  */
618 void
619 default_print(register const u_char *bp, register u_int length)
620 {
621         default_print_unaligned(bp, length);
622 }
623
624 #ifdef SIGINFO
625 RETSIGTYPE requestinfo(int signo)
626 {
627         if (infodelay)
628                 ++infoprint;
629         else
630                 info(0);
631 }
632 #endif
633
634 static void
635 usage(void)
636 {
637         extern char version[];
638         extern char pcap_version[];
639
640         (void)fprintf(stderr, "%s version %s\n", program_name, version);
641         (void)fprintf(stderr, "libpcap version %s\n", pcap_version);
642         (void)fprintf(stderr,
643 "Usage: %s [-adeflnNOpqRStuvxX] [ -c count ] [ -C file_size ]\n", program_name);
644         (void)fprintf(stderr,
645 "\t\t[ -F file ] [ -i interface ] [ -r file ] [ -s snaplen ]\n");
646         (void)fprintf(stderr,
647 "\t\t[ -T type ] [ -w file ] [ -E algo:secret ] [ expression ]\n");
648         exit(1);
649 }