xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c (revision 2760:38f12e308f6d)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51106Smrj  * Common Development and Distribution License (the "License").
61106Smrj  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211106Smrj 
220Sstevel@tonic-gate /*
231293Smh138676  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SunOS	*/
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <stdio.h>
300Sstevel@tonic-gate #include <unistd.h>
310Sstevel@tonic-gate #include <stropts.h>
320Sstevel@tonic-gate #include <string.h>
330Sstevel@tonic-gate #include <stdlib.h>
340Sstevel@tonic-gate #include <fcntl.h>
350Sstevel@tonic-gate #include <stdarg.h>
360Sstevel@tonic-gate #include <setjmp.h>
370Sstevel@tonic-gate #include <string.h>
380Sstevel@tonic-gate #include <errno.h>
390Sstevel@tonic-gate #include <sys/types.h>
400Sstevel@tonic-gate #include <sys/time.h>
410Sstevel@tonic-gate #include <signal.h>
420Sstevel@tonic-gate #include <sys/mman.h>
430Sstevel@tonic-gate #include <assert.h>
440Sstevel@tonic-gate #include <sys/sysmacros.h>
450Sstevel@tonic-gate 
460Sstevel@tonic-gate #include <sys/socket.h>
470Sstevel@tonic-gate #include <sys/pfmod.h>
480Sstevel@tonic-gate #include <net/if.h>
490Sstevel@tonic-gate #include <netinet/in_systm.h>
500Sstevel@tonic-gate #include <netinet/in.h>
510Sstevel@tonic-gate #include <netinet/if_ether.h>
520Sstevel@tonic-gate #include <netdb.h>
530Sstevel@tonic-gate 
540Sstevel@tonic-gate #include "snoop.h"
550Sstevel@tonic-gate 
561676Sjpk static int snaplen;
570Sstevel@tonic-gate char *device = NULL;
580Sstevel@tonic-gate 
590Sstevel@tonic-gate /* Global error recovery variables */
600Sstevel@tonic-gate sigjmp_buf jmp_env, ojmp_env;		/* error recovery jmp buf */
610Sstevel@tonic-gate int snoop_nrecover;			/* number of recoveries on curr pkt */
620Sstevel@tonic-gate int quitting;				/* user termination flag */
630Sstevel@tonic-gate 
641676Sjpk static struct snoop_handler *snoop_hp;		/* global alarm handler head */
651676Sjpk static struct snoop_handler *snoop_tp;		/* global alarm handler tail */
661676Sjpk static time_t snoop_nalarm;			/* time of next alarm */
670Sstevel@tonic-gate 
680Sstevel@tonic-gate /* protected interpreter output areas */
690Sstevel@tonic-gate #define	MAXSUM		8
700Sstevel@tonic-gate #define	REDZONE		64
710Sstevel@tonic-gate static char *sumline[MAXSUM];
720Sstevel@tonic-gate static char *detail_line;
730Sstevel@tonic-gate static char *line;
740Sstevel@tonic-gate static char *encap;
750Sstevel@tonic-gate 
761676Sjpk static int audio;
770Sstevel@tonic-gate int maxcount;	/* maximum no of packets to capture */
780Sstevel@tonic-gate int count;	/* count of packets captured */
791676Sjpk static int sumcount;
800Sstevel@tonic-gate int x_offset = -1;
810Sstevel@tonic-gate int x_length = 0x7fffffff;
820Sstevel@tonic-gate FILE *namefile;
830Sstevel@tonic-gate int Pflg;
840Sstevel@tonic-gate boolean_t qflg = B_FALSE;
850Sstevel@tonic-gate boolean_t rflg = B_FALSE;
860Sstevel@tonic-gate #ifdef	DEBUG
870Sstevel@tonic-gate boolean_t zflg = B_FALSE;		/* debugging packet corrupt flag */
880Sstevel@tonic-gate #endif
890Sstevel@tonic-gate struct Pf_ext_packetfilt pf;
900Sstevel@tonic-gate 
91*2760Sdg199075 static int vlanid = 0;
92*2760Sdg199075 
931676Sjpk static void usage(void);
940Sstevel@tonic-gate void show_count();
951676Sjpk static void snoop_sigrecover(int sig, siginfo_t *info, void *p);
960Sstevel@tonic-gate static char *protmalloc(size_t);
970Sstevel@tonic-gate static void resetperm(void);
980Sstevel@tonic-gate 
99410Skcpoon int
100410Skcpoon main(int argc, char **argv)
1010Sstevel@tonic-gate {
1020Sstevel@tonic-gate 	int c;
1030Sstevel@tonic-gate 	int filter = 0;
1040Sstevel@tonic-gate 	int flags = F_SUM;
1050Sstevel@tonic-gate 	struct Pf_ext_packetfilt *fp = NULL;
1060Sstevel@tonic-gate 	char *icapfile = NULL;
1070Sstevel@tonic-gate 	char *ocapfile = NULL;
1080Sstevel@tonic-gate 	int nflg = 0;
1090Sstevel@tonic-gate 	int Nflg = 0;
1100Sstevel@tonic-gate 	int Cflg = 0;
1110Sstevel@tonic-gate 	int first = 1;
1120Sstevel@tonic-gate 	int last  = 0x7fffffff;
1130Sstevel@tonic-gate 	int ppa;
1140Sstevel@tonic-gate 	int use_kern_pf;
1150Sstevel@tonic-gate 	char *p, *p2;
1160Sstevel@tonic-gate 	char names[MAXPATHLEN + 1];
1170Sstevel@tonic-gate 	char self[MAXHOSTNAMELEN + 1];
1180Sstevel@tonic-gate 	char *argstr = NULL;
1190Sstevel@tonic-gate 	void (*proc)();
1200Sstevel@tonic-gate 	char *audiodev;
1210Sstevel@tonic-gate 	int ret;
1220Sstevel@tonic-gate 	struct sigaction sigact;
1230Sstevel@tonic-gate 	stack_t sigstk;
1240Sstevel@tonic-gate 	char *output_area;
1250Sstevel@tonic-gate 	int nbytes;
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	names[0] = '\0';
1280Sstevel@tonic-gate 	/*
1290Sstevel@tonic-gate 	 * Global error recovery: Prepare for interpreter failures
1300Sstevel@tonic-gate 	 * with corrupted packets or confused interpreters.
1310Sstevel@tonic-gate 	 * Allocate protected output and stack areas, with generous
1320Sstevel@tonic-gate 	 * red-zones.
1330Sstevel@tonic-gate 	 */
1340Sstevel@tonic-gate 	nbytes = (MAXSUM + 3) * (MAXLINE + REDZONE);
1350Sstevel@tonic-gate 	output_area = protmalloc(nbytes);
1360Sstevel@tonic-gate 	if (output_area == NULL) {
1370Sstevel@tonic-gate 		perror("Warning: mmap");
1380Sstevel@tonic-gate 		exit(1);
1390Sstevel@tonic-gate 	}
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	/* Allocate protected output areas */
1420Sstevel@tonic-gate 	for (ret = 0; ret < MAXSUM; ret++) {
1430Sstevel@tonic-gate 		sumline[ret] = (char *)output_area;
1440Sstevel@tonic-gate 		output_area += (MAXLINE + REDZONE);
1450Sstevel@tonic-gate 	}
1460Sstevel@tonic-gate 	detail_line = output_area;
1470Sstevel@tonic-gate 	output_area += MAXLINE + REDZONE;
1480Sstevel@tonic-gate 	line = output_area;
1490Sstevel@tonic-gate 	output_area += MAXLINE + REDZONE;
1500Sstevel@tonic-gate 	encap = output_area;
1510Sstevel@tonic-gate 	output_area += MAXLINE + REDZONE;
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	/* Initialize an alternate signal stack to increase robustness */
1540Sstevel@tonic-gate 	if ((sigstk.ss_sp = (char *)malloc(SIGSTKSZ+REDZONE)) == NULL) {
1550Sstevel@tonic-gate 		perror("Warning: malloc");
1560Sstevel@tonic-gate 		exit(1);
1570Sstevel@tonic-gate 	}
1580Sstevel@tonic-gate 	sigstk.ss_size = SIGSTKSZ;
1590Sstevel@tonic-gate 	sigstk.ss_flags = 0;
1600Sstevel@tonic-gate 	if (sigaltstack(&sigstk, (stack_t *)NULL) < 0) {
1610Sstevel@tonic-gate 		perror("Warning: sigaltstack");
1620Sstevel@tonic-gate 		exit(1);
1630Sstevel@tonic-gate 	}
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	/* Initialize a master signal handler */
1660Sstevel@tonic-gate 	sigact.sa_handler = NULL;
1670Sstevel@tonic-gate 	sigact.sa_sigaction = snoop_sigrecover;
1681676Sjpk 	(void) sigemptyset(&sigact.sa_mask);
1690Sstevel@tonic-gate 	sigact.sa_flags = SA_ONSTACK|SA_SIGINFO;
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	/* Register master signal handler */
1720Sstevel@tonic-gate 	if (sigaction(SIGHUP, &sigact, (struct sigaction *)NULL) < 0) {
1730Sstevel@tonic-gate 		perror("Warning: sigaction");
1740Sstevel@tonic-gate 		exit(1);
1750Sstevel@tonic-gate 	}
1760Sstevel@tonic-gate 	if (sigaction(SIGINT, &sigact, (struct sigaction *)NULL) < 0) {
1770Sstevel@tonic-gate 		perror("Warning: sigaction");
1780Sstevel@tonic-gate 		exit(1);
1790Sstevel@tonic-gate 	}
1800Sstevel@tonic-gate 	if (sigaction(SIGQUIT, &sigact, (struct sigaction *)NULL) < 0) {
1810Sstevel@tonic-gate 		perror("Warning: sigaction");
1820Sstevel@tonic-gate 		exit(1);
1830Sstevel@tonic-gate 	}
1840Sstevel@tonic-gate 	if (sigaction(SIGILL, &sigact, (struct sigaction *)NULL) < 0) {
1850Sstevel@tonic-gate 		perror("Warning: sigaction");
1860Sstevel@tonic-gate 		exit(1);
1870Sstevel@tonic-gate 	}
1880Sstevel@tonic-gate 	if (sigaction(SIGTRAP, &sigact, (struct sigaction *)NULL) < 0) {
1890Sstevel@tonic-gate 		perror("Warning: sigaction");
1900Sstevel@tonic-gate 		exit(1);
1910Sstevel@tonic-gate 	}
1920Sstevel@tonic-gate 	if (sigaction(SIGIOT, &sigact, (struct sigaction *)NULL) < 0) {
1930Sstevel@tonic-gate 		perror("Warning: sigaction");
1940Sstevel@tonic-gate 		exit(1);
1950Sstevel@tonic-gate 	}
1960Sstevel@tonic-gate 	if (sigaction(SIGEMT, &sigact, (struct sigaction *)NULL) < 0) {
1970Sstevel@tonic-gate 		perror("Warning: sigaction");
1980Sstevel@tonic-gate 		exit(1);
1990Sstevel@tonic-gate 	}
2000Sstevel@tonic-gate 	if (sigaction(SIGFPE, &sigact, (struct sigaction *)NULL) < 0) {
2010Sstevel@tonic-gate 		perror("Warning: sigaction");
2020Sstevel@tonic-gate 		exit(1);
2030Sstevel@tonic-gate 	}
2040Sstevel@tonic-gate 	if (sigaction(SIGBUS, &sigact, (struct sigaction *)NULL) < 0) {
2050Sstevel@tonic-gate 		perror("Warning: sigaction");
2060Sstevel@tonic-gate 		exit(1);
2070Sstevel@tonic-gate 	}
2080Sstevel@tonic-gate 	if (sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL) < 0) {
2090Sstevel@tonic-gate 		perror("Warning: sigaction");
2100Sstevel@tonic-gate 		exit(1);
2110Sstevel@tonic-gate 	}
2120Sstevel@tonic-gate 	if (sigaction(SIGSYS, &sigact, (struct sigaction *)NULL) < 0) {
2130Sstevel@tonic-gate 		perror("Warning: sigaction");
2140Sstevel@tonic-gate 		exit(1);
2150Sstevel@tonic-gate 	}
2160Sstevel@tonic-gate 	if (sigaction(SIGALRM, &sigact, (struct sigaction *)NULL) < 0) {
2170Sstevel@tonic-gate 		perror("Warning: sigaction");
2180Sstevel@tonic-gate 		exit(1);
2190Sstevel@tonic-gate 	}
2200Sstevel@tonic-gate 	if (sigaction(SIGTERM, &sigact, (struct sigaction *)NULL) < 0) {
2210Sstevel@tonic-gate 		perror("Warning: sigaction");
2220Sstevel@tonic-gate 		exit(1);
2230Sstevel@tonic-gate 	}
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	/* Prepare for failure during program initialization/exit */
2260Sstevel@tonic-gate 	if (sigsetjmp(jmp_env, 1)) {
2270Sstevel@tonic-gate 		exit(1);
2280Sstevel@tonic-gate 	}
2291676Sjpk 	(void) setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "at:CPDSi:o:Nn:s:d:vVp:f:c:x:?rqz"))
2320Sstevel@tonic-gate 				!= EOF) {
2330Sstevel@tonic-gate 		switch (c) {
2340Sstevel@tonic-gate 		case 'a':
2350Sstevel@tonic-gate 			audiodev = getenv("AUDIODEV");
2360Sstevel@tonic-gate 			if (audiodev == NULL)
2370Sstevel@tonic-gate 				audiodev = "/dev/audio";
2380Sstevel@tonic-gate 			audio = open(audiodev, O_WRONLY);
2390Sstevel@tonic-gate 			if (audio < 0) {
2400Sstevel@tonic-gate 				pr_err("Audio device %s: %m",
2410Sstevel@tonic-gate 					audiodev);
2420Sstevel@tonic-gate 				exit(1);
2430Sstevel@tonic-gate 			}
2440Sstevel@tonic-gate 			break;
2450Sstevel@tonic-gate 		case 't':
2460Sstevel@tonic-gate 			flags |= F_TIME;
2470Sstevel@tonic-gate 			switch (*optarg) {
2480Sstevel@tonic-gate 			case 'r':	flags |= F_RTIME; break;
2490Sstevel@tonic-gate 			case 'a':	flags |= F_ATIME; break;
2500Sstevel@tonic-gate 			case 'd':	break;
2510Sstevel@tonic-gate 			default:	usage();
2520Sstevel@tonic-gate 			}
2530Sstevel@tonic-gate 			break;
2540Sstevel@tonic-gate 		case 'P':
2550Sstevel@tonic-gate 			Pflg++;
2560Sstevel@tonic-gate 			break;
2570Sstevel@tonic-gate 		case 'D':
2580Sstevel@tonic-gate 			flags |= F_DROPS;
2590Sstevel@tonic-gate 			break;
2600Sstevel@tonic-gate 		case 'S':
2610Sstevel@tonic-gate 			flags |= F_LEN;
2620Sstevel@tonic-gate 			break;
2630Sstevel@tonic-gate 		case 'i':
2640Sstevel@tonic-gate 			icapfile = optarg;
2650Sstevel@tonic-gate 			break;
2660Sstevel@tonic-gate 		case 'o':
2670Sstevel@tonic-gate 			ocapfile = optarg;
2680Sstevel@tonic-gate 			break;
2690Sstevel@tonic-gate 		case 'N':
2700Sstevel@tonic-gate 			Nflg++;
2710Sstevel@tonic-gate 			break;
2720Sstevel@tonic-gate 		case 'n':
2730Sstevel@tonic-gate 			nflg++;
2740Sstevel@tonic-gate 			(void) strlcpy(names, optarg, MAXPATHLEN);
2750Sstevel@tonic-gate 			break;
2760Sstevel@tonic-gate 		case 's':
2770Sstevel@tonic-gate 			snaplen = atoi(optarg);
2780Sstevel@tonic-gate 			break;
2790Sstevel@tonic-gate 		case 'd':
2800Sstevel@tonic-gate 			device = optarg;
2810Sstevel@tonic-gate 			break;
2820Sstevel@tonic-gate 		case 'v':
2830Sstevel@tonic-gate 			flags &= ~(F_SUM);
2840Sstevel@tonic-gate 			flags |= F_DTAIL;
2850Sstevel@tonic-gate 			break;
2860Sstevel@tonic-gate 		case 'V':
2870Sstevel@tonic-gate 			flags |= F_ALLSUM;
2880Sstevel@tonic-gate 			break;
2890Sstevel@tonic-gate 		case 'p':
2900Sstevel@tonic-gate 			p = optarg;
2910Sstevel@tonic-gate 			p2 = strpbrk(p, ",:-");
2920Sstevel@tonic-gate 			if (p2 == NULL) {
2930Sstevel@tonic-gate 				first = last = atoi(p);
2940Sstevel@tonic-gate 			} else {
2950Sstevel@tonic-gate 				*p2++ = '\0';
2960Sstevel@tonic-gate 				first = atoi(p);
2970Sstevel@tonic-gate 				last = atoi(p2);
2980Sstevel@tonic-gate 			}
2990Sstevel@tonic-gate 			break;
3000Sstevel@tonic-gate 		case 'f':
3010Sstevel@tonic-gate 			(void) gethostname(self, MAXHOSTNAMELEN);
3020Sstevel@tonic-gate 			p = strchr(optarg, ':');
3030Sstevel@tonic-gate 			if (p) {
3040Sstevel@tonic-gate 				*p = '\0';
3050Sstevel@tonic-gate 				if (strcmp(optarg, self) == 0 ||
3060Sstevel@tonic-gate 				    strcmp(p+1, self) == 0)
3070Sstevel@tonic-gate 				(void) fprintf(stderr,
3080Sstevel@tonic-gate 				"Warning: cannot capture packets from %s\n",
3090Sstevel@tonic-gate 					self);
3100Sstevel@tonic-gate 				*p = ' ';
3110Sstevel@tonic-gate 			} else if (strcmp(optarg, self) == 0)
3120Sstevel@tonic-gate 				(void) fprintf(stderr,
3130Sstevel@tonic-gate 				"Warning: cannot capture packets from %s\n",
3140Sstevel@tonic-gate 					self);
3150Sstevel@tonic-gate 			argstr = optarg;
3160Sstevel@tonic-gate 			break;
3170Sstevel@tonic-gate 		case 'x':
3180Sstevel@tonic-gate 			p = optarg;
3190Sstevel@tonic-gate 			p2 = strpbrk(p, ",:-");
3200Sstevel@tonic-gate 			if (p2 == NULL) {
3210Sstevel@tonic-gate 				x_offset = atoi(p);
3220Sstevel@tonic-gate 				x_length = -1;
3230Sstevel@tonic-gate 			} else {
3240Sstevel@tonic-gate 				*p2++ = '\0';
3250Sstevel@tonic-gate 				x_offset = atoi(p);
3260Sstevel@tonic-gate 				x_length = atoi(p2);
3270Sstevel@tonic-gate 			}
3280Sstevel@tonic-gate 			break;
3290Sstevel@tonic-gate 		case 'c':
3300Sstevel@tonic-gate 			maxcount = atoi(optarg);
3310Sstevel@tonic-gate 			break;
3320Sstevel@tonic-gate 		case 'C':
3330Sstevel@tonic-gate 			Cflg++;
3340Sstevel@tonic-gate 			break;
3350Sstevel@tonic-gate 		case 'q':
3360Sstevel@tonic-gate 			qflg = B_TRUE;
3370Sstevel@tonic-gate 			break;
3380Sstevel@tonic-gate 		case 'r':
3390Sstevel@tonic-gate 			rflg = B_TRUE;
3400Sstevel@tonic-gate 			break;
3410Sstevel@tonic-gate #ifdef	DEBUG
3420Sstevel@tonic-gate 		case 'z':
3430Sstevel@tonic-gate 			zflg = B_TRUE;
3440Sstevel@tonic-gate 			break;
3450Sstevel@tonic-gate #endif	/* DEBUG */
3460Sstevel@tonic-gate 		case '?':
3470Sstevel@tonic-gate 		default:
3480Sstevel@tonic-gate 			usage();
3490Sstevel@tonic-gate 		}
3500Sstevel@tonic-gate 	}
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	if (argc > optind)
3530Sstevel@tonic-gate 		argstr = (char *)concat_args(&argv[optind], argc - optind);
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	/*
3560Sstevel@tonic-gate 	 * Need to know before we decide on filtering method some things
3570Sstevel@tonic-gate 	 * about the interface.  So, go ahead and do part of the initialization
3580Sstevel@tonic-gate 	 * now so we have that data.  Note that if no device is specified,
3590Sstevel@tonic-gate 	 * check_device selects one and returns it.  In an ideal world,
3600Sstevel@tonic-gate 	 * it might be nice if the "correct" interface for the filter
3610Sstevel@tonic-gate 	 * requested was chosen, but that's too hard.
3620Sstevel@tonic-gate 	 */
3630Sstevel@tonic-gate 	if (!icapfile) {
3640Sstevel@tonic-gate 		use_kern_pf = check_device(&device, &ppa);
3650Sstevel@tonic-gate 	} else {
3660Sstevel@tonic-gate 		cap_open_read(icapfile);
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 		if (!nflg) {
3690Sstevel@tonic-gate 			names[0] = '\0';
3700Sstevel@tonic-gate 			(void) strlcpy(names, icapfile, MAXPATHLEN);
3710Sstevel@tonic-gate 			(void) strlcat(names, ".names", MAXPATHLEN);
3720Sstevel@tonic-gate 		}
3730Sstevel@tonic-gate 	}
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 	/* attempt to read .names file if it exists before filtering */
3760Sstevel@tonic-gate 	if ((!Nflg) && names[0] != '\0') {
3770Sstevel@tonic-gate 		if (access(names, F_OK) == 0) {
3780Sstevel@tonic-gate 			load_names(names);
3790Sstevel@tonic-gate 		} else if (nflg) {
3800Sstevel@tonic-gate 			(void) fprintf(stderr, "%s not found\n", names);
3810Sstevel@tonic-gate 			exit(1);
3820Sstevel@tonic-gate 		}
3830Sstevel@tonic-gate 	}
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	if (argstr) {
3860Sstevel@tonic-gate 		if (!icapfile && use_kern_pf) {
3870Sstevel@tonic-gate 			ret = pf_compile(argstr, Cflg);
3880Sstevel@tonic-gate 			switch (ret) {
3890Sstevel@tonic-gate 			case 0:
3900Sstevel@tonic-gate 				filter++;
3910Sstevel@tonic-gate 				compile(argstr, Cflg);
3920Sstevel@tonic-gate 				break;
3930Sstevel@tonic-gate 			case 1:
3940Sstevel@tonic-gate 				fp = &pf;
3950Sstevel@tonic-gate 				break;
3960Sstevel@tonic-gate 			case 2:
3970Sstevel@tonic-gate 				fp = &pf;
3980Sstevel@tonic-gate 				filter++;
3990Sstevel@tonic-gate 				break;
4000Sstevel@tonic-gate 			}
4010Sstevel@tonic-gate 		} else {
4020Sstevel@tonic-gate 			filter++;
4030Sstevel@tonic-gate 			compile(argstr, Cflg);
4040Sstevel@tonic-gate 		}
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 		if (Cflg)
4070Sstevel@tonic-gate 			exit(0);
4080Sstevel@tonic-gate 	}
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	if (flags & F_SUM)
4110Sstevel@tonic-gate 		flags |= F_WHO;
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	/*
4140Sstevel@tonic-gate 	 * If the -o flag is set then capture packets
4150Sstevel@tonic-gate 	 * directly to a file.  Don't attempt to
4160Sstevel@tonic-gate 	 * interpret them on the fly (F_NOW).
4170Sstevel@tonic-gate 	 * Note: capture to file is much less likely
4180Sstevel@tonic-gate 	 * to drop packets since we don't spend cpu
4190Sstevel@tonic-gate 	 * cycles running through the interpreters
4200Sstevel@tonic-gate 	 * and possibly hanging in address-to-name
4210Sstevel@tonic-gate 	 * mappings through the name service.
4220Sstevel@tonic-gate 	 */
4230Sstevel@tonic-gate 	if (ocapfile) {
4240Sstevel@tonic-gate 		cap_open_write(ocapfile);
4250Sstevel@tonic-gate 		proc = cap_write;
4260Sstevel@tonic-gate 	} else {
4270Sstevel@tonic-gate 		flags |= F_NOW;
4280Sstevel@tonic-gate 		proc = process_pkt;
4290Sstevel@tonic-gate 	}
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	/*
4330Sstevel@tonic-gate 	 * If the -i flag is set then get packets from
4340Sstevel@tonic-gate 	 * the log file which has been previously captured
4350Sstevel@tonic-gate 	 * with the -o option.
4360Sstevel@tonic-gate 	 */
4370Sstevel@tonic-gate 	if (icapfile) {
4380Sstevel@tonic-gate 		names[0] = '\0';
4390Sstevel@tonic-gate 		(void) strlcpy(names, icapfile, MAXPATHLEN);
4400Sstevel@tonic-gate 		(void) strlcat(names, ".names", MAXPATHLEN);
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 		if (Nflg) {
4430Sstevel@tonic-gate 			namefile = fopen(names, "w");
4440Sstevel@tonic-gate 			if (namefile == NULL) {
4450Sstevel@tonic-gate 				perror(names);
4460Sstevel@tonic-gate 				exit(1);
4470Sstevel@tonic-gate 			}
4480Sstevel@tonic-gate 			flags = 0;
4490Sstevel@tonic-gate 			(void) fprintf(stderr,
4500Sstevel@tonic-gate 				"Creating name file %s\n", names);
4510Sstevel@tonic-gate 		}
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 		if (flags & F_DTAIL)
4540Sstevel@tonic-gate 			flags = F_DTAIL;
4550Sstevel@tonic-gate 		else
4560Sstevel@tonic-gate 			flags |= F_NUM | F_TIME;
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 		resetperm();
4590Sstevel@tonic-gate 		cap_read(first, last, filter, proc, flags);
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 		if (Nflg)
4620Sstevel@tonic-gate 			(void) fclose(namefile);
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate 	} else {
4650Sstevel@tonic-gate 		const int chunksize = 8 * 8192;
4660Sstevel@tonic-gate 		struct timeval timeout;
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 		/*
4690Sstevel@tonic-gate 		 * If listening to packets on audio
4700Sstevel@tonic-gate 		 * then set the buffer timeout down
4710Sstevel@tonic-gate 		 * to 1/10 sec.  A higher value
4720Sstevel@tonic-gate 		 * makes the audio "bursty".
4730Sstevel@tonic-gate 		 */
4740Sstevel@tonic-gate 		if (audio) {
4750Sstevel@tonic-gate 			timeout.tv_sec = 0;
4760Sstevel@tonic-gate 			timeout.tv_usec = 100000;
4770Sstevel@tonic-gate 		} else {
4780Sstevel@tonic-gate 			timeout.tv_sec = 1;
4790Sstevel@tonic-gate 			timeout.tv_usec = 0;
4800Sstevel@tonic-gate 		}
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 		initdevice(device, snaplen, chunksize, &timeout, fp, ppa);
4830Sstevel@tonic-gate 		if (! qflg && ocapfile)
4840Sstevel@tonic-gate 			show_count();
4850Sstevel@tonic-gate 		resetperm();
4860Sstevel@tonic-gate 		net_read(chunksize, filter, proc, flags);
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 		if (!(flags & F_NOW))
4891676Sjpk 			(void) printf("\n");
4900Sstevel@tonic-gate 	}
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	if (ocapfile)
4930Sstevel@tonic-gate 		cap_close();
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 	return (0);
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate 
4981676Sjpk static int tone[] = {
4991293Smh138676 0x076113, 0x153333, 0x147317, 0x144311, 0x147315, 0x050353, 0x037103, 0x051106,
5001293Smh138676 0x157155, 0x142723, 0x133273, 0x134664, 0x051712, 0x024465, 0x026447, 0x072473,
5011293Smh138676 0x136715, 0x126257, 0x135256, 0x047344, 0x034476, 0x027464, 0x036062, 0x133334,
5021293Smh138676 0x127256, 0x130660, 0x136262, 0x040724, 0x016446, 0x025437, 0x137171, 0x127672,
5031293Smh138676 0x124655, 0x134654, 0x032741, 0x021447, 0x037450, 0x125675, 0x127650, 0x077277,
5041293Smh138676 0x046514, 0x036077, 0x035471, 0x147131, 0x136272, 0x162720, 0x166151, 0x037527,
5050Sstevel@tonic-gate };
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate /*
5081293Smh138676  * Make a sound on /dev/audio according to the length of the packet.  The
5091293Smh138676  * tone data was ripped from /usr/share/audio/samples/au/bark.au.  The
5101293Smh138676  * amount of waveform used is a function of packet length e.g.  a series
5111293Smh138676  * of small packets is heard as clicks, whereas a series of NFS packets in
5121293Smh138676  * an 8k read sounds like a "WHAAAARP".
5130Sstevel@tonic-gate  */
5140Sstevel@tonic-gate void
5150Sstevel@tonic-gate click(len)
5160Sstevel@tonic-gate 	int len;
5170Sstevel@tonic-gate {
5180Sstevel@tonic-gate 	len /= 8;
5190Sstevel@tonic-gate 	len = len ? len : 4;
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	if (audio) {
5221676Sjpk 		(void) write(audio, tone, len);
5230Sstevel@tonic-gate 	}
5240Sstevel@tonic-gate }
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate /* Display a count of packets */
5270Sstevel@tonic-gate void
5280Sstevel@tonic-gate show_count()
5290Sstevel@tonic-gate {
5300Sstevel@tonic-gate 	static int prev = -1;
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 	if (count == prev)
5330Sstevel@tonic-gate 		return;
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	prev = count;
5360Sstevel@tonic-gate 	(void) fprintf(stderr, "\r%d ", count);
5370Sstevel@tonic-gate }
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate #define	ENCAP_LEN	16	/* Hold "(NN encap)" */
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate /*
5420Sstevel@tonic-gate  * Display data that's external to the packet.
5430Sstevel@tonic-gate  * This constitutes the first half of the summary
5440Sstevel@tonic-gate  * line display.
5450Sstevel@tonic-gate  */
5460Sstevel@tonic-gate void
5470Sstevel@tonic-gate show_pktinfo(flags, num, src, dst, ptvp, tvp, drops, len)
5480Sstevel@tonic-gate 	int flags, num, drops, len;
5490Sstevel@tonic-gate 	char *src, *dst;
5500Sstevel@tonic-gate 	struct timeval *ptvp, *tvp;
5510Sstevel@tonic-gate {
5520Sstevel@tonic-gate 	struct tm *tm;
5530Sstevel@tonic-gate 	static struct timeval tvp0;
5540Sstevel@tonic-gate 	int sec, usec;
5550Sstevel@tonic-gate 	char *lp = line;
5560Sstevel@tonic-gate 	int i, start;
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 	if (flags & F_NUM) {
5591676Sjpk 		(void) sprintf(lp, "%3d ", num);
5600Sstevel@tonic-gate 		lp += strlen(lp);
5610Sstevel@tonic-gate 	}
5620Sstevel@tonic-gate 	tm = localtime(&tvp->tv_sec);
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 	if (flags & F_TIME) {
5650Sstevel@tonic-gate 		if (flags & F_ATIME) {
5661676Sjpk 			(void) sprintf(lp, "%d:%02d:%d.%05d ",
5670Sstevel@tonic-gate 				tm->tm_hour, tm->tm_min, tm->tm_sec,
5681676Sjpk 				(int)tvp->tv_usec / 10);
5690Sstevel@tonic-gate 			lp += strlen(lp);
5700Sstevel@tonic-gate 		} else {
5710Sstevel@tonic-gate 			if (flags & F_RTIME) {
5720Sstevel@tonic-gate 				if (tvp0.tv_sec == 0) {
5730Sstevel@tonic-gate 					tvp0.tv_sec = tvp->tv_sec;
5740Sstevel@tonic-gate 					tvp0.tv_usec = tvp->tv_usec;
5750Sstevel@tonic-gate 				}
5760Sstevel@tonic-gate 				ptvp = &tvp0;
5770Sstevel@tonic-gate 			}
5780Sstevel@tonic-gate 			sec  = tvp->tv_sec  - ptvp->tv_sec;
5790Sstevel@tonic-gate 			usec = tvp->tv_usec - ptvp->tv_usec;
5800Sstevel@tonic-gate 			if (usec < 0) {
5810Sstevel@tonic-gate 				usec += 1000000;
5820Sstevel@tonic-gate 				sec  -= 1;
5830Sstevel@tonic-gate 			}
5841676Sjpk 			(void) sprintf(lp, "%3d.%05d ", sec, usec / 10);
5850Sstevel@tonic-gate 			lp += strlen(lp);
5860Sstevel@tonic-gate 		}
5870Sstevel@tonic-gate 	}
5880Sstevel@tonic-gate 
589*2760Sdg199075 	if ((flags & F_SUM) && !(flags & F_ALLSUM) && (vlanid != 0)) {
590*2760Sdg199075 		(void) snprintf(lp, MAXLINE, "VLAN#%i: ", vlanid);
591*2760Sdg199075 		lp += strlen(lp);
592*2760Sdg199075 	}
593*2760Sdg199075 
5940Sstevel@tonic-gate 	if (flags & F_WHO) {
5951676Sjpk 		(void) sprintf(lp, "%12s -> %-12s ", src, dst);
5960Sstevel@tonic-gate 		lp += strlen(lp);
5970Sstevel@tonic-gate 	}
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 	if (flags & F_DROPS) {
6001676Sjpk 		(void) sprintf(lp, "drops: %d ", drops);
6010Sstevel@tonic-gate 		lp += strlen(lp);
6020Sstevel@tonic-gate 	}
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	if (flags & F_LEN) {
6051676Sjpk 		(void) sprintf(lp, "length: %4d  ", len);
6060Sstevel@tonic-gate 		lp += strlen(lp);
6070Sstevel@tonic-gate 	}
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	if (flags & F_SUM) {
6100Sstevel@tonic-gate 		if (flags & F_ALLSUM)
6111676Sjpk 			(void) printf("________________________________\n");
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 		start = flags & F_ALLSUM ? 0 : sumcount - 1;
6141676Sjpk 		(void) sprintf(encap, "  (%d encap)", total_encap_levels - 1);
6151676Sjpk 		(void) printf("%s%s%s\n", line, sumline[start],
6160Sstevel@tonic-gate 		    ((flags & F_ALLSUM) || (total_encap_levels == 1)) ? "" :
6170Sstevel@tonic-gate 			encap);
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 		for (i = start + 1; i < sumcount; i++)
6201676Sjpk 			(void) printf("%s%s\n", line, sumline[i]);
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate 		sumcount = 0;
6230Sstevel@tonic-gate 	}
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	if (flags & F_DTAIL) {
6261676Sjpk 		(void) printf("%s\n\n", detail_line);
6270Sstevel@tonic-gate 		detail_line[0] = '\0';
6280Sstevel@tonic-gate 	}
6290Sstevel@tonic-gate }
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate /*
632*2760Sdg199075  * The following three routines are called back
6330Sstevel@tonic-gate  * from the interpreters to display their stuff.
6340Sstevel@tonic-gate  * The theory is that when snoop becomes a window
6350Sstevel@tonic-gate  * based tool we can just supply a new version of
6360Sstevel@tonic-gate  * get_sum_line and get_detail_line and not have
6370Sstevel@tonic-gate  * to touch the interpreters at all.
6380Sstevel@tonic-gate  */
6390Sstevel@tonic-gate char *
6400Sstevel@tonic-gate get_sum_line()
6410Sstevel@tonic-gate {
6420Sstevel@tonic-gate 	int tsumcount = sumcount;
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 	if (sumcount >= MAXSUM) {
6450Sstevel@tonic-gate 		sumcount = 0;			/* error recovery */
6460Sstevel@tonic-gate 		pr_err(
6470Sstevel@tonic-gate 		    "get_sum_line: sumline overflow (sumcount=%d, MAXSUM=%d)\n",
6480Sstevel@tonic-gate 			tsumcount, MAXSUM);
6490Sstevel@tonic-gate 	}
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	sumline[sumcount][0] = '\0';
6520Sstevel@tonic-gate 	return (sumline[sumcount++]);
6530Sstevel@tonic-gate }
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate /*ARGSUSED*/
6560Sstevel@tonic-gate char *
6570Sstevel@tonic-gate get_detail_line(off, len)
6580Sstevel@tonic-gate 	int off, len;
6590Sstevel@tonic-gate {
6600Sstevel@tonic-gate 	if (detail_line[0]) {
6611676Sjpk 		(void) printf("%s\n", detail_line);
6620Sstevel@tonic-gate 		detail_line[0] = '\0';
6630Sstevel@tonic-gate 	}
6640Sstevel@tonic-gate 	return (detail_line);
6650Sstevel@tonic-gate }
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate /*
668*2760Sdg199075  * This function exists to make sure that VLAN information is
669*2760Sdg199075  * prepended to summary lines displayed.  The problem this function
670*2760Sdg199075  * solves is how to display VLAN information while in summary mode.
671*2760Sdg199075  * Each interpretor uses the get_sum_line and get_detail_line functions
672*2760Sdg199075  * to get a character buffer to display information to the user.
673*2760Sdg199075  * get_sum_line is the important one here.  Each call to get_sum_line
674*2760Sdg199075  * gets a buffer which stores one line of information.  In summary mode,
675*2760Sdg199075  * the last line generated is the line printed.  Instead of changing each
676*2760Sdg199075  * interpreter to add VLAN information to the summary line, the ethernet
677*2760Sdg199075  * interpreter changes to call this function and set an ID.  If the ID is not
678*2760Sdg199075  * zero and snoop is in default summary mode, snoop displays the
679*2760Sdg199075  * VLAN information at the beginning of the output line.  Otherwise,
680*2760Sdg199075  * no VLAN information is displayed.
681*2760Sdg199075  */
682*2760Sdg199075 void
683*2760Sdg199075 set_vlan_id(int id)
684*2760Sdg199075 {
685*2760Sdg199075 	vlanid = id;
686*2760Sdg199075 }
687*2760Sdg199075 
688*2760Sdg199075 /*
6890Sstevel@tonic-gate  * Print an error.
6900Sstevel@tonic-gate  * Works like printf (fmt string and variable args)
6911676Sjpk  * except that it will substitute an error message
6920Sstevel@tonic-gate  * for a "%m" string (like syslog) and it calls
6930Sstevel@tonic-gate  * long_jump - it doesn't return to where it was
6940Sstevel@tonic-gate  * called from - it goes to the last setjmp().
6950Sstevel@tonic-gate  */
6961676Sjpk /* VARARGS1 */
6970Sstevel@tonic-gate void
6981676Sjpk pr_err(const char *fmt, ...)
6990Sstevel@tonic-gate {
7000Sstevel@tonic-gate 	va_list ap;
7011676Sjpk 	char buf[1024], *p2;
7021676Sjpk 	const char *p1;
7030Sstevel@tonic-gate 
7041676Sjpk 	(void) strcpy(buf, "snoop: ");
7050Sstevel@tonic-gate 	p2 = buf + strlen(buf);
7060Sstevel@tonic-gate 
7071676Sjpk 	/*
7081676Sjpk 	 * Note that we terminate the buffer with '\n' and '\0'.
7091676Sjpk 	 */
7101676Sjpk 	for (p1 = fmt; *p1 != '\0' && p2 < buf + sizeof (buf) - 2; p1++) {
7110Sstevel@tonic-gate 		if (*p1 == '%' && *(p1+1) == 'm') {
7121676Sjpk 			const char *errstr;
7130Sstevel@tonic-gate 
7141676Sjpk 			if ((errstr = strerror(errno)) != NULL) {
7151676Sjpk 				*p2 = '\0';
7161676Sjpk 				(void) strlcat(buf, errstr, sizeof (buf));
7170Sstevel@tonic-gate 				p2 += strlen(p2);
7180Sstevel@tonic-gate 			}
7190Sstevel@tonic-gate 			p1++;
7200Sstevel@tonic-gate 		} else {
7210Sstevel@tonic-gate 			*p2++ = *p1;
7220Sstevel@tonic-gate 		}
7230Sstevel@tonic-gate 	}
7240Sstevel@tonic-gate 	if (p2 > buf && *(p2-1) != '\n')
7250Sstevel@tonic-gate 		*p2++ = '\n';
7260Sstevel@tonic-gate 	*p2 = '\0';
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	va_start(ap, fmt);
7291676Sjpk 	/* LINTED: E_SEC_PRINTF_VAR_FMT */
7300Sstevel@tonic-gate 	(void) vfprintf(stderr, buf, ap);
7310Sstevel@tonic-gate 	va_end(ap);
7320Sstevel@tonic-gate 	snoop_sigrecover(-1, NULL, NULL);	/* global error recovery */
7330Sstevel@tonic-gate }
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate /*
7360Sstevel@tonic-gate  * Ye olde usage proc
7370Sstevel@tonic-gate  * PLEASE keep this up to date!
7380Sstevel@tonic-gate  * Naive users *love* this stuff.
7390Sstevel@tonic-gate  */
7401676Sjpk static void
7411676Sjpk usage(void)
7420Sstevel@tonic-gate {
7430Sstevel@tonic-gate 	(void) fprintf(stderr, "\nUsage:  snoop\n");
7440Sstevel@tonic-gate 	(void) fprintf(stderr,
7450Sstevel@tonic-gate 	"\t[ -a ]			# Listen to packets on audio\n");
7460Sstevel@tonic-gate 	(void) fprintf(stderr,
7470Sstevel@tonic-gate 	"\t[ -d device ]		# Listen on interface named device\n");
7480Sstevel@tonic-gate 	(void) fprintf(stderr,
7490Sstevel@tonic-gate 	"\t[ -s snaplen ]		# Truncate packets\n");
7500Sstevel@tonic-gate 	(void) fprintf(stderr,
7510Sstevel@tonic-gate 	"\t[ -c count ]		# Quit after count packets\n");
7520Sstevel@tonic-gate 	(void) fprintf(stderr,
7530Sstevel@tonic-gate 	"\t[ -P ]			# Turn OFF promiscuous mode\n");
7540Sstevel@tonic-gate 	(void) fprintf(stderr,
7550Sstevel@tonic-gate 	"\t[ -D ]			# Report dropped packets\n");
7560Sstevel@tonic-gate 	(void) fprintf(stderr,
7570Sstevel@tonic-gate 	"\t[ -S ]			# Report packet size\n");
7580Sstevel@tonic-gate 	(void) fprintf(stderr,
7590Sstevel@tonic-gate 	"\t[ -i file ]		# Read previously captured packets\n");
7600Sstevel@tonic-gate 	(void) fprintf(stderr,
7610Sstevel@tonic-gate 	"\t[ -o file ]		# Capture packets in file\n");
7620Sstevel@tonic-gate 	(void) fprintf(stderr,
7630Sstevel@tonic-gate 	"\t[ -n file ]		# Load addr-to-name table from file\n");
7640Sstevel@tonic-gate 	(void) fprintf(stderr,
7650Sstevel@tonic-gate 	"\t[ -N ]			# Create addr-to-name table\n");
7660Sstevel@tonic-gate 	(void) fprintf(stderr,
7670Sstevel@tonic-gate 	"\t[ -t  r|a|d ]		# Time: Relative, Absolute or Delta\n");
7680Sstevel@tonic-gate 	(void) fprintf(stderr,
7690Sstevel@tonic-gate 	"\t[ -v ]			# Verbose packet display\n");
7700Sstevel@tonic-gate 	(void) fprintf(stderr,
7710Sstevel@tonic-gate 	"\t[ -V ]			# Show all summary lines\n");
7720Sstevel@tonic-gate 	(void) fprintf(stderr,
7730Sstevel@tonic-gate 	"\t[ -p first[,last] ]	# Select packet(s) to display\n");
7740Sstevel@tonic-gate 	(void) fprintf(stderr,
7750Sstevel@tonic-gate 	"\t[ -x offset[,length] ]	# Hex dump from offset for length\n");
7760Sstevel@tonic-gate 	(void) fprintf(stderr,
7770Sstevel@tonic-gate 	"\t[ -C ]			# Print packet filter code\n");
7780Sstevel@tonic-gate 	(void) fprintf(stderr,
7790Sstevel@tonic-gate 	"\t[ -q ]			# Suppress printing packet count\n");
7800Sstevel@tonic-gate 	(void) fprintf(stderr,
7810Sstevel@tonic-gate 	"\t[ -r ]			# Do not resolve address to name\n");
7820Sstevel@tonic-gate 	(void) fprintf(stderr,
7830Sstevel@tonic-gate 	"\n\t[ filter expression ]\n");
7840Sstevel@tonic-gate 	(void) fprintf(stderr, "\nExample:\n");
7850Sstevel@tonic-gate 	(void) fprintf(stderr, "\tsnoop -o saved  host fred\n\n");
7860Sstevel@tonic-gate 	(void) fprintf(stderr, "\tsnoop -i saved -tr -v -p19\n");
7870Sstevel@tonic-gate 	exit(1);
7880Sstevel@tonic-gate }
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate /*
7910Sstevel@tonic-gate  * sdefault: default global alarm handler. Causes the current packet
7920Sstevel@tonic-gate  * to be skipped.
7930Sstevel@tonic-gate  */
7940Sstevel@tonic-gate static void
7950Sstevel@tonic-gate sdefault(void)
7960Sstevel@tonic-gate {
7970Sstevel@tonic-gate 	snoop_nrecover = SNOOP_MAXRECOVER;
7980Sstevel@tonic-gate }
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate /*
8010Sstevel@tonic-gate  * snoop_alarm: register or unregister an alarm handler to be called after
8020Sstevel@tonic-gate  * s_sec seconds. Because snoop wasn't written to tolerate random signal
8030Sstevel@tonic-gate  * delivery, periodic SIGALRM delivery (or SA_RESTART) cannot be used.
8040Sstevel@tonic-gate  *
8050Sstevel@tonic-gate  * s_sec argument of 0 seconds unregisters the handler.
8060Sstevel@tonic-gate  * s_handler argument of NULL registers default handler sdefault(), or
8070Sstevel@tonic-gate  * unregisters all signal handlers (for error recovery).
8080Sstevel@tonic-gate  *
8090Sstevel@tonic-gate  * Variables must be volatile to force the compiler to not optimize
8100Sstevel@tonic-gate  * out the signal blocking.
8110Sstevel@tonic-gate  */
8120Sstevel@tonic-gate /*ARGSUSED*/
8130Sstevel@tonic-gate int
8140Sstevel@tonic-gate snoop_alarm(int s_sec, void (*s_handler)())
8150Sstevel@tonic-gate {
8160Sstevel@tonic-gate 	volatile time_t now;
8170Sstevel@tonic-gate 	volatile time_t nalarm = 0;
8180Sstevel@tonic-gate 	volatile struct snoop_handler *sh = NULL;
8190Sstevel@tonic-gate 	volatile struct snoop_handler *hp, *tp, *next;
8200Sstevel@tonic-gate 	volatile sigset_t s_mask;
8210Sstevel@tonic-gate 	volatile int ret = -1;
8220Sstevel@tonic-gate 
8231676Sjpk 	(void) sigemptyset((sigset_t *)&s_mask);
8241676Sjpk 	(void) sigaddset((sigset_t *)&s_mask, SIGALRM);
8250Sstevel@tonic-gate 	if (s_sec < 0)
8260Sstevel@tonic-gate 		return (-1);
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 	/* register an alarm handler */
8290Sstevel@tonic-gate 	now = time(NULL);
8300Sstevel@tonic-gate 	if (s_sec) {
8310Sstevel@tonic-gate 		sh = malloc(sizeof (struct snoop_handler));
8320Sstevel@tonic-gate 		sh->s_time = now + s_sec;
8330Sstevel@tonic-gate 		if (s_handler == NULL)
8340Sstevel@tonic-gate 			s_handler = sdefault;
8350Sstevel@tonic-gate 		sh->s_handler = s_handler;
8360Sstevel@tonic-gate 		sh->s_next = NULL;
8370Sstevel@tonic-gate 		(void) sigprocmask(SIG_BLOCK, (sigset_t *)&s_mask, NULL);
8380Sstevel@tonic-gate 		if (snoop_hp == NULL) {
8390Sstevel@tonic-gate 			snoop_hp = snoop_tp = (struct snoop_handler *)sh;
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 			snoop_nalarm = sh->s_time;
8421676Sjpk 			(void) alarm(sh->s_time - now);
8430Sstevel@tonic-gate 		} else {
8440Sstevel@tonic-gate 			snoop_tp->s_next = (struct snoop_handler *)sh;
8450Sstevel@tonic-gate 			snoop_tp = (struct snoop_handler *)sh;
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 			if (sh->s_time < snoop_nalarm) {
8480Sstevel@tonic-gate 				snoop_nalarm = sh->s_time;
8490Sstevel@tonic-gate 				(void) alarm(sh->s_time - now);
8500Sstevel@tonic-gate 			}
8510Sstevel@tonic-gate 		}
8520Sstevel@tonic-gate 		(void) sigprocmask(SIG_UNBLOCK, (sigset_t *)&s_mask, NULL);
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 		return (0);
8550Sstevel@tonic-gate 	}
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 	/* unregister an alarm handler */
8580Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, (sigset_t *)&s_mask, NULL);
8590Sstevel@tonic-gate 	tp = (struct snoop_handler *)&snoop_hp;
8600Sstevel@tonic-gate 	for (hp = snoop_hp; hp; hp = next) {
8610Sstevel@tonic-gate 		next = hp->s_next;
8620Sstevel@tonic-gate 		if (s_handler == NULL || hp->s_handler == s_handler) {
8630Sstevel@tonic-gate 			ret = 0;
8640Sstevel@tonic-gate 			tp->s_next = hp->s_next;
8650Sstevel@tonic-gate 			if (snoop_tp == hp) {
8660Sstevel@tonic-gate 				if (tp == (struct snoop_handler *)&snoop_hp)
8670Sstevel@tonic-gate 					snoop_tp = NULL;
8680Sstevel@tonic-gate 				else
8690Sstevel@tonic-gate 					snoop_tp = (struct snoop_handler *)tp;
8700Sstevel@tonic-gate 			}
8710Sstevel@tonic-gate 			free((void *)hp);
8720Sstevel@tonic-gate 		} else {
8730Sstevel@tonic-gate 			if (nalarm == 0 || nalarm > hp->s_time)
8740Sstevel@tonic-gate 				nalarm = now < hp->s_time ? hp->s_time :
8750Sstevel@tonic-gate 					now + 1;
8760Sstevel@tonic-gate 			tp = hp;
8770Sstevel@tonic-gate 		}
8780Sstevel@tonic-gate 	}
8790Sstevel@tonic-gate 	/*
8800Sstevel@tonic-gate 	 * Stop or adjust timer
8810Sstevel@tonic-gate 	 */
8820Sstevel@tonic-gate 	if (snoop_hp == NULL) {
8830Sstevel@tonic-gate 		snoop_nalarm = 0;
8840Sstevel@tonic-gate 		(void) alarm(0);
8850Sstevel@tonic-gate 	} else if (nalarm > 0 && nalarm < snoop_nalarm) {
8860Sstevel@tonic-gate 		snoop_nalarm = nalarm;
8870Sstevel@tonic-gate 		(void) alarm(nalarm - now);
8880Sstevel@tonic-gate 	}
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 	(void) sigprocmask(SIG_UNBLOCK, (sigset_t *)&s_mask, NULL);
8910Sstevel@tonic-gate 	return (ret);
8920Sstevel@tonic-gate }
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate /*
8950Sstevel@tonic-gate  * snoop_recover: reset snoop's output area, and any internal variables,
8960Sstevel@tonic-gate  * to allow continuation.
8970Sstevel@tonic-gate  * XXX: make this an interface such that each interpreter can
8980Sstevel@tonic-gate  * register a reset routine.
8990Sstevel@tonic-gate  */
9000Sstevel@tonic-gate void
9010Sstevel@tonic-gate snoop_recover(void)
9020Sstevel@tonic-gate {
9030Sstevel@tonic-gate 	int i;
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 	/* Error recovery: reset output_area and associated variables */
9060Sstevel@tonic-gate 	for (i = 0; i < MAXSUM; i++)
9070Sstevel@tonic-gate 		sumline[i][0] = '\0';
9080Sstevel@tonic-gate 	detail_line[0] = '\0';
9090Sstevel@tonic-gate 	line[0] = '\0';
9100Sstevel@tonic-gate 	encap[0] = '\0';
9110Sstevel@tonic-gate 	sumcount = 0;
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	/* stacking/unstacking cannot be relied upon */
9140Sstevel@tonic-gate 	encap_levels = 0;
9150Sstevel@tonic-gate 	total_encap_levels = 1;
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 	/* remove any pending timeouts */
9180Sstevel@tonic-gate 	(void) snoop_alarm(0, NULL);
9190Sstevel@tonic-gate }
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate /*
9220Sstevel@tonic-gate  * snoop_sigrecover: global sigaction routine to manage recovery
9230Sstevel@tonic-gate  * from catastrophic interpreter failures while interpreting
9240Sstevel@tonic-gate  * corrupt trace files/packets. SIGALRM timeouts, program errors,
9250Sstevel@tonic-gate  * and user termination are all handled. In the case of a corrupt
9260Sstevel@tonic-gate  * packet or confused interpreter, the packet will be skipped, and
9270Sstevel@tonic-gate  * execution will continue in scan().
9280Sstevel@tonic-gate  *
9290Sstevel@tonic-gate  * Global alarm handling (see snoop_alarm()) is managed here.
9300Sstevel@tonic-gate  *
9310Sstevel@tonic-gate  * Variables must be volatile to force the compiler to not optimize
9320Sstevel@tonic-gate  * out the signal blocking.
9330Sstevel@tonic-gate  */
9340Sstevel@tonic-gate /*ARGSUSED*/
9351676Sjpk static void
9360Sstevel@tonic-gate snoop_sigrecover(int sig, siginfo_t *info, void *p)
9370Sstevel@tonic-gate {
9380Sstevel@tonic-gate 	volatile time_t now;
9390Sstevel@tonic-gate 	volatile time_t nalarm = 0;
9400Sstevel@tonic-gate 	volatile struct snoop_handler *hp;
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 	/*
9430Sstevel@tonic-gate 	 * Invoke any registered alarms. This involves first calculating
9440Sstevel@tonic-gate 	 * the time for the next alarm, setting it up, then progressing
9450Sstevel@tonic-gate 	 * through handler invocations. Note that since handlers may
9460Sstevel@tonic-gate 	 * use siglongjmp(), in the worst case handlers may be serviced
9470Sstevel@tonic-gate 	 * at a later time.
9480Sstevel@tonic-gate 	 */
9490Sstevel@tonic-gate 	if (sig == SIGALRM) {
9500Sstevel@tonic-gate 		now = time(NULL);
9510Sstevel@tonic-gate 		/* Calculate next alarm time */
9520Sstevel@tonic-gate 		for (hp = snoop_hp; hp; hp = hp->s_next) {
9530Sstevel@tonic-gate 			if (hp->s_time) {
9540Sstevel@tonic-gate 				if ((hp->s_time - now) > 0) {
9550Sstevel@tonic-gate 					if (nalarm == 0 || nalarm > hp->s_time)
9560Sstevel@tonic-gate 						nalarm = now < hp->s_time ?
9570Sstevel@tonic-gate 							hp->s_time : now + 1;
9580Sstevel@tonic-gate 				}
9590Sstevel@tonic-gate 			}
9600Sstevel@tonic-gate 		}
9610Sstevel@tonic-gate 		/* Setup next alarm */
9620Sstevel@tonic-gate 		if (nalarm) {
9630Sstevel@tonic-gate 			snoop_nalarm = nalarm;
9641676Sjpk 			(void) alarm(nalarm - now);
9650Sstevel@tonic-gate 		} else {
9660Sstevel@tonic-gate 			snoop_nalarm = 0;
9670Sstevel@tonic-gate 		}
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 		/* Invoke alarm handlers (may not return) */
9700Sstevel@tonic-gate 		for (hp = snoop_hp; hp; hp = hp->s_next) {
9710Sstevel@tonic-gate 			if (hp->s_time) {
9720Sstevel@tonic-gate 				if ((now - hp->s_time) >= 0) {
9730Sstevel@tonic-gate 					hp->s_time = 0;	/* only invoke once */
9740Sstevel@tonic-gate 					if (hp->s_handler)
9750Sstevel@tonic-gate 						hp->s_handler();
9760Sstevel@tonic-gate 				}
9770Sstevel@tonic-gate 			}
9780Sstevel@tonic-gate 		}
9790Sstevel@tonic-gate 	} else {
9800Sstevel@tonic-gate 		snoop_nrecover++;
9810Sstevel@tonic-gate 	}
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 	/*
9840Sstevel@tonic-gate 	 * Exit if a signal has occurred after snoop has begun the process
9850Sstevel@tonic-gate 	 * of quitting.
9860Sstevel@tonic-gate 	 */
9870Sstevel@tonic-gate 	if (quitting)
9880Sstevel@tonic-gate 		exit(1);
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate 	/*
9910Sstevel@tonic-gate 	 * If an alarm handler has timed out, and snoop_nrecover has
9920Sstevel@tonic-gate 	 * reached SNOOP_MAXRECOVER, skip to the next packet.
9930Sstevel@tonic-gate 	 *
9940Sstevel@tonic-gate 	 * If any other signal has occurred, and snoop_nrecover has
9950Sstevel@tonic-gate 	 * reached SNOOP_MAXRECOVER, give up.
9960Sstevel@tonic-gate 	 */
9970Sstevel@tonic-gate 	if (sig == SIGALRM) {
9980Sstevel@tonic-gate 		if (ioctl(STDOUT_FILENO, I_CANPUT, 0) == 0) {
9990Sstevel@tonic-gate 			/*
10000Sstevel@tonic-gate 			 * We've stalled on output, which is not a critical
10010Sstevel@tonic-gate 			 * failure.  Reset the recovery counter so we do not
10020Sstevel@tonic-gate 			 * consider this a persistent failure, and return so
10030Sstevel@tonic-gate 			 * we do not skip this packet.
10040Sstevel@tonic-gate 			 */
10050Sstevel@tonic-gate 			snoop_nrecover = 0;
10060Sstevel@tonic-gate 			return;
10070Sstevel@tonic-gate 		}
10080Sstevel@tonic-gate 		if (snoop_nrecover >= SNOOP_MAXRECOVER) {
10091676Sjpk 			(void) fprintf(stderr,
10100Sstevel@tonic-gate 				"snoop: WARNING: skipping from packet %d\n",
10110Sstevel@tonic-gate 				count);
10120Sstevel@tonic-gate 			snoop_nrecover = 0;
10130Sstevel@tonic-gate 		} else {
10140Sstevel@tonic-gate 			/* continue trying */
10150Sstevel@tonic-gate 			return;
10160Sstevel@tonic-gate 		}
10170Sstevel@tonic-gate 	} else if (snoop_nrecover >= SNOOP_MAXRECOVER) {
10181676Sjpk 		(void) fprintf(stderr,
10190Sstevel@tonic-gate 			"snoop: ERROR: cannot recover from packet %d\n", count);
10200Sstevel@tonic-gate 		exit(1);
10210Sstevel@tonic-gate 	}
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate #ifdef DEBUG
10241676Sjpk 	(void) fprintf(stderr, "snoop_sigrecover(%d, %p, %p)\n", sig, info, p);
10250Sstevel@tonic-gate #endif /* DEBUG */
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 	/*
10280Sstevel@tonic-gate 	 * Prepare to quit. This allows final processing to occur
10290Sstevel@tonic-gate 	 * after first terminal interruption.
10300Sstevel@tonic-gate 	 */
10310Sstevel@tonic-gate 	if (sig == SIGTERM || sig == SIGHUP || sig == SIGINT) {
10320Sstevel@tonic-gate 		quitting = 1;
10330Sstevel@tonic-gate 		return;
10340Sstevel@tonic-gate 	} else if (sig != -1 && sig != SIGALRM) {
10350Sstevel@tonic-gate 		/* Inform user that snoop has taken a fault */
10361676Sjpk 		(void) fprintf(stderr,
10371676Sjpk 		    "WARNING: received signal %d from packet %d\n",
10380Sstevel@tonic-gate 				sig, count);
10390Sstevel@tonic-gate 	}
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 	/* Reset interpreter variables */
10420Sstevel@tonic-gate 	snoop_recover();
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 	/* Continue in scan() with the next packet */
10450Sstevel@tonic-gate 	siglongjmp(jmp_env, 1);
10460Sstevel@tonic-gate 	/*NOTREACHED*/
10470Sstevel@tonic-gate }
10480Sstevel@tonic-gate 
10490Sstevel@tonic-gate /*
10500Sstevel@tonic-gate  * Protected malloc for global error recovery: prepare for interpreter
10510Sstevel@tonic-gate  * failures with corrupted packets or confused interpreters.  Dynamically
10520Sstevel@tonic-gate  * allocate `nbytes' bytes, and sandwich it between two PROT_NONE pages to
10530Sstevel@tonic-gate  * catch writes outside of the allocated region.
10540Sstevel@tonic-gate  */
10550Sstevel@tonic-gate static char *
10560Sstevel@tonic-gate protmalloc(size_t nbytes)
10570Sstevel@tonic-gate {
10580Sstevel@tonic-gate 	caddr_t start;
10590Sstevel@tonic-gate 	int psz = sysconf(_SC_PAGESIZE);
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	nbytes = P2ROUNDUP(nbytes, psz);
10620Sstevel@tonic-gate 	start = mmap(NULL, nbytes + psz * 2, PROT_READ|PROT_WRITE,
10630Sstevel@tonic-gate 	    MAP_PRIVATE|MAP_ANON, -1, 0);
10640Sstevel@tonic-gate 	if (start == MAP_FAILED) {
10650Sstevel@tonic-gate 		perror("Error: protmalloc: mmap");
10660Sstevel@tonic-gate 		return (NULL);
10670Sstevel@tonic-gate 	}
10680Sstevel@tonic-gate 	assert(IS_P2ALIGNED(start, psz));
10690Sstevel@tonic-gate 	if (mprotect(start, 1, PROT_NONE) == -1)
10700Sstevel@tonic-gate 		perror("Warning: mprotect");
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 	start += psz;
10730Sstevel@tonic-gate 	if (mprotect(start + nbytes, 1, PROT_NONE) == -1)
10740Sstevel@tonic-gate 		perror("Warning: mprotect");
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 	return (start);
10770Sstevel@tonic-gate }
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate /*
10800Sstevel@tonic-gate  * resetperm - reduce security vulnerabilities by resetting
10810Sstevel@tonic-gate  * owner/group/permissions. Always attempt setuid() - if we have
10820Sstevel@tonic-gate  * permission to drop our privilege level, do so.
10830Sstevel@tonic-gate  */
10840Sstevel@tonic-gate void
10850Sstevel@tonic-gate resetperm(void)
10860Sstevel@tonic-gate {
10870Sstevel@tonic-gate 	if (geteuid() == 0) {
10880Sstevel@tonic-gate 		(void) setgid(GID_NOBODY);
10890Sstevel@tonic-gate 		(void) setuid(UID_NOBODY);
10900Sstevel@tonic-gate 	}
10910Sstevel@tonic-gate }
1092