tcpdump.c revision 146778
117680Spst/*
298527Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
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.
2098527Sfenner *
2198527Sfenner * Support for splitting captures into multiple files with a maximum
2298527Sfenner * file size:
2398527Sfenner *
2498527Sfenner * Copyright (c) 2001
2598527Sfenner *	Seth Webster <swebster@sst.ll.mit.edu>
2617680Spst */
2717680Spst
2817680Spst#ifndef lint
29127675Sbmsstatic const char copyright[] _U_ =
3098527Sfenner    "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
3117680SpstThe Regents of the University of California.  All rights reserved.\n";
32127675Sbmsstatic const char rcsid[] _U_ =
33146778Ssam    "@(#) $Header: /tcpdump/master/tcpdump/tcpdump.c,v 1.253 2005/01/27 18:30:36 hannes Exp $ (LBL)";
3417680Spst#endif
3517680Spst
3656648Sarchie/* $FreeBSD: head/contrib/tcpdump/tcpdump.c 146778 2005-05-29 19:09:28Z sam $ */
3756648Sarchie
3817680Spst/*
3917680Spst * tcpdump - monitor tcp/ip traffic on an ethernet.
4017680Spst *
4117680Spst * First written in 1987 by Van Jacobson, Lawrence Berkeley Laboratory.
4217680Spst * Mercilessly hacked and occasionally improved since then via the
4317680Spst * combined efforts of Van, Steve McCanne and Craig Leres of LBL.
4417680Spst */
4517680Spst
4656896Sfenner#ifdef HAVE_CONFIG_H
4756896Sfenner#include "config.h"
4856896Sfenner#endif
4956896Sfenner
50127675Sbms#include <tcpdump-stdinc.h>
5117680Spst
52127675Sbms#ifdef WIN32
53127675Sbms#include "getopt.h"
54127675Sbms#include "w32_fzs.h"
55127675Sbmsextern int strcasecmp (const char *__s1, const char *__s2);
56127675Sbmsextern int SIZE_BUF;
57127675Sbms#define off_t long
58127675Sbms#define uint UINT
59127675Sbms#endif /* WIN32 */
6017680Spst
61146778Ssam#ifdef HAVE_SMI_H
62146778Ssam#include <smi.h>
63146778Ssam#endif
64146778Ssam
6517680Spst#include <pcap.h>
6617680Spst#include <signal.h>
6717680Spst#include <stdio.h>
6817680Spst#include <stdlib.h>
6917680Spst#include <string.h>
70146778Ssam#ifndef WIN32
71146778Ssam#include <pwd.h>
72146778Ssam#include <grp.h>
73146778Ssam#include <errno.h>
74146778Ssam#endif /* WIN32 */
7517680Spst
76146778Ssam#include "netdissect.h"
7717680Spst#include "interface.h"
7817680Spst#include "addrtoname.h"
7917680Spst#include "machdep.h"
8039297Sfenner#include "setsignal.h"
8139297Sfenner#include "gmt2local.h"
82127675Sbms#include "pcap-missing.h"
8317680Spst
84146778Ssamnetdissect_options Gndo;
85146778Ssamnetdissect_options *gndo = &Gndo;
86146778Ssam
87146778Ssam/*
88146778Ssam * Define the maximum number of files for the -C flag, and how many
89146778Ssam * characters can be added to a filename for the -C flag (which
90146778Ssam * should be enough to handle MAX_CFLAG - 1).
91146778Ssam */
92146778Ssam#define MAX_CFLAG	1000000
93146778Ssam#define MAX_CFLAG_CHARS	6
94146778Ssam
9539297Sfennerint dflag;			/* print filter code */
96109842Sfennerint Lflag;			/* list available data link types and exit */
9739297Sfenner
98127675Sbmsstatic int infodelay;
99127675Sbmsstatic int infoprint;
10017680Spst
10117680Spstchar *program_name;
10217680Spst
10317680Spstint32_t thiszone;		/* seconds offset from gmt to local time */
10417680Spst
10517680Spst/* Forwards */
10675118Sfennerstatic RETSIGTYPE cleanup(int);
10775118Sfennerstatic void usage(void) __attribute__((noreturn));
108109842Sfennerstatic void show_dlts_and_exit(pcap_t *pd) __attribute__((noreturn));
10917680Spst
110127675Sbmsstatic void print_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
111146778Ssamstatic void ndo_default_print(netdissect_options *, const u_char *, u_int);
112127675Sbmsstatic void dump_packet_and_trunc(u_char *, const struct pcap_pkthdr *, const u_char *);
113127675Sbmsstatic void dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
114146778Ssamstatic void droproot(const char *, const char *);
115146778Ssamstatic void ndo_error(netdissect_options *ndo, const char *fmt, ...);
116146778Ssamstatic void ndo_warning(netdissect_options *ndo, const char *fmt, ...);
11798527Sfenner
11898527Sfenner#ifdef SIGINFO
11998527SfennerRETSIGTYPE requestinfo(int);
12098527Sfenner#endif
12198527Sfenner
122146778Ssam#if defined(USE_WIN32_MM_TIMER)
123146778Ssam  #include <MMsystem.h>
124146778Ssam  static UINT timer_id;
125146778Ssam  static void CALLBACK verbose_stats_dump(UINT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR);
126146778Ssam#elif defined(HAVE_ALARM)
127146778Ssam  static void verbose_stats_dump(int sig);
128146778Ssam#endif
129146778Ssam
130127675Sbmsstatic void info(int);
131127675Sbmsstatic u_int packets_captured;
132127675Sbms
133127675Sbmstypedef u_int (*if_printer)(const struct pcap_pkthdr *, const u_char *);
134127675Sbms
13517680Spststruct printer {
136127675Sbms	if_printer f;
13717680Spst	int type;
13817680Spst};
13917680Spst
14017680Spststatic struct printer printers[] = {
14198527Sfenner	{ arcnet_if_print,	DLT_ARCNET },
142127675Sbms#ifdef DLT_ARCNET_LINUX
143127675Sbms	{ arcnet_linux_if_print, DLT_ARCNET_LINUX },
144127675Sbms#endif
14517680Spst	{ ether_if_print,	DLT_EN10MB },
14644165Sjulian	{ token_if_print,	DLT_IEEE802 },
14756896Sfenner#ifdef DLT_LANE8023
14856896Sfenner	{ lane_if_print,        DLT_LANE8023 },
14956896Sfenner#endif
15056896Sfenner#ifdef DLT_CIP
15156896Sfenner	{ cip_if_print,         DLT_CIP },
15256896Sfenner#endif
15375118Sfenner#ifdef DLT_ATM_CLIP
15475118Sfenner	{ cip_if_print,         DLT_ATM_CLIP },
15575118Sfenner#endif
15617680Spst	{ sl_if_print,		DLT_SLIP },
157127675Sbms#ifdef DLT_SLIP_BSDOS
15839297Sfenner	{ sl_bsdos_if_print,	DLT_SLIP_BSDOS },
159127675Sbms#endif
16017680Spst	{ ppp_if_print,		DLT_PPP },
161146778Ssam#ifdef DLT_PPP_WITHDIRECTION
162146778Ssam	{ ppp_if_print,		DLT_PPP_WITHDIRECTION },
163146778Ssam#endif
164127675Sbms#ifdef DLT_PPP_BSDOS
16539297Sfenner	{ ppp_bsdos_if_print,	DLT_PPP_BSDOS },
166127675Sbms#endif
16717680Spst	{ fddi_if_print,	DLT_FDDI },
16817680Spst	{ null_if_print,	DLT_NULL },
16975118Sfenner#ifdef DLT_LOOP
17075118Sfenner	{ null_if_print,	DLT_LOOP },
17175118Sfenner#endif
17239297Sfenner	{ raw_if_print,		DLT_RAW },
17317680Spst	{ atm_if_print,		DLT_ATM_RFC1483 },
17475118Sfenner#ifdef DLT_C_HDLC
17575118Sfenner	{ chdlc_if_print,	DLT_C_HDLC },
17656896Sfenner#endif
17798527Sfenner#ifdef DLT_HDLC
17898527Sfenner	{ chdlc_if_print,	DLT_HDLC },
17998527Sfenner#endif
18075118Sfenner#ifdef DLT_PPP_SERIAL
18175118Sfenner	{ ppp_hdlc_if_print,    DLT_PPP_SERIAL },
18275118Sfenner#endif
18398527Sfenner#ifdef DLT_PPP_ETHER
18498527Sfenner	{ pppoe_if_print,	DLT_PPP_ETHER },
18598527Sfenner#endif
18675118Sfenner#ifdef DLT_LINUX_SLL
18775118Sfenner	{ sll_if_print,		DLT_LINUX_SLL },
18875118Sfenner#endif
18998527Sfenner#ifdef DLT_IEEE802_11
19098527Sfenner	{ ieee802_11_if_print,	DLT_IEEE802_11},
19198527Sfenner#endif
19298527Sfenner#ifdef DLT_LTALK
19398527Sfenner	{ ltalk_if_print,	DLT_LTALK },
19498527Sfenner#endif
195127675Sbms#ifdef DLT_PFLOG
196127675Sbms	{ pflog_if_print, 	DLT_PFLOG },
197127675Sbms#endif
198127675Sbms#ifdef DLT_FR
199127675Sbms	{ fr_if_print,		DLT_FR },
200127675Sbms#endif
201127675Sbms#ifdef DLT_FRELAY
202127675Sbms	{ fr_if_print,		DLT_FRELAY },
203127675Sbms#endif
204127675Sbms#ifdef DLT_SUNATM
205127675Sbms	{ sunatm_if_print,	DLT_SUNATM },
206127675Sbms#endif
207127675Sbms#ifdef DLT_IP_OVER_FC
208127675Sbms	{ ipfc_if_print,	DLT_IP_OVER_FC },
209127675Sbms#endif
210127675Sbms#ifdef DLT_PRISM_HEADER
211127675Sbms	{ prism_if_print,	DLT_PRISM_HEADER },
212127675Sbms#endif
213127675Sbms#ifdef DLT_IEEE802_11_RADIO
214127675Sbms	{ ieee802_11_radio_if_print,	DLT_IEEE802_11_RADIO },
215127675Sbms#endif
216127675Sbms#ifdef DLT_ENC
217127675Sbms	{ enc_if_print, 	DLT_ENC },
218127675Sbms#endif
219146778Ssam#ifdef DLT_SYMANTEC_FIREWALL
220146778Ssam	{ symantec_if_print, 	DLT_SYMANTEC_FIREWALL },
221146778Ssam#endif
222127675Sbms#ifdef DLT_APPLE_IP_OVER_IEEE1394
223127675Sbms	{ ap1394_if_print,	DLT_APPLE_IP_OVER_IEEE1394 },
224127675Sbms#endif
225146778Ssam#ifdef DLT_JUNIPER_ATM1
226146778Ssam	{ juniper_atm1_print,	DLT_JUNIPER_ATM1 },
227146778Ssam#endif
228146778Ssam#ifdef DLT_JUNIPER_ATM2
229146778Ssam	{ juniper_atm2_print,	DLT_JUNIPER_ATM2 },
230146778Ssam#endif
231146778Ssam#ifdef DLT_JUNIPER_MLFR
232146778Ssam	{ juniper_mlfr_print,	DLT_JUNIPER_MLFR },
233146778Ssam#endif
234146778Ssam#ifdef DLT_JUNIPER_MLPPP
235146778Ssam	{ juniper_mlppp_print,	DLT_JUNIPER_MLPPP },
236146778Ssam#endif
23717680Spst	{ NULL,			0 },
23817680Spst};
23917680Spst
240127675Sbmsstatic if_printer
24117680Spstlookup_printer(int type)
24217680Spst{
24317680Spst	struct printer *p;
24417680Spst
24517680Spst	for (p = printers; p->f; ++p)
24617680Spst		if (type == p->type)
24717680Spst			return p->f;
24817680Spst
249127675Sbms	return NULL;
25017680Spst	/* NOTREACHED */
25117680Spst}
25217680Spst
25317680Spststatic pcap_t *pd;
25417680Spst
25517680Spstextern int optind;
25617680Spstextern int opterr;
25717680Spstextern char *optarg;
25817680Spst
259127675Sbmsstruct print_info {
260127675Sbms	if_printer printer;
261127675Sbms};
262127675Sbms
26398527Sfennerstruct dump_info {
26498527Sfenner	char	*WFileName;
26598527Sfenner	pcap_t	*pd;
26698527Sfenner	pcap_dumper_t *p;
26798527Sfenner};
26898527Sfenner
269109842Sfennerstatic void
270109842Sfennershow_dlts_and_exit(pcap_t *pd)
271109842Sfenner{
272127675Sbms	int n_dlts;
273109842Sfenner	int *dlts = 0;
274127675Sbms	const char *dlt_name;
275127675Sbms
276109842Sfenner	n_dlts = pcap_list_datalinks(pd, &dlts);
277109842Sfenner	if (n_dlts < 0)
278109842Sfenner		error("%s", pcap_geterr(pd));
279109842Sfenner	else if (n_dlts == 0 || !dlts)
280109842Sfenner		error("No data link types.");
281109842Sfenner
282127675Sbms	(void) fprintf(stderr, "Data link types (use option -y to set):\n");
283109842Sfenner
284109842Sfenner	while (--n_dlts >= 0) {
285127675Sbms		dlt_name = pcap_datalink_val_to_name(dlts[n_dlts]);
286127675Sbms		if (dlt_name != NULL) {
287127675Sbms			(void) fprintf(stderr, "  %s (%s)", dlt_name,
288127675Sbms			    pcap_datalink_val_to_description(dlts[n_dlts]));
289127675Sbms
290127675Sbms			/*
291127675Sbms			 * OK, does tcpdump handle that type?
292127675Sbms			 */
293127675Sbms			if (lookup_printer(dlts[n_dlts]) == NULL)
294127675Sbms				(void) fprintf(stderr, " (not supported)");
295127675Sbms			putchar('\n');
296127675Sbms		} else {
297127675Sbms			(void) fprintf(stderr, "  DLT %d (not supported)\n",
298127675Sbms			    dlts[n_dlts]);
299109842Sfenner		}
300109842Sfenner	}
301109842Sfenner	free(dlts);
302109842Sfenner	exit(0);
303109842Sfenner}
304109842Sfenner
305127675Sbms/*
306127675Sbms * Set up flags that might or might not be supported depending on the
307127675Sbms * version of libpcap we're using.
308127675Sbms */
309127675Sbms#ifdef WIN32
310127675Sbms#define B_FLAG		"B:"
311127675Sbms#define B_FLAG_USAGE	" [ -B size ]"
312127675Sbms#else /* WIN32 */
313127675Sbms#define B_FLAG
314127675Sbms#define B_FLAG_USAGE
315127675Sbms#endif /* WIN32 */
316127675Sbms
317127675Sbms#ifdef HAVE_PCAP_FINDALLDEVS
318146778Ssam#ifndef HAVE_PCAP_IF_T
319146778Ssam#undef HAVE_PCAP_FINDALLDEVS
320146778Ssam#endif
321146778Ssam#endif
322146778Ssam
323146778Ssam#ifdef HAVE_PCAP_FINDALLDEVS
324127675Sbms#define D_FLAG	"D"
325127675Sbms#else
326127675Sbms#define D_FLAG
327127675Sbms#endif
328127675Sbms
329127675Sbms#ifdef HAVE_PCAP_DUMP_FLUSH
330127675Sbms#define U_FLAG	"U"
331127675Sbms#else
332127675Sbms#define U_FLAG
333127675Sbms#endif
334127675Sbms
335146778Ssam#ifndef WIN32
336146778Ssam/* Drop root privileges and chroot if necessary */
337146778Ssamstatic void
338146778Ssamdroproot(const char *username, const char *chroot_dir)
339146778Ssam{
340146778Ssam	struct passwd *pw = NULL;
341146778Ssam
342146778Ssam	if (chroot_dir && !username) {
343146778Ssam		fprintf(stderr, "tcpdump: Chroot without dropping root is insecure\n");
344146778Ssam		exit(1);
345146778Ssam	}
346146778Ssam
347146778Ssam	pw = getpwnam(username);
348146778Ssam	if (pw) {
349146778Ssam		if (chroot_dir) {
350146778Ssam			if (chroot(chroot_dir) != 0 || chdir ("/") != 0) {
351146778Ssam				fprintf(stderr, "tcpdump: Couldn't chroot/chdir to '%.64s': %s\n",
352146778Ssam				    chroot_dir, pcap_strerror(errno));
353146778Ssam				exit(1);
354146778Ssam			}
355146778Ssam		}
356146778Ssam		if (initgroups(pw->pw_name, pw->pw_gid) != 0 ||
357146778Ssam		    setgid(pw->pw_gid) != 0 || setuid(pw->pw_uid) != 0) {
358146778Ssam			fprintf(stderr, "tcpdump: Couldn't change to '%.32s' uid=%lu gid=%lu: %s\n",
359146778Ssam			    username,
360146778Ssam			    (unsigned long)pw->pw_uid,
361146778Ssam			    (unsigned long)pw->pw_gid,
362146778Ssam			    pcap_strerror(errno));
363146778Ssam			exit(1);
364146778Ssam		}
365146778Ssam	}
366146778Ssam	else {
367146778Ssam		fprintf(stderr, "tcpdump: Couldn't find user '%.32s'\n",
368146778Ssam		    username);
369146778Ssam		exit(1);
370146778Ssam	}
371146778Ssam}
372146778Ssam#endif /* WIN32 */
373146778Ssam
374146778Ssamstatic int
375146778SsamgetWflagChars(int x)
376146778Ssam{
377146778Ssam	int c = 0;
378146778Ssam
379146778Ssam	x -= 1;
380146778Ssam	while (x > 0) {
381146778Ssam		c += 1;
382146778Ssam		x /= 10;
383146778Ssam	}
384146778Ssam
385146778Ssam	return c;
386146778Ssam}
387146778Ssam
388146778Ssam
389146778Ssamstatic void
390146778SsamMakeFilename(char *buffer, char *orig_name, int cnt, int max_chars)
391146778Ssam{
392146778Ssam	if (cnt == 0 && max_chars == 0)
393146778Ssam		strcpy(buffer, orig_name);
394146778Ssam	else
395146778Ssam		sprintf(buffer, "%s%0*d", orig_name, max_chars, cnt);
396146778Ssam}
397146778Ssam
398146778Ssamstatic int tcpdump_printf(netdissect_options *ndo _U_,
399146778Ssam			  const char *fmt, ...)
400146778Ssam{
401146778Ssam
402146778Ssam  va_list args;
403146778Ssam  int ret;
404146778Ssam
405146778Ssam  va_start(args, fmt);
406146778Ssam  ret=vfprintf(stdout, fmt, args);
407146778Ssam  va_end(args);
408146778Ssam
409146778Ssam  return ret;
410146778Ssam}
411146778Ssam
41217680Spstint
41317680Spstmain(int argc, char **argv)
41417680Spst{
41517680Spst	register int cnt, op, i;
41617680Spst	bpf_u_int32 localnet, netmask;
417146778Ssam	register char *cp, *infile, *cmdbuf, *device, *RFileName, *WFileName, *WFileNameAlt;
418127675Sbms	pcap_handler callback;
419127675Sbms	int type;
42017680Spst	struct bpf_program fcode;
421127675Sbms#ifndef WIN32
42239297Sfenner	RETSIGTYPE (*oldhandler)(int);
423127675Sbms#endif
424127675Sbms	struct print_info printinfo;
42598527Sfenner	struct dump_info dumpinfo;
42617680Spst	u_char *pcap_userdata;
42717680Spst	char ebuf[PCAP_ERRBUF_SIZE];
428146778Ssam	char *username = NULL;
429146778Ssam	char *chroot_dir = NULL;
430127675Sbms#ifdef HAVE_PCAP_FINDALLDEVS
431127675Sbms	pcap_if_t *devpointer;
432127675Sbms	int devnum;
433127675Sbms#endif
434127675Sbms	int status;
435127675Sbms#ifdef WIN32
436127675Sbms	u_int UserBufferSize = 1000000;
437127675Sbms	if(wsockinit() != 0) return 1;
438127675Sbms#endif /* WIN32 */
43917680Spst
440146778Ssam        gndo->ndo_Oflag=1;
441146778Ssam	gndo->ndo_Rflag=1;
442146778Ssam	gndo->ndo_dlt=-1;
443146778Ssam	gndo->ndo_default_print=ndo_default_print;
444146778Ssam	gndo->ndo_printf=tcpdump_printf;
445146778Ssam	gndo->ndo_error=ndo_error;
446146778Ssam	gndo->ndo_warning=ndo_warning;
447146778Ssam	gndo->ndo_snaplen = DEFAULT_SNAPLEN;
448146778Ssam
44917680Spst	cnt = -1;
45017680Spst	device = NULL;
45117680Spst	infile = NULL;
45217680Spst	RFileName = NULL;
45317680Spst	WFileName = NULL;
45417680Spst	if ((cp = strrchr(argv[0], '/')) != NULL)
45517680Spst		program_name = cp + 1;
45617680Spst	else
45717680Spst		program_name = argv[0];
45817680Spst
45975118Sfenner	if (abort_on_misalignment(ebuf, sizeof(ebuf)) < 0)
46026180Sfenner		error("%s", ebuf);
46117680Spst
46256896Sfenner#ifdef LIBSMI
46356896Sfenner	smiInit("tcpdump");
46456896Sfenner#endif
465127675Sbms
46617680Spst	opterr = 0;
46739297Sfenner	while (
468146778Ssam	    (op = getopt(argc, argv, "aA" B_FLAG "c:C:d" D_FLAG "eE:fF:i:lLm:M:nNOpqr:Rs:StT:u" U_FLAG "vw:W:xXy:YZ:")) != -1)
46917680Spst		switch (op) {
47039297Sfenner
47139297Sfenner		case 'a':
472127675Sbms			/* compatibility for old -a */
47339297Sfenner			break;
47439297Sfenner
475127675Sbms		case 'A':
476127675Sbms			++xflag;
477127675Sbms			++Xflag;
478127675Sbms			++Aflag;
479127675Sbms			break;
480127675Sbms
481127675Sbms#ifdef WIN32
482127675Sbms		case 'B':
483127675Sbms			UserBufferSize = atoi(optarg)*1024;
484127675Sbms			if (UserBufferSize < 0)
485127675Sbms				error("invalid packet buffer size %s", optarg);
486127675Sbms			break;
487127675Sbms#endif /* WIN32 */
488127675Sbms
48917680Spst		case 'c':
49017680Spst			cnt = atoi(optarg);
49117680Spst			if (cnt <= 0)
49217680Spst				error("invalid packet count %s", optarg);
49317680Spst			break;
49417680Spst
49598527Sfenner		case 'C':
49698527Sfenner			Cflag = atoi(optarg) * 1000000;
497127675Sbms			if (Cflag < 0)
49898527Sfenner				error("invalid file size %s", optarg);
49998527Sfenner			break;
50098527Sfenner
50117680Spst		case 'd':
50217680Spst			++dflag;
50317680Spst			break;
50417680Spst
505127675Sbms#ifdef HAVE_PCAP_FINDALLDEVS
506127675Sbms		case 'D':
507127675Sbms			if (pcap_findalldevs(&devpointer, ebuf) < 0)
508127675Sbms				error("%s", ebuf);
509127675Sbms			else {
510127675Sbms				for (i = 0; devpointer != 0; i++) {
511127675Sbms					printf("%d.%s", i+1, devpointer->name);
512127675Sbms					if (devpointer->description != NULL)
513127675Sbms						printf(" (%s)", devpointer->description);
514127675Sbms					printf("\n");
515127675Sbms					devpointer = devpointer->next;
516127675Sbms				}
517127675Sbms			}
518127675Sbms			return 0;
519127675Sbms#endif /* HAVE_PCAP_FINDALLDEVS */
520127675Sbms
521109842Sfenner		case 'L':
522109842Sfenner			Lflag++;
523109842Sfenner			break;
524109842Sfenner
52517680Spst		case 'e':
52617680Spst			++eflag;
52717680Spst			break;
52817680Spst
52956896Sfenner		case 'E':
53075118Sfenner#ifndef HAVE_LIBCRYPTO
53156896Sfenner			warning("crypto code not compiled in");
53256896Sfenner#endif
533146778Ssam			gndo->ndo_espsecret = optarg;
53456896Sfenner			break;
53556896Sfenner
53617680Spst		case 'f':
53717680Spst			++fflag;
53817680Spst			break;
53917680Spst
54017680Spst		case 'F':
54117680Spst			infile = optarg;
54217680Spst			break;
54317680Spst
54417680Spst		case 'i':
545127675Sbms			if (optarg[0] == '0' && optarg[1] == 0)
546127675Sbms				error("Invalid adapter index");
547127675Sbms
548127675Sbms#ifdef HAVE_PCAP_FINDALLDEVS
549127675Sbms			/*
550127675Sbms			 * If the argument is a number, treat it as
551127675Sbms			 * an index into the list of adapters, as
552127675Sbms			 * printed by "tcpdump -D".
553127675Sbms			 *
554127675Sbms			 * This should be OK on UNIX systems, as interfaces
555127675Sbms			 * shouldn't have names that begin with digits.
556127675Sbms			 * It can be useful on Windows, where more than
557127675Sbms			 * one interface can have the same name.
558127675Sbms			 */
559127675Sbms			if ((devnum = atoi(optarg)) != 0) {
560127675Sbms				if (devnum < 0)
561127675Sbms					error("Invalid adapter index");
562127675Sbms
563127675Sbms				if (pcap_findalldevs(&devpointer, ebuf) < 0)
564127675Sbms					error("%s", ebuf);
565127675Sbms				else {
566127675Sbms					for (i = 0; i < devnum-1; i++){
567127675Sbms						devpointer = devpointer->next;
568127675Sbms						if (devpointer == NULL)
569127675Sbms							error("Invalid adapter index");
570127675Sbms					}
571127675Sbms				}
572127675Sbms				device = devpointer->name;
573127675Sbms				break;
574127675Sbms			}
575127675Sbms#endif /* HAVE_PCAP_FINDALLDEVS */
57617680Spst			device = optarg;
57717680Spst			break;
57817680Spst
57917680Spst		case 'l':
580127675Sbms#ifdef WIN32
581127675Sbms			/*
582127675Sbms			 * _IOLBF is the same as _IOFBF in Microsoft's C
583127675Sbms			 * libraries; the only alternative they offer
584127675Sbms			 * is _IONBF.
585127675Sbms			 *
586127675Sbms			 * XXX - this should really be checking for MSVC++,
587127675Sbms			 * not WIN32, if, for example, MinGW has its own
588127675Sbms			 * C library that is more UNIX-compatible.
589127675Sbms			 */
590127675Sbms			setvbuf(stdout, NULL, _IONBF, 0);
591127675Sbms#else /* WIN32 */
59217680Spst#ifdef HAVE_SETLINEBUF
59317680Spst			setlinebuf(stdout);
59417680Spst#else
59517680Spst			setvbuf(stdout, NULL, _IOLBF, 0);
59617680Spst#endif
597127675Sbms#endif /* WIN32 */
59817680Spst			break;
59917680Spst
60017680Spst		case 'n':
60117680Spst			++nflag;
60217680Spst			break;
60317680Spst
60417680Spst		case 'N':
60517680Spst			++Nflag;
60617680Spst			break;
60717680Spst
60856896Sfenner		case 'm':
60956896Sfenner#ifdef LIBSMI
61056896Sfenner		        if (smiLoadModule(optarg) == 0) {
61156896Sfenner				error("could not load MIB module %s", optarg);
61256896Sfenner		        }
61356896Sfenner			sflag = 1;
61456896Sfenner#else
61556896Sfenner			(void)fprintf(stderr, "%s: ignoring option `-m %s' ",
61656896Sfenner				      program_name, optarg);
61756896Sfenner			(void)fprintf(stderr, "(no libsmi support)\n");
61856896Sfenner#endif
619127675Sbms			break;
620127675Sbms
621146778Ssam		case 'M':
622146778Ssam			/* TCP-MD5 shared secret */
623146778Ssam#ifndef HAVE_LIBCRYPTO
624146778Ssam			warning("crypto code not compiled in");
625146778Ssam#endif
626146778Ssam			tcpmd5secret = optarg;
627146778Ssam			break;
628146778Ssam
62917680Spst		case 'O':
63017680Spst			Oflag = 0;
63117680Spst			break;
63217680Spst
63317680Spst		case 'p':
63417680Spst			++pflag;
63517680Spst			break;
63617680Spst
63717680Spst		case 'q':
63817680Spst			++qflag;
63917680Spst			break;
64017680Spst
64117680Spst		case 'r':
64217680Spst			RFileName = optarg;
64317680Spst			break;
64417680Spst
64556896Sfenner		case 'R':
64656896Sfenner			Rflag = 0;
64756896Sfenner			break;
64856896Sfenner
64975118Sfenner		case 's': {
65075118Sfenner			char *end;
65175118Sfenner
65275118Sfenner			snaplen = strtol(optarg, &end, 0);
65375118Sfenner			if (optarg == end || *end != '\0'
65475118Sfenner			    || snaplen < 0 || snaplen > 65535)
65517680Spst				error("invalid snaplen %s", optarg);
65675118Sfenner			else if (snaplen == 0)
65775118Sfenner				snaplen = 65535;
65817680Spst			break;
65975118Sfenner		}
66017680Spst
66117680Spst		case 'S':
66217680Spst			++Sflag;
66317680Spst			break;
66417680Spst
66517680Spst		case 't':
666146778Ssam			++tflag;
66717680Spst			break;
66817680Spst
66917680Spst		case 'T':
67017680Spst			if (strcasecmp(optarg, "vat") == 0)
67117680Spst				packettype = PT_VAT;
67217680Spst			else if (strcasecmp(optarg, "wb") == 0)
67317680Spst				packettype = PT_WB;
67417680Spst			else if (strcasecmp(optarg, "rpc") == 0)
67517680Spst				packettype = PT_RPC;
67617680Spst			else if (strcasecmp(optarg, "rtp") == 0)
67717680Spst				packettype = PT_RTP;
67817680Spst			else if (strcasecmp(optarg, "rtcp") == 0)
67917680Spst				packettype = PT_RTCP;
68056896Sfenner			else if (strcasecmp(optarg, "snmp") == 0)
68156896Sfenner				packettype = PT_SNMP;
68275118Sfenner			else if (strcasecmp(optarg, "cnfp") == 0)
68375118Sfenner				packettype = PT_CNFP;
684127675Sbms			else if (strcasecmp(optarg, "tftp") == 0)
685127675Sbms				packettype = PT_TFTP;
686127675Sbms			else if (strcasecmp(optarg, "aodv") == 0)
687127675Sbms				packettype = PT_AODV;
68817680Spst			else
68917680Spst				error("unknown packet type `%s'", optarg);
69017680Spst			break;
69117680Spst
69275118Sfenner		case 'u':
69375118Sfenner			++uflag;
69475118Sfenner			break;
695127675Sbms
696127675Sbms#ifdef HAVE_PCAP_DUMP_FLUSH
697127675Sbms		case 'U':
698127675Sbms			++Uflag;
699127675Sbms			break;
700127675Sbms#endif
701127675Sbms
70217680Spst		case 'v':
70317680Spst			++vflag;
70417680Spst			break;
70517680Spst
70617680Spst		case 'w':
70717680Spst			WFileName = optarg;
70817680Spst			break;
70956896Sfenner
710146778Ssam		case 'W':
711146778Ssam			Wflag = atoi(optarg);
712146778Ssam			if (Wflag < 0)
713146778Ssam				error("invalid number of output files %s", optarg);
714146778Ssam			WflagChars = getWflagChars(Wflag);
715146778Ssam			break;
716146778Ssam
71756896Sfenner		case 'x':
71856896Sfenner			++xflag;
71956896Sfenner			break;
72056896Sfenner
72156896Sfenner		case 'X':
72256896Sfenner			++Xflag;
72356896Sfenner			break;
72456896Sfenner
725109842Sfenner		case 'y':
726146778Ssam			gndo->ndo_dltname = optarg;
727146778Ssam			gndo->ndo_dlt =
728146778Ssam			  pcap_datalink_name_to_val(gndo->ndo_dltname);
729146778Ssam			if (gndo->ndo_dlt < 0)
730146778Ssam				error("invalid data link type %s", gndo->ndo_dltname);
731109842Sfenner			break;
732109842Sfenner
733127675Sbms#if defined(HAVE_PCAP_DEBUG) || defined(HAVE_YYDEBUG)
73417680Spst		case 'Y':
73517680Spst			{
73617680Spst			/* Undocumented flag */
737127675Sbms#ifdef HAVE_PCAP_DEBUG
738127675Sbms			extern int pcap_debug;
739127675Sbms			pcap_debug = 1;
740127675Sbms#else
74117680Spst			extern int yydebug;
74217680Spst			yydebug = 1;
743127675Sbms#endif
74417680Spst			}
74517680Spst			break;
74617680Spst#endif
747146778Ssam		case 'Z':
748146778Ssam			if (optarg) {
749146778Ssam				username = strdup(optarg);
750146778Ssam			}
751146778Ssam			else {
752146778Ssam				usage();
753146778Ssam				/* NOTREACHED */
754146778Ssam			}
755146778Ssam			break;
756146778Ssam
75717680Spst		default:
75817680Spst			usage();
75917680Spst			/* NOTREACHED */
76017680Spst		}
76117680Spst
762146778Ssam	switch (tflag) {
763146778Ssam
764146778Ssam	case 0: /* Default */
765146778Ssam	case 4: /* Default + Date*/
76639297Sfenner		thiszone = gmt2local(0);
767146778Ssam		break;
76817680Spst
769146778Ssam	case 1: /* No time stamp */
770146778Ssam	case 2: /* Unix timeval style */
771146778Ssam	case 3: /* Microseconds since previous packet */
772146778Ssam		break;
773146778Ssam
774146778Ssam	default: /* Not supported */
775146778Ssam		error("only -t, -tt, -ttt, and -tttt are supported");
776146778Ssam		break;
777146778Ssam	}
778146778Ssam
779146778Ssam#ifdef WITH_CHROOT
780146778Ssam	/* if run as root, prepare for chrooting */
781146778Ssam	if (getuid() == 0 || geteuid() == 0) {
782146778Ssam		/* future extensibility for cmd-line arguments */
783146778Ssam		if (!chroot_dir)
784146778Ssam			chroot_dir = WITH_CHROOT;
785146778Ssam	}
786146778Ssam#endif
787146778Ssam
788146778Ssam#ifdef WITH_USER
789146778Ssam	/* if run as root, prepare for dropping root privileges */
790146778Ssam	if (getuid() == 0 || geteuid() == 0) {
791146778Ssam		/* Run with '-Z root' to restore old behaviour */
792146778Ssam		if (!username)
793146778Ssam			username = WITH_USER;
794146778Ssam	}
795146778Ssam#endif
796146778Ssam
79717680Spst	if (RFileName != NULL) {
798127675Sbms		int dlt;
799127675Sbms		const char *dlt_name;
800127675Sbms
801127675Sbms#ifndef WIN32
80217680Spst		/*
803127675Sbms		 * We don't need network access, so relinquish any set-UID
804127675Sbms		 * or set-GID privileges we have (if any).
805127675Sbms		 *
806127675Sbms		 * We do *not* want set-UID privileges when opening a
807127675Sbms		 * trace file, as that might let the user read other
808127675Sbms		 * people's trace files (especially if we're set-UID
809127675Sbms		 * root).
81017680Spst		 */
811146778Ssam		if (setgid(getgid()) != 0 || setuid(getuid()) != 0 )
812146778Ssam			fprintf(stderr, "Warning: setgid/setuid failed !\n");
813127675Sbms#endif /* WIN32 */
81417680Spst		pd = pcap_open_offline(RFileName, ebuf);
81517680Spst		if (pd == NULL)
81626180Sfenner			error("%s", ebuf);
817127675Sbms		dlt = pcap_datalink(pd);
818127675Sbms		dlt_name = pcap_datalink_val_to_name(dlt);
819127675Sbms		if (dlt_name == NULL) {
820127675Sbms			fprintf(stderr, "reading from file %s, link-type %u\n",
821127675Sbms			    RFileName, dlt);
822127675Sbms		} else {
823127675Sbms			fprintf(stderr,
824127675Sbms			    "reading from file %s, link-type %s (%s)\n",
825127675Sbms			    RFileName, dlt_name,
826127675Sbms			    pcap_datalink_val_to_description(dlt));
827127675Sbms		}
82817680Spst		localnet = 0;
82917680Spst		netmask = 0;
83017680Spst		if (fflag != 0)
83117680Spst			error("-f and -r options are incompatible");
83217680Spst	} else {
83317680Spst		if (device == NULL) {
83417680Spst			device = pcap_lookupdev(ebuf);
83517680Spst			if (device == NULL)
83626180Sfenner				error("%s", ebuf);
83717680Spst		}
838127675Sbms#ifdef WIN32
839146778Ssam		if(strlen(device) == 1)	//we assume that an ASCII string is always longer than 1 char
840146778Ssam		{						//a Unicode string has a \0 as second byte (so strlen() is 1)
841127675Sbms			fprintf(stderr, "%s: listening on %ws\n", program_name, device);
842127675Sbms		}
843127675Sbms		else
844127675Sbms		{
845127675Sbms			fprintf(stderr, "%s: listening on %s\n", program_name, device);
846127675Sbms		}
847127675Sbms
848127675Sbms		fflush(stderr);
849127675Sbms#endif /* WIN32 */
85098527Sfenner		*ebuf = '\0';
85117680Spst		pd = pcap_open_live(device, snaplen, !pflag, 1000, ebuf);
85217680Spst		if (pd == NULL)
85326180Sfenner			error("%s", ebuf);
85498527Sfenner		else if (*ebuf)
85598527Sfenner			warning("%s", ebuf);
856146778Ssam		/*
857146778Ssam		 * Let user own process after socket has been opened.
858146778Ssam		 */
859146778Ssam#ifndef WIN32
860146778Ssam		if (setgid(getgid()) != 0 || setuid(getuid()) != 0)
861146778Ssam			fprintf(stderr, "Warning: setgid/setuid failed !\n");
862146778Ssam#endif /* WIN32 */
863146778Ssam#ifdef WIN32
864146778Ssam		if(UserBufferSize != 1000000)
865146778Ssam			if(pcap_setbuff(pd, UserBufferSize)==-1){
866146778Ssam				error("%s", pcap_geterr(pd));
867146778Ssam			}
868146778Ssam#endif /* WIN32 */
869127675Sbms		if (Lflag)
870109842Sfenner			show_dlts_and_exit(pd);
871146778Ssam		if (gndo->ndo_dlt >= 0) {
872127675Sbms#ifdef HAVE_PCAP_SET_DATALINK
873146778Ssam			if (pcap_set_datalink(pd, gndo->ndo_dlt) < 0)
874109842Sfenner				error("%s", pcap_geterr(pd));
875127675Sbms#else
876127675Sbms			/*
877127675Sbms			 * We don't actually support changing the
878127675Sbms			 * data link type, so we only let them
879127675Sbms			 * set it to what it already is.
880127675Sbms			 */
881146778Ssam			if (gndo->ndo_dlt != pcap_datalink(pd)) {
882127675Sbms				error("%s is not one of the DLTs supported by this device\n",
883146778Ssam				      gndo->ndo_dltname);
884127675Sbms			}
885127675Sbms#endif
886109842Sfenner			(void)fprintf(stderr, "%s: data link type %s\n",
887146778Ssam			              program_name, gndo->ndo_dltname);
888109842Sfenner			(void)fflush(stderr);
889109842Sfenner		}
89017680Spst		i = pcap_snapshot(pd);
89117680Spst		if (snaplen < i) {
89217680Spst			warning("snaplen raised from %d to %d", snaplen, i);
89317680Spst			snaplen = i;
89417680Spst		}
89539297Sfenner		if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
89639297Sfenner			localnet = 0;
89739297Sfenner			netmask = 0;
89839297Sfenner			warning("%s", ebuf);
89939297Sfenner		}
90017680Spst	}
90117680Spst	if (infile)
90217680Spst		cmdbuf = read_infile(infile);
90317680Spst	else
90417680Spst		cmdbuf = copy_argv(&argv[optind]);
90517680Spst
90617680Spst	if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
90726180Sfenner		error("%s", pcap_geterr(pd));
90817680Spst	if (dflag) {
90917680Spst		bpf_dump(&fcode, dflag);
910127675Sbms		pcap_close(pd);
91117680Spst		exit(0);
91217680Spst	}
91339297Sfenner	init_addrtoname(localnet, netmask);
91417680Spst
915127675Sbms#ifndef WIN32
916127675Sbms	(void)setsignal(SIGPIPE, cleanup);
917127675Sbms#endif /* WIN32 */
91839297Sfenner	(void)setsignal(SIGTERM, cleanup);
91939297Sfenner	(void)setsignal(SIGINT, cleanup);
92039297Sfenner	/* Cooperate with nohup(1) */
921127675Sbms#ifndef WIN32
92239297Sfenner	if ((oldhandler = setsignal(SIGHUP, cleanup)) != SIG_DFL)
92339297Sfenner		(void)setsignal(SIGHUP, oldhandler);
924127675Sbms#endif /* WIN32 */
92517680Spst
92617680Spst	if (pcap_setfilter(pd, &fcode) < 0)
92726180Sfenner		error("%s", pcap_geterr(pd));
92817680Spst	if (WFileName) {
929146778Ssam		pcap_dumper_t *p;
930146778Ssam
931146778Ssam		WFileNameAlt = (char *)malloc(strlen(WFileName) + MAX_CFLAG_CHARS + 1);
932146778Ssam		if (WFileNameAlt == NULL)
933146778Ssam			error("malloc of WFileNameAlt");
934146778Ssam		MakeFilename(WFileNameAlt, WFileName, 0, WflagChars);
935146778Ssam		p = pcap_dump_open(pd, WFileNameAlt);
93617680Spst		if (p == NULL)
93726180Sfenner			error("%s", pcap_geterr(pd));
93898527Sfenner		if (Cflag != 0) {
939127675Sbms			callback = dump_packet_and_trunc;
94098527Sfenner			dumpinfo.WFileName = WFileName;
94198527Sfenner			dumpinfo.pd = pd;
94298527Sfenner			dumpinfo.p = p;
94398527Sfenner			pcap_userdata = (u_char *)&dumpinfo;
94498527Sfenner		} else {
945127675Sbms			callback = dump_packet;
94698527Sfenner			pcap_userdata = (u_char *)p;
94798527Sfenner		}
94817680Spst	} else {
949127675Sbms		type = pcap_datalink(pd);
950127675Sbms		printinfo.printer = lookup_printer(type);
951127675Sbms		if (printinfo.printer == NULL) {
952146778Ssam			gndo->ndo_dltname = pcap_datalink_val_to_name(type);
953146778Ssam			if (gndo->ndo_dltname != NULL)
954146778Ssam				error("unsupported data link type %s",
955146778Ssam				      gndo->ndo_dltname);
956127675Sbms			else
957127675Sbms				error("unsupported data link type %d", type);
958127675Sbms		}
959127675Sbms		callback = print_packet;
960127675Sbms		pcap_userdata = (u_char *)&printinfo;
961127675Sbms	}
962146778Ssam#ifndef WIN32
963146778Ssam	/*
964146778Ssam	 * We cannot do this earlier, because we want to be able to open
965146778Ssam	 * the file (if done) for writing before giving up permissions.
966146778Ssam	 */
967146778Ssam	if (getuid() == 0 || geteuid() == 0) {
968146778Ssam		if (username || chroot_dir)
969146778Ssam			droproot(username, chroot_dir);
970146778Ssam	}
971146778Ssam#endif /* WIN32 */
97298527Sfenner#ifdef SIGINFO
973127675Sbms	(void)setsignal(SIGINFO, requestinfo);
97498527Sfenner#endif
975146778Ssam
976146778Ssam	if (vflag > 0 && WFileName) {
977146778Ssam		/*
978146778Ssam		 * When capturing to a file, "-v" means tcpdump should,
979146778Ssam		 * every 10 secodns, "v"erbosely report the number of
980146778Ssam		 * packets captured.
981146778Ssam		 */
982146778Ssam#ifdef USE_WIN32_MM_TIMER
983146778Ssam		/* call verbose_stats_dump() each 1000 +/-100msec */
984146778Ssam		timer_id = timeSetEvent(1000, 100, verbose_stats_dump, 0, TIME_PERIODIC);
985146778Ssam		setvbuf(stderr, NULL, _IONBF, 0);
986146778Ssam#elif defined(HAVE_ALARM)
987146778Ssam		(void)setsignal(SIGALRM, verbose_stats_dump);
988146778Ssam		alarm(1);
989146778Ssam#endif
990146778Ssam	}
991146778Ssam
992127675Sbms#ifndef WIN32
99317680Spst	if (RFileName == NULL) {
994127675Sbms		int dlt;
995127675Sbms		const char *dlt_name;
996127675Sbms
997127675Sbms		if (!vflag && !WFileName) {
998127675Sbms			(void)fprintf(stderr,
999127675Sbms			    "%s: verbose output suppressed, use -v or -vv for full protocol decode\n",
1000127675Sbms			    program_name);
1001127675Sbms		} else
1002127675Sbms			(void)fprintf(stderr, "%s: ", program_name);
1003127675Sbms		dlt = pcap_datalink(pd);
1004127675Sbms		dlt_name = pcap_datalink_val_to_name(dlt);
1005127675Sbms		if (dlt_name == NULL) {
1006127675Sbms			(void)fprintf(stderr, "listening on %s, link-type %u, capture size %u bytes\n",
1007127675Sbms			    device, dlt, snaplen);
1008127675Sbms		} else {
1009127675Sbms			(void)fprintf(stderr, "listening on %s, link-type %s (%s), capture size %u bytes\n",
1010127675Sbms			    device, dlt_name,
1011127675Sbms			    pcap_datalink_val_to_description(dlt), snaplen);
1012127675Sbms		}
101317680Spst		(void)fflush(stderr);
101417680Spst	}
1015127675Sbms#endif /* WIN32 */
1016127675Sbms	status = pcap_loop(pd, cnt, callback, pcap_userdata);
1017127675Sbms	if (WFileName == NULL) {
1018127675Sbms		/*
1019127675Sbms		 * We're printing packets.  Flush the printed output,
1020127675Sbms		 * so it doesn't get intermingled with error output.
1021127675Sbms		 */
1022127675Sbms		if (status == -2) {
1023127675Sbms			/*
1024127675Sbms			 * We got interrupted, so perhaps we didn't
1025127675Sbms			 * manage to finish a line we were printing.
1026127675Sbms			 * Print an extra newline, just in case.
1027127675Sbms			 */
1028127675Sbms			putchar('\n');
1029127675Sbms		}
1030127675Sbms		(void)fflush(stdout);
1031127675Sbms	}
1032127675Sbms	if (status == -1) {
1033127675Sbms		/*
1034127675Sbms		 * Error.  Report it.
1035127675Sbms		 */
103617680Spst		(void)fprintf(stderr, "%s: pcap_loop: %s\n",
103717680Spst		    program_name, pcap_geterr(pd));
103817680Spst	}
1039127675Sbms	if (RFileName == NULL) {
1040127675Sbms		/*
1041127675Sbms		 * We're doing a live capture.  Report the capture
1042127675Sbms		 * statistics.
1043127675Sbms		 */
104498527Sfenner		info(1);
1045127675Sbms	}
104617680Spst	pcap_close(pd);
1047127675Sbms	exit(status == -1 ? 1 : 0);
104817680Spst}
104917680Spst
105017680Spst/* make a clean exit on interrupts */
105175118Sfennerstatic RETSIGTYPE
1052127675Sbmscleanup(int signo _U_)
105317680Spst{
1054146778Ssam#ifdef USE_WIN32_MM_TIMER
1055146778Ssam	if (timer_id)
1056146778Ssam		timeKillEvent(timer_id);
1057146778Ssam	timer_id = 0;
1058146778Ssam#elif defined(HAVE_ALARM)
1059146778Ssam	alarm(0);
1060146778Ssam#endif
1061146778Ssam
1062127675Sbms#ifdef HAVE_PCAP_BREAKLOOP
1063127675Sbms	/*
1064127675Sbms	 * We have "pcap_breakloop()"; use it, so that we do as little
1065127675Sbms	 * as possible in the signal handler (it's probably not safe
1066127675Sbms	 * to do anything with standard I/O streams in a signal handler -
1067127675Sbms	 * the ANSI C standard doesn't say it is).
1068127675Sbms	 */
1069127675Sbms	pcap_breakloop(pd);
1070127675Sbms#else
1071127675Sbms	/*
1072127675Sbms	 * We don't have "pcap_breakloop()"; this isn't safe, but
1073127675Sbms	 * it's the best we can do.  Print the summary if we're
1074127675Sbms	 * not reading from a savefile - i.e., if we're doing a
1075127675Sbms	 * live capture - and exit.
1076127675Sbms	 */
107717680Spst	if (pd != NULL && pcap_file(pd) == NULL) {
1078127675Sbms		/*
1079127675Sbms		 * We got interrupted, so perhaps we didn't
1080127675Sbms		 * manage to finish a line we were printing.
1081127675Sbms		 * Print an extra newline, just in case.
1082127675Sbms		 */
1083127675Sbms		putchar('\n');
108417680Spst		(void)fflush(stdout);
108598527Sfenner		info(1);
108617680Spst	}
108717680Spst	exit(0);
1088127675Sbms#endif
108917680Spst}
109017680Spst
1091127675Sbmsstatic void
109298527Sfennerinfo(register int verbose)
109398527Sfenner{
109498527Sfenner	struct pcap_stat stat;
109598527Sfenner
109698527Sfenner	if (pcap_stats(pd, &stat) < 0) {
109798527Sfenner		(void)fprintf(stderr, "pcap_stats: %s\n", pcap_geterr(pd));
109898527Sfenner		return;
109998527Sfenner	}
1100127675Sbms
110198527Sfenner	if (!verbose)
110298527Sfenner		fprintf(stderr, "%s: ", program_name);
1103127675Sbms
1104127675Sbms	(void)fprintf(stderr, "%u packets captured", packets_captured);
1105127675Sbms	if (!verbose)
1106127675Sbms		fputs(", ", stderr);
1107127675Sbms	else
1108127675Sbms		putc('\n', stderr);
110998527Sfenner	(void)fprintf(stderr, "%d packets received by filter", stat.ps_recv);
111098527Sfenner	if (!verbose)
111198527Sfenner		fputs(", ", stderr);
111298527Sfenner	else
111398527Sfenner		putc('\n', stderr);
111498527Sfenner	(void)fprintf(stderr, "%d packets dropped by kernel\n", stat.ps_drop);
111598527Sfenner	infoprint = 0;
111698527Sfenner}
111798527Sfenner
111898527Sfennerstatic void
1119127675Sbmsdump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
112098527Sfenner{
1121127675Sbms	struct dump_info *dump_info;
112298527Sfenner	char *name;
112398527Sfenner
1124127675Sbms	++packets_captured;
1125127675Sbms
1126127675Sbms	++infodelay;
1127127675Sbms
1128127675Sbms	dump_info = (struct dump_info *)user;
1129127675Sbms
113098527Sfenner	/*
113198527Sfenner	 * XXX - this won't prevent capture files from getting
113298527Sfenner	 * larger than Cflag - the last packet written to the
113398527Sfenner	 * file could put it over Cflag.
113498527Sfenner	 */
1135127675Sbms	if (ftell((FILE *)dump_info->p) > Cflag) {
1136127675Sbms		/*
1137127675Sbms		 * Close the current file and open a new one.
1138127675Sbms		 */
1139127675Sbms		pcap_dump_close(dump_info->p);
1140146778Ssam		Cflag_count++;
1141146778Ssam		if (Wflag > 0) {
1142146778Ssam			if (Cflag_count >= Wflag)
1143146778Ssam				Cflag_count = 0;
1144146778Ssam		} else {
1145146778Ssam			if (Cflag_count >= MAX_CFLAG)
1146146778Ssam				error("too many output files");
1147146778Ssam		}
1148146778Ssam		name = (char *)malloc(strlen(dump_info->WFileName) + MAX_CFLAG_CHARS + 1);
114998527Sfenner		if (name == NULL)
1150127675Sbms			error("dump_packet_and_trunc: malloc");
1151146778Ssam		MakeFilename(name, dump_info->WFileName, Cflag_count, WflagChars);
1152127675Sbms		dump_info->p = pcap_dump_open(dump_info->pd, name);
115398527Sfenner		free(name);
1154127675Sbms		if (dump_info->p == NULL)
115598527Sfenner			error("%s", pcap_geterr(pd));
115698527Sfenner	}
115798527Sfenner
1158127675Sbms	pcap_dump((u_char *)dump_info->p, h, sp);
1159127675Sbms#ifdef HAVE_PCAP_DUMP_FLUSH
1160127675Sbms	if (Uflag)
1161127675Sbms		pcap_dump_flush(dump_info->p);
1162127675Sbms#endif
1163127675Sbms
1164127675Sbms	--infodelay;
1165127675Sbms	if (infoprint)
1166127675Sbms		info(0);
116798527Sfenner}
116898527Sfenner
1169127675Sbmsstatic void
1170127675Sbmsdump_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
117117680Spst{
1172127675Sbms	++packets_captured;
117317680Spst
1174127675Sbms	++infodelay;
1175127675Sbms
1176127675Sbms	pcap_dump(user, h, sp);
1177127675Sbms#ifdef HAVE_PCAP_DUMP_FLUSH
1178127675Sbms	if (Uflag)
1179127675Sbms		pcap_dump_flush((pcap_dumper_t *)user);
1180127675Sbms#endif
1181127675Sbms
1182127675Sbms	--infodelay;
1183127675Sbms	if (infoprint)
1184127675Sbms		info(0);
1185127675Sbms}
1186127675Sbms
1187127675Sbmsstatic void
1188127675Sbmsprint_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
1189127675Sbms{
1190127675Sbms	struct print_info *print_info;
1191127675Sbms	u_int hdrlen;
1192127675Sbms
1193127675Sbms	++packets_captured;
1194127675Sbms
1195127675Sbms	++infodelay;
1196127675Sbms	ts_print(&h->ts);
1197127675Sbms
1198127675Sbms	print_info = (struct print_info *)user;
1199127675Sbms
1200127675Sbms	/*
1201127675Sbms	 * Some printers want to check that they're not walking off the
1202127675Sbms	 * end of the packet.
1203127675Sbms	 * Rather than pass it all the way down, we set this global.
1204127675Sbms	 */
1205127675Sbms	snapend = sp + h->caplen;
1206127675Sbms
1207127675Sbms	hdrlen = (*print_info->printer)(h, sp);
1208127675Sbms	if (xflag) {
1209127675Sbms		/*
1210127675Sbms		 * Print the raw packet data.
1211127675Sbms		 */
1212127675Sbms		if (xflag > 1) {
1213127675Sbms			/*
1214127675Sbms			 * Include the link-layer header.
1215127675Sbms			 */
1216146778Ssam			hex_print("\n\t", sp, h->caplen);
1217127675Sbms		} else {
1218127675Sbms			/*
1219127675Sbms			 * Don't include the link-layer header - and if
1220127675Sbms			 * we have nothing past the link-layer header,
1221127675Sbms			 * print nothing.
1222127675Sbms			 */
1223127675Sbms			if (h->caplen > hdrlen)
1224146778Ssam				hex_print("\n\t", sp + hdrlen,
1225127675Sbms				    h->caplen - hdrlen);
1226127675Sbms		}
1227146778Ssam       } else if (Xflag) {
1228146778Ssam		/*
1229146778Ssam		 * Print the raw packet data.
1230146778Ssam		 */
1231146778Ssam		if (Xflag > 1) {
1232146778Ssam			/*
1233146778Ssam			 * Include the link-layer header.
1234146778Ssam			 */
1235146778Ssam			ascii_print("\n\t", sp, h->caplen);
1236146778Ssam		} else {
1237146778Ssam			/*
1238146778Ssam			 * Don't include the link-layer header - and if
1239146778Ssam			 * we have nothing past the link-layer header,
1240146778Ssam			 * print nothing.
1241146778Ssam			 */
1242146778Ssam			if (h->caplen > hdrlen)
1243146778Ssam				ascii_print("\n\t", sp + hdrlen,
1244146778Ssam				    h->caplen - hdrlen);
1245146778Ssam		}
124617680Spst	}
1247127675Sbms
1248127675Sbms	putchar('\n');
1249127675Sbms
1250127675Sbms	--infodelay;
1251127675Sbms	if (infoprint)
1252127675Sbms		info(0);
125317680Spst}
125417680Spst
1255127675Sbms#ifdef WIN32
1256127675Sbms	/*
1257127675Sbms	 * XXX - there should really be libpcap calls to get the version
1258127675Sbms	 * number as a string (the string would be generated from #defines
1259127675Sbms	 * at run time, so that it's not generated from string constants
1260127675Sbms	 * in the library, as, on many UNIX systems, those constants would
1261127675Sbms	 * be statically linked into the application executable image, and
1262127675Sbms	 * would thus reflect the version of libpcap on the system on
1263127675Sbms	 * which the application was *linked*, not the system on which it's
1264127675Sbms	 * *running*.
1265127675Sbms	 *
1266127675Sbms	 * That routine should be documented, unlike the "version[]"
1267127675Sbms	 * string, so that UNIX vendors providing their own libpcaps
1268127675Sbms	 * don't omit it (as a couple of vendors have...).
1269127675Sbms	 *
1270127675Sbms	 * Packet.dll should perhaps also export a routine to return the
1271127675Sbms	 * version number of the Packet.dll code, to supply the
1272127675Sbms	 * "Wpcap_version" information on Windows.
1273127675Sbms	 */
1274127675Sbms	char WDversion[]="current-cvs.tcpdump.org";
1275146778Ssam#if !defined(HAVE_GENERATED_VERSION)
1276127675Sbms	char version[]="current-cvs.tcpdump.org";
1277146778Ssam#endif
1278127675Sbms	char pcap_version[]="current-cvs.tcpdump.org";
1279146778Ssam	char Wpcap_version[]="3.1";
1280127675Sbms#endif
1281127675Sbms
128239297Sfenner/*
1283127675Sbms * By default, print the specified data out in hex.
128439297Sfenner */
1285146778Ssamstatic void
1286146778Ssamndo_default_print(netdissect_options *ndo _U_, const u_char *bp, u_int length)
1287146778Ssam{
1288146778Ssam	ascii_print("\n\t", bp, length); /* pass on lf and identation string */
1289146778Ssam}
1290146778Ssam
129117680Spstvoid
1292146778Ssamdefault_print(const u_char *bp, u_int length)
129317680Spst{
1294146778Ssam	ndo_default_print(gndo, bp, length);
129517680Spst}
129617680Spst
129798527Sfenner#ifdef SIGINFO
1298127675SbmsRETSIGTYPE requestinfo(int signo _U_)
129998527Sfenner{
130098527Sfenner	if (infodelay)
130198527Sfenner		++infoprint;
130298527Sfenner	else
130398527Sfenner		info(0);
130498527Sfenner}
130598527Sfenner#endif
130698527Sfenner
1307146778Ssam/*
1308146778Ssam * Called once each second in verbose mode while dumping to file
1309146778Ssam */
1310146778Ssam#ifdef USE_WIN32_MM_TIMER
1311146778Ssamvoid CALLBACK verbose_stats_dump (UINT timer_id _U_, UINT msg _U_, DWORD_PTR arg _U_,
1312146778Ssam                                  DWORD_PTR dw1 _U_, DWORD_PTR dw2 _U_)
1313146778Ssam{
1314146778Ssam	struct pcap_stat stat;
1315146778Ssam
1316146778Ssam	if (infodelay == 0 && pcap_stats(pd, &stat) >= 0)
1317146778Ssam		fprintf(stderr, "Got %u\r", packets_captured);
1318146778Ssam}
1319146778Ssam#elif defined(HAVE_ALARM)
1320146778Ssamstatic void verbose_stats_dump(int sig _U_)
1321146778Ssam{
1322146778Ssam	struct pcap_stat stat;
1323146778Ssam
1324146778Ssam	if (infodelay == 0 && pcap_stats(pd, &stat) >= 0)
1325146778Ssam		fprintf(stderr, "Got %u\r", packets_captured);
1326146778Ssam	alarm(1);
1327146778Ssam}
1328146778Ssam#endif
1329146778Ssam
133075118Sfennerstatic void
133126180Sfennerusage(void)
133217680Spst{
133317680Spst	extern char version[];
1334127675Sbms#ifndef HAVE_PCAP_LIB_VERSION
1335127675Sbms#if defined(WIN32) || defined(HAVE_PCAP_VERSION)
133639297Sfenner	extern char pcap_version[];
1337127675Sbms#else /* defined(WIN32) || defined(HAVE_PCAP_VERSION) */
1338127675Sbms	static char pcap_version[] = "unknown";
1339127675Sbms#endif /* defined(WIN32) || defined(HAVE_PCAP_VERSION) */
1340127675Sbms#endif /* HAVE_PCAP_LIB_VERSION */
134117680Spst
1342127675Sbms#ifdef HAVE_PCAP_LIB_VERSION
1343146778Ssam#ifdef WIN32
1344146778Ssam	(void)fprintf(stderr, "%s version %s, based on tcpdump version %s\n", program_name, WDversion, version);
1345146778Ssam#else /* WIN32 */
134639297Sfenner	(void)fprintf(stderr, "%s version %s\n", program_name, version);
1347146778Ssam#endif /* WIN32 */
1348146778Ssam	(void)fprintf(stderr, "%s\n",pcap_lib_version());
1349127675Sbms#else /* HAVE_PCAP_LIB_VERSION */
1350127675Sbms#ifdef WIN32
1351127675Sbms	(void)fprintf(stderr, "%s version %s, based on tcpdump version %s\n", program_name, WDversion, version);
1352127675Sbms	(void)fprintf(stderr, "WinPcap version %s, based on libpcap version %s\n",Wpcap_version, pcap_version);
1353127675Sbms#else /* WIN32 */
1354127675Sbms	(void)fprintf(stderr, "%s version %s\n", program_name, version);
135539297Sfenner	(void)fprintf(stderr, "libpcap version %s\n", pcap_version);
1356127675Sbms#endif /* WIN32 */
1357127675Sbms#endif /* HAVE_PCAP_LIB_VERSION */
135817680Spst	(void)fprintf(stderr,
1359127675Sbms"Usage: %s [-aAd" D_FLAG "eflLnNOpqRStu" U_FLAG "vxX]" B_FLAG_USAGE " [-c count] [ -C file_size ]\n", program_name);
136017680Spst	(void)fprintf(stderr,
1361146778Ssam"\t\t[ -E algo:secret ] [ -F file ] [ -i interface ] [ -M secret ]\n");
136217680Spst	(void)fprintf(stderr,
1363146778Ssam"\t\t[ -r file ] [ -s snaplen ] [ -T type ] [ -w file ]\n");
1364109842Sfenner	(void)fprintf(stderr,
1365146778Ssam"\t\t[ -W filecount ] [ -y datalinktype ] [ -Z user ]\n");
1366146778Ssam	(void)fprintf(stderr,
1367109842Sfenner"\t\t[ expression ]\n");
136898527Sfenner	exit(1);
136917680Spst}
1370146778Ssam
1371146778Ssam
1372146778Ssam
1373146778Ssam/* VARARGS */
1374146778Ssamstatic void
1375146778Ssamndo_error(netdissect_options *ndo _U_, const char *fmt, ...)
1376146778Ssam{
1377146778Ssam	va_list ap;
1378146778Ssam
1379146778Ssam	(void)fprintf(stderr, "%s: ", program_name);
1380146778Ssam	va_start(ap, fmt);
1381146778Ssam	(void)vfprintf(stderr, fmt, ap);
1382146778Ssam	va_end(ap);
1383146778Ssam	if (*fmt) {
1384146778Ssam		fmt += strlen(fmt);
1385146778Ssam		if (fmt[-1] != '\n')
1386146778Ssam			(void)fputc('\n', stderr);
1387146778Ssam	}
1388146778Ssam	exit(1);
1389146778Ssam	/* NOTREACHED */
1390146778Ssam}
1391146778Ssam
1392146778Ssam/* VARARGS */
1393146778Ssamstatic void
1394146778Ssamndo_warning(netdissect_options *ndo _U_, const char *fmt, ...)
1395146778Ssam{
1396146778Ssam	va_list ap;
1397146778Ssam
1398146778Ssam	(void)fprintf(stderr, "%s: WARNING: ", program_name);
1399146778Ssam	va_start(ap, fmt);
1400146778Ssam	(void)vfprintf(stderr, fmt, ap);
1401146778Ssam	va_end(ap);
1402146778Ssam	if (*fmt) {
1403146778Ssam		fmt += strlen(fmt);
1404146778Ssam		if (fmt[-1] != '\n')
1405146778Ssam			(void)fputc('\n', stderr);
1406146778Ssam	}
1407146778Ssam}
1408146778Ssam
1409