tcpdump.c revision 44165
117680Spst/*
239297Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
317680Spst *	The Regents of the University of California.  All rights reserved.
417680Spst *
517680Spst * Redistribution and use in source and binary forms, with or without
617680Spst * modification, are permitted provided that: (1) source code distributions
717680Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817680Spst * distributions including binary code include the above copyright notice and
917680Spst * this paragraph in its entirety in the documentation or other materials
1017680Spst * provided with the distribution, and (3) all advertising materials mentioning
1117680Spst * features or use of this software display the following acknowledgement:
1217680Spst * ``This product includes software developed by the University of California,
1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417680Spst * the University nor the names of its contributors may be used to endorse
1517680Spst * or promote products derived from this software without specific prior
1617680Spst * written permission.
1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2017680Spst */
2117680Spst
2217680Spst#ifndef lint
2326180Sfennerstatic const char copyright[] =
2439297Sfenner    "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997\n\
2517680SpstThe Regents of the University of California.  All rights reserved.\n";
2626180Sfennerstatic const char rcsid[] =
2739297Sfenner    "@(#) $Header: tcpdump.c,v 1.129 97/06/13 13:10:11 leres Exp $ (LBL)";
2817680Spst#endif
2917680Spst
3017680Spst/*
3117680Spst * tcpdump - monitor tcp/ip traffic on an ethernet.
3217680Spst *
3317680Spst * First written in 1987 by Van Jacobson, Lawrence Berkeley Laboratory.
3417680Spst * Mercilessly hacked and occasionally improved since then via the
3517680Spst * combined efforts of Van, Steve McCanne and Craig Leres of LBL.
3617680Spst */
3717680Spst
3817680Spst#include <sys/types.h>
3917680Spst#include <sys/time.h>
4017680Spst
4117680Spst#include <netinet/in.h>
4217680Spst
4317680Spst#include <pcap.h>
4417680Spst#include <signal.h>
4517680Spst#include <stdio.h>
4617680Spst#include <stdlib.h>
4717680Spst#include <string.h>
4817680Spst#include <unistd.h>
4917680Spst
5017680Spst#include "interface.h"
5117680Spst#include "addrtoname.h"
5217680Spst#include "machdep.h"
5339297Sfenner#include "setsignal.h"
5439297Sfenner#include "gmt2local.h"
5517680Spst
5639297Sfennerint aflag;			/* translate network and broadcast addresses */
5739297Sfennerint dflag;			/* print filter code */
5839297Sfennerint eflag;			/* print ethernet header */
5917680Spstint fflag;			/* don't translate "foreign" IP address */
6017680Spstint nflag;			/* leave addresses as numbers */
6117680Spstint Nflag;			/* remove domains from printed host names */
6239297Sfennerint Oflag = 1;			/* run filter code optimizer */
6317680Spstint pflag;			/* don't go promiscuous */
6417680Spstint qflag;			/* quick (shorter) output */
6539297Sfennerint Sflag;			/* print raw TCP sequence numbers */
6617680Spstint tflag = 1;			/* print packet arrival time */
6717680Spstint vflag;			/* verbose */
6817680Spstint xflag;			/* print packet in hex */
6939297Sfenner
7017680Spstint packettype;
7117680Spst
7217680Spst
7317680Spstchar *program_name;
7417680Spst
7517680Spstint32_t thiszone;		/* seconds offset from gmt to local time */
7617680Spst
7717680Spst/* Externs */
7817680Spstextern void bpf_dump(struct bpf_program *, int);
7917680Spst
8017680Spst/* Forwards */
8117680SpstRETSIGTYPE cleanup(int);
8217680Spstextern __dead void usage(void) __attribute__((volatile));
8317680Spst
8417680Spst/* Length of saved portion of packet. */
8517680Spstint snaplen = DEFAULT_SNAPLEN;
8617680Spst
8717680Spststruct printer {
8817680Spst	pcap_handler f;
8917680Spst	int type;
9017680Spst};
9117680Spst
9217680Spststatic struct printer printers[] = {
9317680Spst	{ ether_if_print,	DLT_EN10MB },
9444165Sjulian	{ token_if_print,	DLT_IEEE802 },
9517680Spst	{ sl_if_print,		DLT_SLIP },
9639297Sfenner	{ sl_bsdos_if_print,	DLT_SLIP_BSDOS },
9717680Spst	{ ppp_if_print,		DLT_PPP },
9839297Sfenner	{ ppp_bsdos_if_print,	DLT_PPP_BSDOS },
9917680Spst	{ fddi_if_print,	DLT_FDDI },
10017680Spst	{ null_if_print,	DLT_NULL },
10139297Sfenner	{ raw_if_print,		DLT_RAW },
10217680Spst	{ atm_if_print,		DLT_ATM_RFC1483 },
10317680Spst	{ NULL,			0 },
10417680Spst};
10517680Spst
10617680Spststatic pcap_handler
10717680Spstlookup_printer(int type)
10817680Spst{
10917680Spst	struct printer *p;
11017680Spst
11117680Spst	for (p = printers; p->f; ++p)
11217680Spst		if (type == p->type)
11317680Spst			return p->f;
11417680Spst
11517680Spst	error("unknown data link type 0x%x", type);
11617680Spst	/* NOTREACHED */
11717680Spst}
11817680Spst
11917680Spststatic pcap_t *pd;
12017680Spst
12117680Spstextern int optind;
12217680Spstextern int opterr;
12317680Spstextern char *optarg;
12417680Spst
12517680Spstint
12617680Spstmain(int argc, char **argv)
12717680Spst{
12817680Spst	register int cnt, op, i;
12917680Spst	bpf_u_int32 localnet, netmask;
13017680Spst	register char *cp, *infile, *cmdbuf, *device, *RFileName, *WFileName;
13117680Spst	pcap_handler printer;
13217680Spst	struct bpf_program fcode;
13339297Sfenner	RETSIGTYPE (*oldhandler)(int);
13417680Spst	u_char *pcap_userdata;
13517680Spst	char ebuf[PCAP_ERRBUF_SIZE];
13617680Spst
13717680Spst	cnt = -1;
13817680Spst	device = NULL;
13917680Spst	infile = NULL;
14017680Spst	RFileName = NULL;
14117680Spst	WFileName = NULL;
14217680Spst	if ((cp = strrchr(argv[0], '/')) != NULL)
14317680Spst		program_name = cp + 1;
14417680Spst	else
14517680Spst		program_name = argv[0];
14617680Spst
14717680Spst	if (abort_on_misalignment(ebuf) < 0)
14826180Sfenner		error("%s", ebuf);
14917680Spst
15017680Spst	opterr = 0;
15139297Sfenner	while (
15239297Sfenner	    (op = getopt(argc, argv, "ac:defF:i:lnNOpqr:s:StT:vw:xY")) != EOF)
15317680Spst		switch (op) {
15439297Sfenner
15539297Sfenner		case 'a':
15639297Sfenner			++aflag;
15739297Sfenner			break;
15839297Sfenner
15917680Spst		case 'c':
16017680Spst			cnt = atoi(optarg);
16117680Spst			if (cnt <= 0)
16217680Spst				error("invalid packet count %s", optarg);
16317680Spst			break;
16417680Spst
16517680Spst		case 'd':
16617680Spst			++dflag;
16717680Spst			break;
16817680Spst
16917680Spst		case 'e':
17017680Spst			++eflag;
17117680Spst			break;
17217680Spst
17317680Spst		case 'f':
17417680Spst			++fflag;
17517680Spst			break;
17617680Spst
17717680Spst		case 'F':
17817680Spst			infile = optarg;
17917680Spst			break;
18017680Spst
18117680Spst		case 'i':
18217680Spst			device = optarg;
18317680Spst			break;
18417680Spst
18517680Spst		case 'l':
18617680Spst#ifdef HAVE_SETLINEBUF
18717680Spst			setlinebuf(stdout);
18817680Spst#else
18917680Spst			setvbuf(stdout, NULL, _IOLBF, 0);
19017680Spst#endif
19117680Spst			break;
19217680Spst
19317680Spst		case 'n':
19417680Spst			++nflag;
19517680Spst			break;
19617680Spst
19717680Spst		case 'N':
19817680Spst			++Nflag;
19917680Spst			break;
20017680Spst
20117680Spst		case 'O':
20217680Spst			Oflag = 0;
20317680Spst			break;
20417680Spst
20517680Spst		case 'p':
20617680Spst			++pflag;
20717680Spst			break;
20817680Spst
20917680Spst		case 'q':
21017680Spst			++qflag;
21117680Spst			break;
21217680Spst
21317680Spst		case 'r':
21417680Spst			RFileName = optarg;
21517680Spst			break;
21617680Spst
21717680Spst		case 's':
21817680Spst			snaplen = atoi(optarg);
21917680Spst			if (snaplen <= 0)
22017680Spst				error("invalid snaplen %s", optarg);
22117680Spst			break;
22217680Spst
22317680Spst		case 'S':
22417680Spst			++Sflag;
22517680Spst			break;
22617680Spst
22717680Spst		case 't':
22817680Spst			--tflag;
22917680Spst			break;
23017680Spst
23117680Spst		case 'T':
23217680Spst			if (strcasecmp(optarg, "vat") == 0)
23317680Spst				packettype = PT_VAT;
23417680Spst			else if (strcasecmp(optarg, "wb") == 0)
23517680Spst				packettype = PT_WB;
23617680Spst			else if (strcasecmp(optarg, "rpc") == 0)
23717680Spst				packettype = PT_RPC;
23817680Spst			else if (strcasecmp(optarg, "rtp") == 0)
23917680Spst				packettype = PT_RTP;
24017680Spst			else if (strcasecmp(optarg, "rtcp") == 0)
24117680Spst				packettype = PT_RTCP;
24217680Spst			else
24317680Spst				error("unknown packet type `%s'", optarg);
24417680Spst			break;
24517680Spst
24617680Spst		case 'v':
24717680Spst			++vflag;
24817680Spst			break;
24917680Spst
25017680Spst		case 'w':
25117680Spst			WFileName = optarg;
25217680Spst			break;
25317680Spst#ifdef YYDEBUG
25417680Spst		case 'Y':
25517680Spst			{
25617680Spst			/* Undocumented flag */
25717680Spst			extern int yydebug;
25817680Spst			yydebug = 1;
25917680Spst			}
26017680Spst			break;
26117680Spst#endif
26217680Spst		case 'x':
26317680Spst			++xflag;
26417680Spst			break;
26517680Spst
26617680Spst		default:
26717680Spst			usage();
26817680Spst			/* NOTREACHED */
26917680Spst		}
27017680Spst
27139297Sfenner	if (aflag && nflag)
27239297Sfenner		error("-a and -n options are incompatible");
27339297Sfenner
27417680Spst	if (tflag > 0)
27539297Sfenner		thiszone = gmt2local(0);
27617680Spst
27717680Spst	if (RFileName != NULL) {
27817680Spst		/*
27917680Spst		 * We don't need network access, so set it back to the user id.
28017680Spst		 * Also, this prevents the user from reading anyone's
28117680Spst		 * trace file.
28217680Spst		 */
28317680Spst		setuid(getuid());
28417680Spst
28517680Spst		pd = pcap_open_offline(RFileName, ebuf);
28617680Spst		if (pd == NULL)
28726180Sfenner			error("%s", ebuf);
28817680Spst		localnet = 0;
28917680Spst		netmask = 0;
29017680Spst		if (fflag != 0)
29117680Spst			error("-f and -r options are incompatible");
29217680Spst	} else {
29317680Spst		if (device == NULL) {
29417680Spst			device = pcap_lookupdev(ebuf);
29517680Spst			if (device == NULL)
29626180Sfenner				error("%s", ebuf);
29717680Spst		}
29817680Spst		pd = pcap_open_live(device, snaplen, !pflag, 1000, ebuf);
29917680Spst		if (pd == NULL)
30026180Sfenner			error("%s", ebuf);
30117680Spst		i = pcap_snapshot(pd);
30217680Spst		if (snaplen < i) {
30317680Spst			warning("snaplen raised from %d to %d", snaplen, i);
30417680Spst			snaplen = i;
30517680Spst		}
30639297Sfenner		if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
30739297Sfenner			localnet = 0;
30839297Sfenner			netmask = 0;
30939297Sfenner			warning("%s", ebuf);
31039297Sfenner		}
31117680Spst		/*
31217680Spst		 * Let user own process after socket has been opened.
31317680Spst		 */
31417680Spst		setuid(getuid());
31517680Spst	}
31617680Spst	if (infile)
31717680Spst		cmdbuf = read_infile(infile);
31817680Spst	else
31917680Spst		cmdbuf = copy_argv(&argv[optind]);
32017680Spst
32117680Spst	if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
32226180Sfenner		error("%s", pcap_geterr(pd));
32317680Spst	if (dflag) {
32417680Spst		bpf_dump(&fcode, dflag);
32517680Spst		exit(0);
32617680Spst	}
32739297Sfenner	init_addrtoname(localnet, netmask);
32817680Spst
32939297Sfenner	(void)setsignal(SIGTERM, cleanup);
33039297Sfenner	(void)setsignal(SIGINT, cleanup);
33139297Sfenner	/* Cooperate with nohup(1) */
33239297Sfenner	if ((oldhandler = setsignal(SIGHUP, cleanup)) != SIG_DFL)
33339297Sfenner		(void)setsignal(SIGHUP, oldhandler);
33417680Spst
33517680Spst	if (pcap_setfilter(pd, &fcode) < 0)
33626180Sfenner		error("%s", pcap_geterr(pd));
33717680Spst	if (WFileName) {
33817680Spst		pcap_dumper_t *p = pcap_dump_open(pd, WFileName);
33917680Spst		if (p == NULL)
34026180Sfenner			error("%s", pcap_geterr(pd));
34117680Spst		printer = pcap_dump;
34217680Spst		pcap_userdata = (u_char *)p;
34317680Spst	} else {
34417680Spst		printer = lookup_printer(pcap_datalink(pd));
34517680Spst		pcap_userdata = 0;
34617680Spst	}
34717680Spst	if (RFileName == NULL) {
34817680Spst		(void)fprintf(stderr, "%s: listening on %s\n",
34917680Spst		    program_name, device);
35017680Spst		(void)fflush(stderr);
35117680Spst	}
35217680Spst	if (pcap_loop(pd, cnt, printer, pcap_userdata) < 0) {
35317680Spst		(void)fprintf(stderr, "%s: pcap_loop: %s\n",
35417680Spst		    program_name, pcap_geterr(pd));
35517680Spst		exit(1);
35617680Spst	}
35717680Spst	pcap_close(pd);
35817680Spst	exit(0);
35917680Spst}
36017680Spst
36117680Spst/* make a clean exit on interrupts */
36217680SpstRETSIGTYPE
36317680Spstcleanup(int signo)
36417680Spst{
36517680Spst	struct pcap_stat stat;
36617680Spst
36717680Spst	/* Can't print the summary if reading from a savefile */
36817680Spst	if (pd != NULL && pcap_file(pd) == NULL) {
36917680Spst		(void)fflush(stdout);
37017680Spst		putc('\n', stderr);
37117680Spst		if (pcap_stats(pd, &stat) < 0)
37217680Spst			(void)fprintf(stderr, "pcap_stats: %s\n",
37317680Spst			    pcap_geterr(pd));
37417680Spst		else {
37517680Spst			(void)fprintf(stderr, "%d packets received by filter\n",
37617680Spst			    stat.ps_recv);
37717680Spst			(void)fprintf(stderr, "%d packets dropped by kernel\n",
37817680Spst			    stat.ps_drop);
37917680Spst		}
38017680Spst	}
38117680Spst	exit(0);
38217680Spst}
38317680Spst
38417680Spst/* Like default_print() but data need not be aligned */
38517680Spstvoid
38617680Spstdefault_print_unaligned(register const u_char *cp, register u_int length)
38717680Spst{
38817680Spst	register u_int i, s;
38917680Spst	register int nshorts;
39017680Spst
39117680Spst	nshorts = (u_int) length / sizeof(u_short);
39217680Spst	i = 0;
39317680Spst	while (--nshorts >= 0) {
39417680Spst		if ((i++ % 8) == 0)
39517680Spst			(void)printf("\n\t\t\t");
39617680Spst		s = *cp++;
39717680Spst		(void)printf(" %02x%02x", s, *cp++);
39817680Spst	}
39917680Spst	if (length & 1) {
40017680Spst		if ((i % 8) == 0)
40117680Spst			(void)printf("\n\t\t\t");
40217680Spst		(void)printf(" %02x", *cp);
40317680Spst	}
40417680Spst}
40517680Spst
40639297Sfenner/*
40739297Sfenner * By default, print the packet out in hex.
40839297Sfenner *
40939297Sfenner * (BTW, please don't send us patches to print the packet out in ascii)
41039297Sfenner */
41117680Spstvoid
41217680Spstdefault_print(register const u_char *bp, register u_int length)
41317680Spst{
41417680Spst	register const u_short *sp;
41517680Spst	register u_int i;
41617680Spst	register int nshorts;
41717680Spst
41817680Spst	if ((long)bp & 1) {
41917680Spst		default_print_unaligned(bp, length);
42017680Spst		return;
42117680Spst	}
42217680Spst	sp = (u_short *)bp;
42317680Spst	nshorts = (u_int) length / sizeof(u_short);
42417680Spst	i = 0;
42517680Spst	while (--nshorts >= 0) {
42617680Spst		if ((i++ % 8) == 0)
42717680Spst			(void)printf("\n\t\t\t");
42817680Spst		(void)printf(" %04x", ntohs(*sp++));
42917680Spst	}
43017680Spst	if (length & 1) {
43117680Spst		if ((i % 8) == 0)
43217680Spst			(void)printf("\n\t\t\t");
43317680Spst		(void)printf(" %02x", *(u_char *)sp);
43417680Spst	}
43517680Spst}
43617680Spst
43717680Spst__dead void
43826180Sfennerusage(void)
43917680Spst{
44017680Spst	extern char version[];
44139297Sfenner	extern char pcap_version[];
44217680Spst
44339297Sfenner	(void)fprintf(stderr, "%s version %s\n", program_name, version);
44439297Sfenner	(void)fprintf(stderr, "libpcap version %s\n", pcap_version);
44517680Spst	(void)fprintf(stderr,
44639297Sfenner"Usage: %s [-adeflnNOpqStvx] [-c count] [ -F file ]\n", program_name);
44717680Spst	(void)fprintf(stderr,
44817680Spst"\t\t[ -i interface ] [ -r file ] [ -s snaplen ]\n");
44917680Spst	(void)fprintf(stderr,
45017680Spst"\t\t[ -T type ] [ -w file ] [ expression ]\n");
45117680Spst	exit(-1);
45217680Spst}
453