tcpdump.c revision 56648
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
3056648Sarchie/* $FreeBSD: head/contrib/tcpdump/tcpdump.c 56648 2000-01-26 18:10:21Z archie $ */
3156648Sarchie
3217680Spst/*
3317680Spst * tcpdump - monitor tcp/ip traffic on an ethernet.
3417680Spst *
3517680Spst * First written in 1987 by Van Jacobson, Lawrence Berkeley Laboratory.
3617680Spst * Mercilessly hacked and occasionally improved since then via the
3717680Spst * combined efforts of Van, Steve McCanne and Craig Leres of LBL.
3817680Spst */
3917680Spst
4017680Spst#include <sys/types.h>
4117680Spst#include <sys/time.h>
4217680Spst
4317680Spst#include <netinet/in.h>
4417680Spst
4517680Spst#include <pcap.h>
4617680Spst#include <signal.h>
4717680Spst#include <stdio.h>
4817680Spst#include <stdlib.h>
4917680Spst#include <string.h>
5017680Spst#include <unistd.h>
5117680Spst
5217680Spst#include "interface.h"
5317680Spst#include "addrtoname.h"
5417680Spst#include "machdep.h"
5539297Sfenner#include "setsignal.h"
5639297Sfenner#include "gmt2local.h"
5717680Spst
5839297Sfennerint aflag;			/* translate network and broadcast addresses */
5939297Sfennerint dflag;			/* print filter code */
6039297Sfennerint eflag;			/* print ethernet header */
6117680Spstint fflag;			/* don't translate "foreign" IP address */
6217680Spstint nflag;			/* leave addresses as numbers */
6317680Spstint Nflag;			/* remove domains from printed host names */
6439297Sfennerint Oflag = 1;			/* run filter code optimizer */
6517680Spstint pflag;			/* don't go promiscuous */
6617680Spstint qflag;			/* quick (shorter) output */
6739297Sfennerint Sflag;			/* print raw TCP sequence numbers */
6817680Spstint tflag = 1;			/* print packet arrival time */
6917680Spstint vflag;			/* verbose */
7017680Spstint xflag;			/* print packet in hex */
7156648Sarchieint Xflag;			/* print packet in emacs-hexl style */
7239297Sfenner
7317680Spstint packettype;
7417680Spst
7517680Spst
7617680Spstchar *program_name;
7717680Spst
7817680Spstint32_t thiszone;		/* seconds offset from gmt to local time */
7917680Spst
8017680Spst/* Externs */
8117680Spstextern void bpf_dump(struct bpf_program *, int);
8217680Spst
8317680Spst/* Forwards */
8417680SpstRETSIGTYPE cleanup(int);
8517680Spstextern __dead void usage(void) __attribute__((volatile));
8617680Spst
8717680Spst/* Length of saved portion of packet. */
8817680Spstint snaplen = DEFAULT_SNAPLEN;
8917680Spst
9017680Spststruct printer {
9117680Spst	pcap_handler f;
9217680Spst	int type;
9317680Spst};
9417680Spst
9517680Spststatic struct printer printers[] = {
9617680Spst	{ ether_if_print,	DLT_EN10MB },
9744165Sjulian	{ token_if_print,	DLT_IEEE802 },
9817680Spst	{ sl_if_print,		DLT_SLIP },
9939297Sfenner	{ sl_bsdos_if_print,	DLT_SLIP_BSDOS },
10017680Spst	{ ppp_if_print,		DLT_PPP },
10139297Sfenner	{ ppp_bsdos_if_print,	DLT_PPP_BSDOS },
10217680Spst	{ fddi_if_print,	DLT_FDDI },
10317680Spst	{ null_if_print,	DLT_NULL },
10439297Sfenner	{ raw_if_print,		DLT_RAW },
10517680Spst	{ atm_if_print,		DLT_ATM_RFC1483 },
10617680Spst	{ NULL,			0 },
10717680Spst};
10817680Spst
10917680Spststatic pcap_handler
11017680Spstlookup_printer(int type)
11117680Spst{
11217680Spst	struct printer *p;
11317680Spst
11417680Spst	for (p = printers; p->f; ++p)
11517680Spst		if (type == p->type)
11617680Spst			return p->f;
11717680Spst
11817680Spst	error("unknown data link type 0x%x", type);
11917680Spst	/* NOTREACHED */
12017680Spst}
12117680Spst
12217680Spststatic pcap_t *pd;
12317680Spst
12417680Spstextern int optind;
12517680Spstextern int opterr;
12617680Spstextern char *optarg;
12717680Spst
12817680Spstint
12917680Spstmain(int argc, char **argv)
13017680Spst{
13117680Spst	register int cnt, op, i;
13217680Spst	bpf_u_int32 localnet, netmask;
13317680Spst	register char *cp, *infile, *cmdbuf, *device, *RFileName, *WFileName;
13417680Spst	pcap_handler printer;
13517680Spst	struct bpf_program fcode;
13639297Sfenner	RETSIGTYPE (*oldhandler)(int);
13717680Spst	u_char *pcap_userdata;
13817680Spst	char ebuf[PCAP_ERRBUF_SIZE];
13917680Spst
14017680Spst	cnt = -1;
14117680Spst	device = NULL;
14217680Spst	infile = NULL;
14317680Spst	RFileName = NULL;
14417680Spst	WFileName = NULL;
14517680Spst	if ((cp = strrchr(argv[0], '/')) != NULL)
14617680Spst		program_name = cp + 1;
14717680Spst	else
14817680Spst		program_name = argv[0];
14917680Spst
15017680Spst	if (abort_on_misalignment(ebuf) < 0)
15126180Sfenner		error("%s", ebuf);
15217680Spst
15317680Spst	opterr = 0;
15439297Sfenner	while (
15556648Sarchie	    (op = getopt(argc, argv, "ac:defF:i:lnNOpqr:s:StT:vw:xXY")) != EOF)
15617680Spst		switch (op) {
15739297Sfenner
15839297Sfenner		case 'a':
15939297Sfenner			++aflag;
16039297Sfenner			break;
16139297Sfenner
16217680Spst		case 'c':
16317680Spst			cnt = atoi(optarg);
16417680Spst			if (cnt <= 0)
16517680Spst				error("invalid packet count %s", optarg);
16617680Spst			break;
16717680Spst
16817680Spst		case 'd':
16917680Spst			++dflag;
17017680Spst			break;
17117680Spst
17217680Spst		case 'e':
17317680Spst			++eflag;
17417680Spst			break;
17517680Spst
17617680Spst		case 'f':
17717680Spst			++fflag;
17817680Spst			break;
17917680Spst
18017680Spst		case 'F':
18117680Spst			infile = optarg;
18217680Spst			break;
18317680Spst
18417680Spst		case 'i':
18517680Spst			device = optarg;
18617680Spst			break;
18717680Spst
18817680Spst		case 'l':
18917680Spst#ifdef HAVE_SETLINEBUF
19017680Spst			setlinebuf(stdout);
19117680Spst#else
19217680Spst			setvbuf(stdout, NULL, _IOLBF, 0);
19317680Spst#endif
19417680Spst			break;
19517680Spst
19617680Spst		case 'n':
19717680Spst			++nflag;
19817680Spst			break;
19917680Spst
20017680Spst		case 'N':
20117680Spst			++Nflag;
20217680Spst			break;
20317680Spst
20417680Spst		case 'O':
20517680Spst			Oflag = 0;
20617680Spst			break;
20717680Spst
20817680Spst		case 'p':
20917680Spst			++pflag;
21017680Spst			break;
21117680Spst
21217680Spst		case 'q':
21317680Spst			++qflag;
21417680Spst			break;
21517680Spst
21617680Spst		case 'r':
21717680Spst			RFileName = optarg;
21817680Spst			break;
21917680Spst
22017680Spst		case 's':
22117680Spst			snaplen = atoi(optarg);
22217680Spst			if (snaplen <= 0)
22317680Spst				error("invalid snaplen %s", optarg);
22417680Spst			break;
22517680Spst
22617680Spst		case 'S':
22717680Spst			++Sflag;
22817680Spst			break;
22917680Spst
23017680Spst		case 't':
23117680Spst			--tflag;
23217680Spst			break;
23317680Spst
23417680Spst		case 'T':
23517680Spst			if (strcasecmp(optarg, "vat") == 0)
23617680Spst				packettype = PT_VAT;
23717680Spst			else if (strcasecmp(optarg, "wb") == 0)
23817680Spst				packettype = PT_WB;
23917680Spst			else if (strcasecmp(optarg, "rpc") == 0)
24017680Spst				packettype = PT_RPC;
24117680Spst			else if (strcasecmp(optarg, "rtp") == 0)
24217680Spst				packettype = PT_RTP;
24317680Spst			else if (strcasecmp(optarg, "rtcp") == 0)
24417680Spst				packettype = PT_RTCP;
24517680Spst			else
24617680Spst				error("unknown packet type `%s'", optarg);
24717680Spst			break;
24817680Spst
24917680Spst		case 'v':
25017680Spst			++vflag;
25117680Spst			break;
25217680Spst
25317680Spst		case 'w':
25417680Spst			WFileName = optarg;
25517680Spst			break;
25617680Spst#ifdef YYDEBUG
25717680Spst		case 'Y':
25817680Spst			{
25917680Spst			/* Undocumented flag */
26017680Spst			extern int yydebug;
26117680Spst			yydebug = 1;
26217680Spst			}
26317680Spst			break;
26417680Spst#endif
26517680Spst		case 'x':
26617680Spst			++xflag;
26717680Spst			break;
26817680Spst
26956648Sarchie		case 'X':
27056648Sarchie			++Xflag;
27156648Sarchie			if (xflag == 0) ++xflag;
27256648Sarchie			break;
27356648Sarchie
27417680Spst		default:
27517680Spst			usage();
27617680Spst			/* NOTREACHED */
27717680Spst		}
27817680Spst
27939297Sfenner	if (aflag && nflag)
28039297Sfenner		error("-a and -n options are incompatible");
28139297Sfenner
28217680Spst	if (tflag > 0)
28339297Sfenner		thiszone = gmt2local(0);
28417680Spst
28517680Spst	if (RFileName != NULL) {
28617680Spst		/*
28717680Spst		 * We don't need network access, so set it back to the user id.
28817680Spst		 * Also, this prevents the user from reading anyone's
28917680Spst		 * trace file.
29017680Spst		 */
29117680Spst		setuid(getuid());
29217680Spst
29317680Spst		pd = pcap_open_offline(RFileName, ebuf);
29417680Spst		if (pd == NULL)
29526180Sfenner			error("%s", ebuf);
29617680Spst		localnet = 0;
29717680Spst		netmask = 0;
29817680Spst		if (fflag != 0)
29917680Spst			error("-f and -r options are incompatible");
30017680Spst	} else {
30117680Spst		if (device == NULL) {
30217680Spst			device = pcap_lookupdev(ebuf);
30317680Spst			if (device == NULL)
30426180Sfenner				error("%s", ebuf);
30517680Spst		}
30617680Spst		pd = pcap_open_live(device, snaplen, !pflag, 1000, ebuf);
30717680Spst		if (pd == NULL)
30826180Sfenner			error("%s", ebuf);
30917680Spst		i = pcap_snapshot(pd);
31017680Spst		if (snaplen < i) {
31117680Spst			warning("snaplen raised from %d to %d", snaplen, i);
31217680Spst			snaplen = i;
31317680Spst		}
31439297Sfenner		if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
31539297Sfenner			localnet = 0;
31639297Sfenner			netmask = 0;
31739297Sfenner			warning("%s", ebuf);
31839297Sfenner		}
31917680Spst		/*
32017680Spst		 * Let user own process after socket has been opened.
32117680Spst		 */
32217680Spst		setuid(getuid());
32317680Spst	}
32417680Spst	if (infile)
32517680Spst		cmdbuf = read_infile(infile);
32617680Spst	else
32717680Spst		cmdbuf = copy_argv(&argv[optind]);
32817680Spst
32917680Spst	if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
33026180Sfenner		error("%s", pcap_geterr(pd));
33117680Spst	if (dflag) {
33217680Spst		bpf_dump(&fcode, dflag);
33317680Spst		exit(0);
33417680Spst	}
33539297Sfenner	init_addrtoname(localnet, netmask);
33617680Spst
33739297Sfenner	(void)setsignal(SIGTERM, cleanup);
33839297Sfenner	(void)setsignal(SIGINT, cleanup);
33939297Sfenner	/* Cooperate with nohup(1) */
34039297Sfenner	if ((oldhandler = setsignal(SIGHUP, cleanup)) != SIG_DFL)
34139297Sfenner		(void)setsignal(SIGHUP, oldhandler);
34217680Spst
34317680Spst	if (pcap_setfilter(pd, &fcode) < 0)
34426180Sfenner		error("%s", pcap_geterr(pd));
34517680Spst	if (WFileName) {
34617680Spst		pcap_dumper_t *p = pcap_dump_open(pd, WFileName);
34717680Spst		if (p == NULL)
34826180Sfenner			error("%s", pcap_geterr(pd));
34917680Spst		printer = pcap_dump;
35017680Spst		pcap_userdata = (u_char *)p;
35117680Spst	} else {
35217680Spst		printer = lookup_printer(pcap_datalink(pd));
35317680Spst		pcap_userdata = 0;
35417680Spst	}
35517680Spst	if (RFileName == NULL) {
35617680Spst		(void)fprintf(stderr, "%s: listening on %s\n",
35717680Spst		    program_name, device);
35817680Spst		(void)fflush(stderr);
35917680Spst	}
36017680Spst	if (pcap_loop(pd, cnt, printer, pcap_userdata) < 0) {
36117680Spst		(void)fprintf(stderr, "%s: pcap_loop: %s\n",
36217680Spst		    program_name, pcap_geterr(pd));
36317680Spst		exit(1);
36417680Spst	}
36517680Spst	pcap_close(pd);
36617680Spst	exit(0);
36717680Spst}
36817680Spst
36917680Spst/* make a clean exit on interrupts */
37017680SpstRETSIGTYPE
37117680Spstcleanup(int signo)
37217680Spst{
37317680Spst	struct pcap_stat stat;
37417680Spst
37517680Spst	/* Can't print the summary if reading from a savefile */
37617680Spst	if (pd != NULL && pcap_file(pd) == NULL) {
37717680Spst		(void)fflush(stdout);
37817680Spst		putc('\n', stderr);
37917680Spst		if (pcap_stats(pd, &stat) < 0)
38017680Spst			(void)fprintf(stderr, "pcap_stats: %s\n",
38117680Spst			    pcap_geterr(pd));
38217680Spst		else {
38317680Spst			(void)fprintf(stderr, "%d packets received by filter\n",
38417680Spst			    stat.ps_recv);
38517680Spst			(void)fprintf(stderr, "%d packets dropped by kernel\n",
38617680Spst			    stat.ps_drop);
38717680Spst		}
38817680Spst	}
38917680Spst	exit(0);
39017680Spst}
39117680Spst
39256648Sarchie/* dump the buffer in `emacs-hexl' style */
39356648Sarchievoid
39456648Sarchiedefault_print_hexl(const u_char *cp, unsigned int length, unsigned int offset)
39556648Sarchie{
39656648Sarchie	unsigned int i, j, jm;
39756648Sarchie	int c;
39856648Sarchie	char ln[128];
39956648Sarchie
40056648Sarchie	printf("\n");
40156648Sarchie	for (i = 0; i < length; i += 0x10) {
40256648Sarchie		snprintf(ln,
40356648Sarchie			 sizeof(ln),
40456648Sarchie			 "  %04x: ", (unsigned int)(i + offset));
40556648Sarchie		jm = length - i;
40656648Sarchie		jm = jm > 16 ? 16 : jm;
40756648Sarchie
40856648Sarchie		for (j = 0; j < jm; j++) {
40956648Sarchie			if ((j % 2) == 1)
41056648Sarchie				snprintf(ln + strlen(ln),
41156648Sarchie					 sizeof(ln) - strlen(ln),
41256648Sarchie					 "%02x ", (unsigned int)cp[i+j]);
41356648Sarchie			else
41456648Sarchie				snprintf(ln + strlen(ln),
41556648Sarchie					 sizeof(ln) - strlen(ln),
41656648Sarchie					 "%02x", (unsigned int)cp[i+j]);
41756648Sarchie		}
41856648Sarchie		for (; j < 16; j++) {
41956648Sarchie			if ((j % 2) == 1)
42056648Sarchie				snprintf(ln + strlen(ln),
42156648Sarchie					 sizeof(ln) - strlen(ln),
42256648Sarchie					 "   ");
42356648Sarchie			else
42456648Sarchie				snprintf(ln + strlen(ln),
42556648Sarchie					 sizeof(ln) - strlen(ln),
42656648Sarchie					 "  ");
42756648Sarchie		}
42856648Sarchie
42956648Sarchie		snprintf(ln + strlen(ln), sizeof(ln) - strlen(ln), " ");
43056648Sarchie		for (j = 0; j < jm; j++) {
43156648Sarchie			c = cp[i+j];
43256648Sarchie			c = isprint(c) ? c : '.';
43356648Sarchie			snprintf(ln + strlen(ln),
43456648Sarchie				 sizeof(ln) - strlen(ln),
43556648Sarchie				 "%c", c);
43656648Sarchie		}
43756648Sarchie		printf("%s\n", ln);
43856648Sarchie	}
43956648Sarchie}
44056648Sarchie
44117680Spst/* Like default_print() but data need not be aligned */
44217680Spstvoid
44317680Spstdefault_print_unaligned(register const u_char *cp, register u_int length)
44417680Spst{
44517680Spst	register u_int i, s;
44617680Spst	register int nshorts;
44717680Spst
44856648Sarchie	if (Xflag) {
44956648Sarchie		/* dump the buffer in `emacs-hexl' style */
45056648Sarchie		default_print_hexl(cp, length, 0);
45156648Sarchie	} else {
45256648Sarchie		/* dump the buffer in old tcpdump style */
45356648Sarchie		nshorts = (u_int) length / sizeof(u_short);
45456648Sarchie		i = 0;
45556648Sarchie		while (--nshorts >= 0) {
45656648Sarchie			if ((i++ % 8) == 0)
45756648Sarchie				(void)printf("\n\t\t\t");
45856648Sarchie			s = *cp++;
45956648Sarchie			(void)printf(" %02x%02x", s, *cp++);
46056648Sarchie		}
46156648Sarchie		if (length & 1) {
46256648Sarchie			if ((i % 8) == 0)
46356648Sarchie				(void)printf("\n\t\t\t");
46456648Sarchie			(void)printf(" %02x", *cp);
46556648Sarchie		}
46617680Spst	}
46717680Spst}
46817680Spst
46939297Sfenner/*
47039297Sfenner * By default, print the packet out in hex.
47139297Sfenner *
47239297Sfenner * (BTW, please don't send us patches to print the packet out in ascii)
47339297Sfenner */
47417680Spstvoid
47517680Spstdefault_print(register const u_char *bp, register u_int length)
47617680Spst{
47717680Spst	register const u_short *sp;
47817680Spst	register u_int i;
47917680Spst	register int nshorts;
48017680Spst
48156648Sarchie	if (Xflag) {
48256648Sarchie		/* dump the buffer in `emacs-hexl' style */
48356648Sarchie		default_print_hexl(bp, length, 0);
48456648Sarchie	} else {
48556648Sarchie		/* dump the buffer in old tcpdump style */
48656648Sarchie		if ((long)bp & 1) {
48756648Sarchie			default_print_unaligned(bp, length);
48856648Sarchie			return;
48956648Sarchie		}
49056648Sarchie		sp = (u_short *)bp;
49156648Sarchie		nshorts = (u_int) length / sizeof(u_short);
49256648Sarchie		i = 0;
49356648Sarchie		while (--nshorts >= 0) {
49456648Sarchie			if ((i++ % 8) == 0)
49556648Sarchie				(void)printf("\n\t\t\t");
49656648Sarchie			(void)printf(" %04x", ntohs(*sp++));
49756648Sarchie		}
49856648Sarchie		if (length & 1) {
49956648Sarchie			if ((i % 8) == 0)
50056648Sarchie				(void)printf("\n\t\t\t");
50156648Sarchie			(void)printf(" %02x", *(u_char *)sp);
50256648Sarchie		}
50317680Spst	}
50417680Spst}
50517680Spst
50617680Spst__dead void
50726180Sfennerusage(void)
50817680Spst{
50917680Spst	extern char version[];
51039297Sfenner	extern char pcap_version[];
51117680Spst
51239297Sfenner	(void)fprintf(stderr, "%s version %s\n", program_name, version);
51339297Sfenner	(void)fprintf(stderr, "libpcap version %s\n", pcap_version);
51417680Spst	(void)fprintf(stderr,
51556648Sarchie"Usage: %s [-adeflnNOpqStvxX] [-c count] [ -F file ]\n", program_name);
51617680Spst	(void)fprintf(stderr,
51717680Spst"\t\t[ -i interface ] [ -r file ] [ -s snaplen ]\n");
51817680Spst	(void)fprintf(stderr,
51917680Spst"\t\t[ -T type ] [ -w file ] [ expression ]\n");
52017680Spst	exit(-1);
52117680Spst}
522