xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c (revision 1293:52cb57f230e2)
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 /*
23*1293Smh138676  * 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 
560Sstevel@tonic-gate 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 
640Sstevel@tonic-gate extern int encap_levels;		/* variables needing reset on error */
650Sstevel@tonic-gate extern unsigned int total_encap_levels;
660Sstevel@tonic-gate 
670Sstevel@tonic-gate struct snoop_handler *snoop_hp;		/* global alarm handler head */
680Sstevel@tonic-gate struct snoop_handler *snoop_tp;		/* global alarm handler tail */
690Sstevel@tonic-gate time_t snoop_nalarm;			/* time of next alarm */
700Sstevel@tonic-gate 
710Sstevel@tonic-gate /* protected interpreter output areas */
720Sstevel@tonic-gate #define	MAXSUM		8
730Sstevel@tonic-gate #define	REDZONE		64
740Sstevel@tonic-gate static char *sumline[MAXSUM];
750Sstevel@tonic-gate static char *detail_line;
760Sstevel@tonic-gate static char *line;
770Sstevel@tonic-gate static char *encap;
780Sstevel@tonic-gate 
790Sstevel@tonic-gate int audio;
800Sstevel@tonic-gate int maxcount;	/* maximum no of packets to capture */
810Sstevel@tonic-gate int count;	/* count of packets captured */
820Sstevel@tonic-gate int sumcount;
830Sstevel@tonic-gate int x_offset = -1;
840Sstevel@tonic-gate int x_length = 0x7fffffff;
850Sstevel@tonic-gate FILE *namefile;
860Sstevel@tonic-gate int Pflg;
870Sstevel@tonic-gate boolean_t qflg = B_FALSE;
880Sstevel@tonic-gate boolean_t rflg = B_FALSE;
890Sstevel@tonic-gate #ifdef	DEBUG
900Sstevel@tonic-gate boolean_t zflg = B_FALSE;		/* debugging packet corrupt flag */
910Sstevel@tonic-gate #endif
920Sstevel@tonic-gate struct Pf_ext_packetfilt pf;
930Sstevel@tonic-gate 
940Sstevel@tonic-gate void usage();
950Sstevel@tonic-gate void show_count();
960Sstevel@tonic-gate void snoop_sigrecover(int sig, siginfo_t *info, void *p);
970Sstevel@tonic-gate static char *protmalloc(size_t);
980Sstevel@tonic-gate static void resetperm(void);
990Sstevel@tonic-gate 
100410Skcpoon int
101410Skcpoon main(int argc, char **argv)
1020Sstevel@tonic-gate {
1030Sstevel@tonic-gate 	extern char *optarg;
1040Sstevel@tonic-gate 	extern int optind;
1050Sstevel@tonic-gate 	int c;
1060Sstevel@tonic-gate 	int filter = 0;
1070Sstevel@tonic-gate 	int flags = F_SUM;
1080Sstevel@tonic-gate 	struct Pf_ext_packetfilt *fp = NULL;
1090Sstevel@tonic-gate 	char *icapfile = NULL;
1100Sstevel@tonic-gate 	char *ocapfile = NULL;
1110Sstevel@tonic-gate 	int nflg = 0;
1120Sstevel@tonic-gate 	int Nflg = 0;
1130Sstevel@tonic-gate 	int Cflg = 0;
1140Sstevel@tonic-gate 	int first = 1;
1150Sstevel@tonic-gate 	int last  = 0x7fffffff;
1160Sstevel@tonic-gate 	int ppa;
1170Sstevel@tonic-gate 	int use_kern_pf;
1180Sstevel@tonic-gate 	char *p, *p2;
1190Sstevel@tonic-gate 	char names[MAXPATHLEN + 1];
1200Sstevel@tonic-gate 	char self[MAXHOSTNAMELEN + 1];
1210Sstevel@tonic-gate 	char *argstr = NULL;
1220Sstevel@tonic-gate 	void (*proc)();
1230Sstevel@tonic-gate 	extern void cap_write();
1240Sstevel@tonic-gate 	extern void process_pkt();
1250Sstevel@tonic-gate 	char *audiodev;
1260Sstevel@tonic-gate 	int ret;
1270Sstevel@tonic-gate 	struct sigaction sigact;
1280Sstevel@tonic-gate 	stack_t sigstk;
1290Sstevel@tonic-gate 	char *output_area;
1300Sstevel@tonic-gate 	int nbytes;
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate 	names[0] = '\0';
1330Sstevel@tonic-gate 	/*
1340Sstevel@tonic-gate 	 * Global error recovery: Prepare for interpreter failures
1350Sstevel@tonic-gate 	 * with corrupted packets or confused interpreters.
1360Sstevel@tonic-gate 	 * Allocate protected output and stack areas, with generous
1370Sstevel@tonic-gate 	 * red-zones.
1380Sstevel@tonic-gate 	 */
1390Sstevel@tonic-gate 	nbytes = (MAXSUM + 3) * (MAXLINE + REDZONE);
1400Sstevel@tonic-gate 	output_area = protmalloc(nbytes);
1410Sstevel@tonic-gate 	if (output_area == NULL) {
1420Sstevel@tonic-gate 		perror("Warning: mmap");
1430Sstevel@tonic-gate 		exit(1);
1440Sstevel@tonic-gate 	}
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 	/* Allocate protected output areas */
1470Sstevel@tonic-gate 	for (ret = 0; ret < MAXSUM; ret++) {
1480Sstevel@tonic-gate 		sumline[ret] = (char *)output_area;
1490Sstevel@tonic-gate 		output_area += (MAXLINE + REDZONE);
1500Sstevel@tonic-gate 	}
1510Sstevel@tonic-gate 	detail_line = output_area;
1520Sstevel@tonic-gate 	output_area += MAXLINE + REDZONE;
1530Sstevel@tonic-gate 	line = output_area;
1540Sstevel@tonic-gate 	output_area += MAXLINE + REDZONE;
1550Sstevel@tonic-gate 	encap = output_area;
1560Sstevel@tonic-gate 	output_area += MAXLINE + REDZONE;
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	/* Initialize an alternate signal stack to increase robustness */
1590Sstevel@tonic-gate 	if ((sigstk.ss_sp = (char *)malloc(SIGSTKSZ+REDZONE)) == NULL) {
1600Sstevel@tonic-gate 		perror("Warning: malloc");
1610Sstevel@tonic-gate 		exit(1);
1620Sstevel@tonic-gate 	}
1630Sstevel@tonic-gate 	sigstk.ss_size = SIGSTKSZ;
1640Sstevel@tonic-gate 	sigstk.ss_flags = 0;
1650Sstevel@tonic-gate 	if (sigaltstack(&sigstk, (stack_t *)NULL) < 0) {
1660Sstevel@tonic-gate 		perror("Warning: sigaltstack");
1670Sstevel@tonic-gate 		exit(1);
1680Sstevel@tonic-gate 	}
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	/* Initialize a master signal handler */
1710Sstevel@tonic-gate 	sigact.sa_handler = NULL;
1720Sstevel@tonic-gate 	sigact.sa_sigaction = snoop_sigrecover;
1730Sstevel@tonic-gate 	sigemptyset(&sigact.sa_mask);
1740Sstevel@tonic-gate 	sigact.sa_flags = SA_ONSTACK|SA_SIGINFO;
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	/* Register master signal handler */
1770Sstevel@tonic-gate 	if (sigaction(SIGHUP, &sigact, (struct sigaction *)NULL) < 0) {
1780Sstevel@tonic-gate 		perror("Warning: sigaction");
1790Sstevel@tonic-gate 		exit(1);
1800Sstevel@tonic-gate 	}
1810Sstevel@tonic-gate 	if (sigaction(SIGINT, &sigact, (struct sigaction *)NULL) < 0) {
1820Sstevel@tonic-gate 		perror("Warning: sigaction");
1830Sstevel@tonic-gate 		exit(1);
1840Sstevel@tonic-gate 	}
1850Sstevel@tonic-gate 	if (sigaction(SIGQUIT, &sigact, (struct sigaction *)NULL) < 0) {
1860Sstevel@tonic-gate 		perror("Warning: sigaction");
1870Sstevel@tonic-gate 		exit(1);
1880Sstevel@tonic-gate 	}
1890Sstevel@tonic-gate 	if (sigaction(SIGILL, &sigact, (struct sigaction *)NULL) < 0) {
1900Sstevel@tonic-gate 		perror("Warning: sigaction");
1910Sstevel@tonic-gate 		exit(1);
1920Sstevel@tonic-gate 	}
1930Sstevel@tonic-gate 	if (sigaction(SIGTRAP, &sigact, (struct sigaction *)NULL) < 0) {
1940Sstevel@tonic-gate 		perror("Warning: sigaction");
1950Sstevel@tonic-gate 		exit(1);
1960Sstevel@tonic-gate 	}
1970Sstevel@tonic-gate 	if (sigaction(SIGIOT, &sigact, (struct sigaction *)NULL) < 0) {
1980Sstevel@tonic-gate 		perror("Warning: sigaction");
1990Sstevel@tonic-gate 		exit(1);
2000Sstevel@tonic-gate 	}
2010Sstevel@tonic-gate 	if (sigaction(SIGEMT, &sigact, (struct sigaction *)NULL) < 0) {
2020Sstevel@tonic-gate 		perror("Warning: sigaction");
2030Sstevel@tonic-gate 		exit(1);
2040Sstevel@tonic-gate 	}
2050Sstevel@tonic-gate 	if (sigaction(SIGFPE, &sigact, (struct sigaction *)NULL) < 0) {
2060Sstevel@tonic-gate 		perror("Warning: sigaction");
2070Sstevel@tonic-gate 		exit(1);
2080Sstevel@tonic-gate 	}
2090Sstevel@tonic-gate 	if (sigaction(SIGBUS, &sigact, (struct sigaction *)NULL) < 0) {
2100Sstevel@tonic-gate 		perror("Warning: sigaction");
2110Sstevel@tonic-gate 		exit(1);
2120Sstevel@tonic-gate 	}
2130Sstevel@tonic-gate 	if (sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL) < 0) {
2140Sstevel@tonic-gate 		perror("Warning: sigaction");
2150Sstevel@tonic-gate 		exit(1);
2160Sstevel@tonic-gate 	}
2170Sstevel@tonic-gate 	if (sigaction(SIGSYS, &sigact, (struct sigaction *)NULL) < 0) {
2180Sstevel@tonic-gate 		perror("Warning: sigaction");
2190Sstevel@tonic-gate 		exit(1);
2200Sstevel@tonic-gate 	}
2210Sstevel@tonic-gate 	if (sigaction(SIGALRM, &sigact, (struct sigaction *)NULL) < 0) {
2220Sstevel@tonic-gate 		perror("Warning: sigaction");
2230Sstevel@tonic-gate 		exit(1);
2240Sstevel@tonic-gate 	}
2250Sstevel@tonic-gate 	if (sigaction(SIGTERM, &sigact, (struct sigaction *)NULL) < 0) {
2260Sstevel@tonic-gate 		perror("Warning: sigaction");
2270Sstevel@tonic-gate 		exit(1);
2280Sstevel@tonic-gate 	}
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	/* Prepare for failure during program initialization/exit */
2310Sstevel@tonic-gate 	if (sigsetjmp(jmp_env, 1)) {
2320Sstevel@tonic-gate 		exit(1);
2330Sstevel@tonic-gate 	}
2340Sstevel@tonic-gate 	setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "at:CPDSi:o:Nn:s:d:vVp:f:c:x:?rqz"))
2370Sstevel@tonic-gate 				!= EOF) {
2380Sstevel@tonic-gate 		switch (c) {
2390Sstevel@tonic-gate 		case 'a':
2400Sstevel@tonic-gate 			audiodev = getenv("AUDIODEV");
2410Sstevel@tonic-gate 			if (audiodev == NULL)
2420Sstevel@tonic-gate 				audiodev = "/dev/audio";
2430Sstevel@tonic-gate 			audio = open(audiodev, O_WRONLY);
2440Sstevel@tonic-gate 			if (audio < 0) {
2450Sstevel@tonic-gate 				pr_err("Audio device %s: %m",
2460Sstevel@tonic-gate 					audiodev);
2470Sstevel@tonic-gate 				exit(1);
2480Sstevel@tonic-gate 			}
2490Sstevel@tonic-gate 			break;
2500Sstevel@tonic-gate 		case 't':
2510Sstevel@tonic-gate 			flags |= F_TIME;
2520Sstevel@tonic-gate 			switch (*optarg) {
2530Sstevel@tonic-gate 			case 'r':	flags |= F_RTIME; break;
2540Sstevel@tonic-gate 			case 'a':	flags |= F_ATIME; break;
2550Sstevel@tonic-gate 			case 'd':	break;
2560Sstevel@tonic-gate 			default:	usage();
2570Sstevel@tonic-gate 			}
2580Sstevel@tonic-gate 			break;
2590Sstevel@tonic-gate 		case 'P':
2600Sstevel@tonic-gate 			Pflg++;
2610Sstevel@tonic-gate 			break;
2620Sstevel@tonic-gate 		case 'D':
2630Sstevel@tonic-gate 			flags |= F_DROPS;
2640Sstevel@tonic-gate 			break;
2650Sstevel@tonic-gate 		case 'S':
2660Sstevel@tonic-gate 			flags |= F_LEN;
2670Sstevel@tonic-gate 			break;
2680Sstevel@tonic-gate 		case 'i':
2690Sstevel@tonic-gate 			icapfile = optarg;
2700Sstevel@tonic-gate 			break;
2710Sstevel@tonic-gate 		case 'o':
2720Sstevel@tonic-gate 			ocapfile = optarg;
2730Sstevel@tonic-gate 			break;
2740Sstevel@tonic-gate 		case 'N':
2750Sstevel@tonic-gate 			Nflg++;
2760Sstevel@tonic-gate 			break;
2770Sstevel@tonic-gate 		case 'n':
2780Sstevel@tonic-gate 			nflg++;
2790Sstevel@tonic-gate 			(void) strlcpy(names, optarg, MAXPATHLEN);
2800Sstevel@tonic-gate 			break;
2810Sstevel@tonic-gate 		case 's':
2820Sstevel@tonic-gate 			snaplen = atoi(optarg);
2830Sstevel@tonic-gate 			break;
2840Sstevel@tonic-gate 		case 'd':
2850Sstevel@tonic-gate 			device = optarg;
2860Sstevel@tonic-gate 			break;
2870Sstevel@tonic-gate 		case 'v':
2880Sstevel@tonic-gate 			flags &= ~(F_SUM);
2890Sstevel@tonic-gate 			flags |= F_DTAIL;
2900Sstevel@tonic-gate 			break;
2910Sstevel@tonic-gate 		case 'V':
2920Sstevel@tonic-gate 			flags |= F_ALLSUM;
2930Sstevel@tonic-gate 			break;
2940Sstevel@tonic-gate 		case 'p':
2950Sstevel@tonic-gate 			p = optarg;
2960Sstevel@tonic-gate 			p2 = strpbrk(p, ",:-");
2970Sstevel@tonic-gate 			if (p2 == NULL) {
2980Sstevel@tonic-gate 				first = last = atoi(p);
2990Sstevel@tonic-gate 			} else {
3000Sstevel@tonic-gate 				*p2++ = '\0';
3010Sstevel@tonic-gate 				first = atoi(p);
3020Sstevel@tonic-gate 				last = atoi(p2);
3030Sstevel@tonic-gate 			}
3040Sstevel@tonic-gate 			break;
3050Sstevel@tonic-gate 		case 'f':
3060Sstevel@tonic-gate 			(void) gethostname(self, MAXHOSTNAMELEN);
3070Sstevel@tonic-gate 			p = strchr(optarg, ':');
3080Sstevel@tonic-gate 			if (p) {
3090Sstevel@tonic-gate 				*p = '\0';
3100Sstevel@tonic-gate 				if (strcmp(optarg, self) == 0 ||
3110Sstevel@tonic-gate 				    strcmp(p+1, 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 				*p = ' ';
3160Sstevel@tonic-gate 			} else if (strcmp(optarg, self) == 0)
3170Sstevel@tonic-gate 				(void) fprintf(stderr,
3180Sstevel@tonic-gate 				"Warning: cannot capture packets from %s\n",
3190Sstevel@tonic-gate 					self);
3200Sstevel@tonic-gate 			argstr = optarg;
3210Sstevel@tonic-gate 			break;
3220Sstevel@tonic-gate 		case 'x':
3230Sstevel@tonic-gate 			p = optarg;
3240Sstevel@tonic-gate 			p2 = strpbrk(p, ",:-");
3250Sstevel@tonic-gate 			if (p2 == NULL) {
3260Sstevel@tonic-gate 				x_offset = atoi(p);
3270Sstevel@tonic-gate 				x_length = -1;
3280Sstevel@tonic-gate 			} else {
3290Sstevel@tonic-gate 				*p2++ = '\0';
3300Sstevel@tonic-gate 				x_offset = atoi(p);
3310Sstevel@tonic-gate 				x_length = atoi(p2);
3320Sstevel@tonic-gate 			}
3330Sstevel@tonic-gate 			break;
3340Sstevel@tonic-gate 		case 'c':
3350Sstevel@tonic-gate 			maxcount = atoi(optarg);
3360Sstevel@tonic-gate 			break;
3370Sstevel@tonic-gate 		case 'C':
3380Sstevel@tonic-gate 			Cflg++;
3390Sstevel@tonic-gate 			break;
3400Sstevel@tonic-gate 		case 'q':
3410Sstevel@tonic-gate 			qflg = B_TRUE;
3420Sstevel@tonic-gate 			break;
3430Sstevel@tonic-gate 		case 'r':
3440Sstevel@tonic-gate 			rflg = B_TRUE;
3450Sstevel@tonic-gate 			break;
3460Sstevel@tonic-gate #ifdef	DEBUG
3470Sstevel@tonic-gate 		case 'z':
3480Sstevel@tonic-gate 			zflg = B_TRUE;
3490Sstevel@tonic-gate 			break;
3500Sstevel@tonic-gate #endif	/* DEBUG */
3510Sstevel@tonic-gate 		case '?':
3520Sstevel@tonic-gate 		default:
3530Sstevel@tonic-gate 			usage();
3540Sstevel@tonic-gate 		}
3550Sstevel@tonic-gate 	}
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	if (argc > optind)
3580Sstevel@tonic-gate 		argstr = (char *)concat_args(&argv[optind], argc - optind);
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	/*
3610Sstevel@tonic-gate 	 * Need to know before we decide on filtering method some things
3620Sstevel@tonic-gate 	 * about the interface.  So, go ahead and do part of the initialization
3630Sstevel@tonic-gate 	 * now so we have that data.  Note that if no device is specified,
3640Sstevel@tonic-gate 	 * check_device selects one and returns it.  In an ideal world,
3650Sstevel@tonic-gate 	 * it might be nice if the "correct" interface for the filter
3660Sstevel@tonic-gate 	 * requested was chosen, but that's too hard.
3670Sstevel@tonic-gate 	 */
3680Sstevel@tonic-gate 	if (!icapfile) {
3690Sstevel@tonic-gate 		use_kern_pf = check_device(&device, &ppa);
3700Sstevel@tonic-gate 	} else {
3710Sstevel@tonic-gate 		cap_open_read(icapfile);
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 		if (!nflg) {
3740Sstevel@tonic-gate 			names[0] = '\0';
3750Sstevel@tonic-gate 			(void) strlcpy(names, icapfile, MAXPATHLEN);
3760Sstevel@tonic-gate 			(void) strlcat(names, ".names", MAXPATHLEN);
3770Sstevel@tonic-gate 		}
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	/* attempt to read .names file if it exists before filtering */
3810Sstevel@tonic-gate 	if ((!Nflg) && names[0] != '\0') {
3820Sstevel@tonic-gate 		if (access(names, F_OK) == 0) {
3830Sstevel@tonic-gate 			load_names(names);
3840Sstevel@tonic-gate 		} else if (nflg) {
3850Sstevel@tonic-gate 			(void) fprintf(stderr, "%s not found\n", names);
3860Sstevel@tonic-gate 			exit(1);
3870Sstevel@tonic-gate 		}
3880Sstevel@tonic-gate 	}
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	if (argstr) {
3910Sstevel@tonic-gate 		if (!icapfile && use_kern_pf) {
3920Sstevel@tonic-gate 			ret = pf_compile(argstr, Cflg);
3930Sstevel@tonic-gate 			switch (ret) {
3940Sstevel@tonic-gate 			case 0:
3950Sstevel@tonic-gate 				filter++;
3960Sstevel@tonic-gate 				compile(argstr, Cflg);
3970Sstevel@tonic-gate 				break;
3980Sstevel@tonic-gate 			case 1:
3990Sstevel@tonic-gate 				fp = &pf;
4000Sstevel@tonic-gate 				break;
4010Sstevel@tonic-gate 			case 2:
4020Sstevel@tonic-gate 				fp = &pf;
4030Sstevel@tonic-gate 				filter++;
4040Sstevel@tonic-gate 				break;
4050Sstevel@tonic-gate 			}
4060Sstevel@tonic-gate 		} else {
4070Sstevel@tonic-gate 			filter++;
4080Sstevel@tonic-gate 			compile(argstr, Cflg);
4090Sstevel@tonic-gate 		}
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 		if (Cflg)
4120Sstevel@tonic-gate 			exit(0);
4130Sstevel@tonic-gate 	}
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	if (flags & F_SUM)
4160Sstevel@tonic-gate 		flags |= F_WHO;
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	/*
4190Sstevel@tonic-gate 	 * If the -o flag is set then capture packets
4200Sstevel@tonic-gate 	 * directly to a file.  Don't attempt to
4210Sstevel@tonic-gate 	 * interpret them on the fly (F_NOW).
4220Sstevel@tonic-gate 	 * Note: capture to file is much less likely
4230Sstevel@tonic-gate 	 * to drop packets since we don't spend cpu
4240Sstevel@tonic-gate 	 * cycles running through the interpreters
4250Sstevel@tonic-gate 	 * and possibly hanging in address-to-name
4260Sstevel@tonic-gate 	 * mappings through the name service.
4270Sstevel@tonic-gate 	 */
4280Sstevel@tonic-gate 	if (ocapfile) {
4290Sstevel@tonic-gate 		cap_open_write(ocapfile);
4300Sstevel@tonic-gate 		proc = cap_write;
4310Sstevel@tonic-gate 	} else {
4320Sstevel@tonic-gate 		flags |= F_NOW;
4330Sstevel@tonic-gate 		proc = process_pkt;
4340Sstevel@tonic-gate 	}
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	/*
4380Sstevel@tonic-gate 	 * If the -i flag is set then get packets from
4390Sstevel@tonic-gate 	 * the log file which has been previously captured
4400Sstevel@tonic-gate 	 * with the -o option.
4410Sstevel@tonic-gate 	 */
4420Sstevel@tonic-gate 	if (icapfile) {
4430Sstevel@tonic-gate 		names[0] = '\0';
4440Sstevel@tonic-gate 		(void) strlcpy(names, icapfile, MAXPATHLEN);
4450Sstevel@tonic-gate 		(void) strlcat(names, ".names", MAXPATHLEN);
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 		if (Nflg) {
4480Sstevel@tonic-gate 			namefile = fopen(names, "w");
4490Sstevel@tonic-gate 			if (namefile == NULL) {
4500Sstevel@tonic-gate 				perror(names);
4510Sstevel@tonic-gate 				exit(1);
4520Sstevel@tonic-gate 			}
4530Sstevel@tonic-gate 			flags = 0;
4540Sstevel@tonic-gate 			(void) fprintf(stderr,
4550Sstevel@tonic-gate 				"Creating name file %s\n", names);
4560Sstevel@tonic-gate 		}
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 		if (flags & F_DTAIL)
4590Sstevel@tonic-gate 			flags = F_DTAIL;
4600Sstevel@tonic-gate 		else
4610Sstevel@tonic-gate 			flags |= F_NUM | F_TIME;
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 		resetperm();
4640Sstevel@tonic-gate 		cap_read(first, last, filter, proc, flags);
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 		if (Nflg)
4670Sstevel@tonic-gate 			(void) fclose(namefile);
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	} else {
4700Sstevel@tonic-gate 		const int chunksize = 8 * 8192;
4710Sstevel@tonic-gate 		struct timeval timeout;
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 		/*
4740Sstevel@tonic-gate 		 * If listening to packets on audio
4750Sstevel@tonic-gate 		 * then set the buffer timeout down
4760Sstevel@tonic-gate 		 * to 1/10 sec.  A higher value
4770Sstevel@tonic-gate 		 * makes the audio "bursty".
4780Sstevel@tonic-gate 		 */
4790Sstevel@tonic-gate 		if (audio) {
4800Sstevel@tonic-gate 			timeout.tv_sec = 0;
4810Sstevel@tonic-gate 			timeout.tv_usec = 100000;
4820Sstevel@tonic-gate 		} else {
4830Sstevel@tonic-gate 			timeout.tv_sec = 1;
4840Sstevel@tonic-gate 			timeout.tv_usec = 0;
4850Sstevel@tonic-gate 		}
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 		initdevice(device, snaplen, chunksize, &timeout, fp, ppa);
4880Sstevel@tonic-gate 		if (! qflg && ocapfile)
4890Sstevel@tonic-gate 			show_count();
4900Sstevel@tonic-gate 		resetperm();
4910Sstevel@tonic-gate 		net_read(chunksize, filter, proc, flags);
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 		if (!(flags & F_NOW))
4940Sstevel@tonic-gate 			printf("\n");
4950Sstevel@tonic-gate 	}
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	if (ocapfile)
4980Sstevel@tonic-gate 		cap_close();
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	return (0);
5010Sstevel@tonic-gate }
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate int tone[] = {
504*1293Smh138676 0x076113, 0x153333, 0x147317, 0x144311, 0x147315, 0x050353, 0x037103, 0x051106,
505*1293Smh138676 0x157155, 0x142723, 0x133273, 0x134664, 0x051712, 0x024465, 0x026447, 0x072473,
506*1293Smh138676 0x136715, 0x126257, 0x135256, 0x047344, 0x034476, 0x027464, 0x036062, 0x133334,
507*1293Smh138676 0x127256, 0x130660, 0x136262, 0x040724, 0x016446, 0x025437, 0x137171, 0x127672,
508*1293Smh138676 0x124655, 0x134654, 0x032741, 0x021447, 0x037450, 0x125675, 0x127650, 0x077277,
509*1293Smh138676 0x046514, 0x036077, 0x035471, 0x147131, 0x136272, 0x162720, 0x166151, 0x037527,
5100Sstevel@tonic-gate };
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate /*
513*1293Smh138676  * Make a sound on /dev/audio according to the length of the packet.  The
514*1293Smh138676  * tone data was ripped from /usr/share/audio/samples/au/bark.au.  The
515*1293Smh138676  * amount of waveform used is a function of packet length e.g.  a series
516*1293Smh138676  * of small packets is heard as clicks, whereas a series of NFS packets in
517*1293Smh138676  * an 8k read sounds like a "WHAAAARP".
5180Sstevel@tonic-gate  */
5190Sstevel@tonic-gate void
5200Sstevel@tonic-gate click(len)
5210Sstevel@tonic-gate 	int len;
5220Sstevel@tonic-gate {
5230Sstevel@tonic-gate 	len /= 8;
5240Sstevel@tonic-gate 	len = len ? len : 4;
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	if (audio) {
5270Sstevel@tonic-gate 		write(audio, tone, len);
5280Sstevel@tonic-gate 	}
5290Sstevel@tonic-gate }
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate /* Display a count of packets */
5320Sstevel@tonic-gate void
5330Sstevel@tonic-gate show_count()
5340Sstevel@tonic-gate {
5350Sstevel@tonic-gate 	static int prev = -1;
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	if (count == prev)
5380Sstevel@tonic-gate 		return;
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	prev = count;
5410Sstevel@tonic-gate 	(void) fprintf(stderr, "\r%d ", count);
5420Sstevel@tonic-gate }
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate #define	ENCAP_LEN	16	/* Hold "(NN encap)" */
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate /*
5470Sstevel@tonic-gate  * Display data that's external to the packet.
5480Sstevel@tonic-gate  * This constitutes the first half of the summary
5490Sstevel@tonic-gate  * line display.
5500Sstevel@tonic-gate  */
5510Sstevel@tonic-gate void
5520Sstevel@tonic-gate show_pktinfo(flags, num, src, dst, ptvp, tvp, drops, len)
5530Sstevel@tonic-gate 	int flags, num, drops, len;
5540Sstevel@tonic-gate 	char *src, *dst;
5550Sstevel@tonic-gate 	struct timeval *ptvp, *tvp;
5560Sstevel@tonic-gate {
5570Sstevel@tonic-gate 	struct tm *tm;
5580Sstevel@tonic-gate 	static struct timeval tvp0;
5590Sstevel@tonic-gate 	int sec, usec;
5600Sstevel@tonic-gate 	char *lp = line;
5610Sstevel@tonic-gate 	int i, start;
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	if (flags & F_NUM) {
5640Sstevel@tonic-gate 		sprintf(lp, "%3d ", num);
5650Sstevel@tonic-gate 		lp += strlen(lp);
5660Sstevel@tonic-gate 	}
5670Sstevel@tonic-gate 	tm = localtime(&tvp->tv_sec);
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	if (flags & F_TIME) {
5700Sstevel@tonic-gate 		if (flags & F_ATIME) {
5710Sstevel@tonic-gate 			sprintf(lp, "%d:%02d:%d.%05d ",
5720Sstevel@tonic-gate 				tm->tm_hour, tm->tm_min, tm->tm_sec,
5730Sstevel@tonic-gate 				tvp->tv_usec / 10);
5740Sstevel@tonic-gate 			lp += strlen(lp);
5750Sstevel@tonic-gate 		} else {
5760Sstevel@tonic-gate 			if (flags & F_RTIME) {
5770Sstevel@tonic-gate 				if (tvp0.tv_sec == 0) {
5780Sstevel@tonic-gate 					tvp0.tv_sec = tvp->tv_sec;
5790Sstevel@tonic-gate 					tvp0.tv_usec = tvp->tv_usec;
5800Sstevel@tonic-gate 				}
5810Sstevel@tonic-gate 				ptvp = &tvp0;
5820Sstevel@tonic-gate 			}
5830Sstevel@tonic-gate 			sec  = tvp->tv_sec  - ptvp->tv_sec;
5840Sstevel@tonic-gate 			usec = tvp->tv_usec - ptvp->tv_usec;
5850Sstevel@tonic-gate 			if (usec < 0) {
5860Sstevel@tonic-gate 				usec += 1000000;
5870Sstevel@tonic-gate 				sec  -= 1;
5880Sstevel@tonic-gate 			}
5890Sstevel@tonic-gate 			sprintf(lp, "%3d.%05d ", sec, usec / 10);
5900Sstevel@tonic-gate 			lp += strlen(lp);
5910Sstevel@tonic-gate 		}
5920Sstevel@tonic-gate 	}
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	if (flags & F_WHO) {
5950Sstevel@tonic-gate 		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) {
6000Sstevel@tonic-gate 		sprintf(lp, "drops: %d ", drops);
6010Sstevel@tonic-gate 		lp += strlen(lp);
6020Sstevel@tonic-gate 	}
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	if (flags & F_LEN) {
6050Sstevel@tonic-gate 		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)
6110Sstevel@tonic-gate 			printf("________________________________\n");
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 		start = flags & F_ALLSUM ? 0 : sumcount - 1;
6140Sstevel@tonic-gate 		sprintf(encap, "  (%d encap)", total_encap_levels - 1);
6150Sstevel@tonic-gate 		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++)
6200Sstevel@tonic-gate 			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) {
6260Sstevel@tonic-gate 		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 /*
6320Sstevel@tonic-gate  * The following two 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]) {
6610Sstevel@tonic-gate 		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 /*
6680Sstevel@tonic-gate  * Print an error.
6690Sstevel@tonic-gate  * Works like printf (fmt string and variable args)
6700Sstevel@tonic-gate  * except that it will subsititute an error message
6710Sstevel@tonic-gate  * for a "%m" string (like syslog) and it calls
6720Sstevel@tonic-gate  * long_jump - it doesn't return to where it was
6730Sstevel@tonic-gate  * called from - it goes to the last setjmp().
6740Sstevel@tonic-gate  */
6750Sstevel@tonic-gate void
6760Sstevel@tonic-gate pr_err(char *fmt, ...)
6770Sstevel@tonic-gate {
6780Sstevel@tonic-gate 	va_list ap;
6790Sstevel@tonic-gate 	char buf[BUFSIZ], *p2;
6800Sstevel@tonic-gate 	char *p1;
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	strcpy(buf, "snoop: ");
6830Sstevel@tonic-gate 	p2 = buf + strlen(buf);
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	for (p1 = fmt; *p1; p1++) {
6860Sstevel@tonic-gate 		if (*p1 == '%' && *(p1+1) == 'm') {
6870Sstevel@tonic-gate 			char *errstr;
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 			if ((errstr = strerror(errno)) != (char *)NULL) {
6900Sstevel@tonic-gate 				(void) strcpy(p2, errstr);
6910Sstevel@tonic-gate 				p2 += strlen(p2);
6920Sstevel@tonic-gate 			}
6930Sstevel@tonic-gate 			p1++;
6940Sstevel@tonic-gate 		} else {
6950Sstevel@tonic-gate 			*p2++ = *p1;
6960Sstevel@tonic-gate 		}
6970Sstevel@tonic-gate 	}
6980Sstevel@tonic-gate 	if (p2 > buf && *(p2-1) != '\n')
6990Sstevel@tonic-gate 		*p2++ = '\n';
7000Sstevel@tonic-gate 	*p2 = '\0';
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 	va_start(ap, fmt);
7030Sstevel@tonic-gate 	(void) vfprintf(stderr, buf, ap);
7040Sstevel@tonic-gate 	va_end(ap);
7050Sstevel@tonic-gate 	snoop_sigrecover(-1, NULL, NULL);	/* global error recovery */
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate /*
7090Sstevel@tonic-gate  * Ye olde usage proc
7100Sstevel@tonic-gate  * PLEASE keep this up to date!
7110Sstevel@tonic-gate  * Naive users *love* this stuff.
7120Sstevel@tonic-gate  */
7130Sstevel@tonic-gate void
7140Sstevel@tonic-gate usage()
7150Sstevel@tonic-gate {
7160Sstevel@tonic-gate 	(void) fprintf(stderr, "\nUsage:  snoop\n");
7170Sstevel@tonic-gate 	(void) fprintf(stderr,
7180Sstevel@tonic-gate 	"\t[ -a ]			# Listen to packets on audio\n");
7190Sstevel@tonic-gate 	(void) fprintf(stderr,
7200Sstevel@tonic-gate 	"\t[ -d device ]		# Listen on interface named device\n");
7210Sstevel@tonic-gate 	(void) fprintf(stderr,
7220Sstevel@tonic-gate 	"\t[ -s snaplen ]		# Truncate packets\n");
7230Sstevel@tonic-gate 	(void) fprintf(stderr,
7240Sstevel@tonic-gate 	"\t[ -c count ]		# Quit after count packets\n");
7250Sstevel@tonic-gate 	(void) fprintf(stderr,
7260Sstevel@tonic-gate 	"\t[ -P ]			# Turn OFF promiscuous mode\n");
7270Sstevel@tonic-gate 	(void) fprintf(stderr,
7280Sstevel@tonic-gate 	"\t[ -D ]			# Report dropped packets\n");
7290Sstevel@tonic-gate 	(void) fprintf(stderr,
7300Sstevel@tonic-gate 	"\t[ -S ]			# Report packet size\n");
7310Sstevel@tonic-gate 	(void) fprintf(stderr,
7320Sstevel@tonic-gate 	"\t[ -i file ]		# Read previously captured packets\n");
7330Sstevel@tonic-gate 	(void) fprintf(stderr,
7340Sstevel@tonic-gate 	"\t[ -o file ]		# Capture packets in file\n");
7350Sstevel@tonic-gate 	(void) fprintf(stderr,
7360Sstevel@tonic-gate 	"\t[ -n file ]		# Load addr-to-name table from file\n");
7370Sstevel@tonic-gate 	(void) fprintf(stderr,
7380Sstevel@tonic-gate 	"\t[ -N ]			# Create addr-to-name table\n");
7390Sstevel@tonic-gate 	(void) fprintf(stderr,
7400Sstevel@tonic-gate 	"\t[ -t  r|a|d ]		# Time: Relative, Absolute or Delta\n");
7410Sstevel@tonic-gate 	(void) fprintf(stderr,
7420Sstevel@tonic-gate 	"\t[ -v ]			# Verbose packet display\n");
7430Sstevel@tonic-gate 	(void) fprintf(stderr,
7440Sstevel@tonic-gate 	"\t[ -V ]			# Show all summary lines\n");
7450Sstevel@tonic-gate 	(void) fprintf(stderr,
7460Sstevel@tonic-gate 	"\t[ -p first[,last] ]	# Select packet(s) to display\n");
7470Sstevel@tonic-gate 	(void) fprintf(stderr,
7480Sstevel@tonic-gate 	"\t[ -x offset[,length] ]	# Hex dump from offset for length\n");
7490Sstevel@tonic-gate 	(void) fprintf(stderr,
7500Sstevel@tonic-gate 	"\t[ -C ]			# Print packet filter code\n");
7510Sstevel@tonic-gate 	(void) fprintf(stderr,
7520Sstevel@tonic-gate 	"\t[ -q ]			# Suppress printing packet count\n");
7530Sstevel@tonic-gate 	(void) fprintf(stderr,
7540Sstevel@tonic-gate 	"\t[ -r ]			# Do not resolve address to name\n");
7550Sstevel@tonic-gate 	(void) fprintf(stderr,
7560Sstevel@tonic-gate 	"\n\t[ filter expression ]\n");
7570Sstevel@tonic-gate 	(void) fprintf(stderr, "\nExample:\n");
7580Sstevel@tonic-gate 	(void) fprintf(stderr, "\tsnoop -o saved  host fred\n\n");
7590Sstevel@tonic-gate 	(void) fprintf(stderr, "\tsnoop -i saved -tr -v -p19\n");
7600Sstevel@tonic-gate 	exit(1);
7610Sstevel@tonic-gate }
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate /*
7640Sstevel@tonic-gate  * sdefault: default global alarm handler. Causes the current packet
7650Sstevel@tonic-gate  * to be skipped.
7660Sstevel@tonic-gate  */
7670Sstevel@tonic-gate static void
7680Sstevel@tonic-gate sdefault(void)
7690Sstevel@tonic-gate {
7700Sstevel@tonic-gate 	snoop_nrecover = SNOOP_MAXRECOVER;
7710Sstevel@tonic-gate }
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate /*
7740Sstevel@tonic-gate  * snoop_alarm: register or unregister an alarm handler to be called after
7750Sstevel@tonic-gate  * s_sec seconds. Because snoop wasn't written to tolerate random signal
7760Sstevel@tonic-gate  * delivery, periodic SIGALRM delivery (or SA_RESTART) cannot be used.
7770Sstevel@tonic-gate  *
7780Sstevel@tonic-gate  * s_sec argument of 0 seconds unregisters the handler.
7790Sstevel@tonic-gate  * s_handler argument of NULL registers default handler sdefault(), or
7800Sstevel@tonic-gate  * unregisters all signal handlers (for error recovery).
7810Sstevel@tonic-gate  *
7820Sstevel@tonic-gate  * Variables must be volatile to force the compiler to not optimize
7830Sstevel@tonic-gate  * out the signal blocking.
7840Sstevel@tonic-gate  */
7850Sstevel@tonic-gate /*ARGSUSED*/
7860Sstevel@tonic-gate int
7870Sstevel@tonic-gate snoop_alarm(int s_sec, void (*s_handler)())
7880Sstevel@tonic-gate {
7890Sstevel@tonic-gate 	volatile time_t now;
7900Sstevel@tonic-gate 	volatile time_t nalarm = 0;
7910Sstevel@tonic-gate 	volatile struct snoop_handler *sh = NULL;
7920Sstevel@tonic-gate 	volatile struct snoop_handler *hp, *tp, *next;
7930Sstevel@tonic-gate 	volatile sigset_t s_mask;
7940Sstevel@tonic-gate 	volatile int ret = -1;
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 	sigemptyset((sigset_t *)&s_mask);
7970Sstevel@tonic-gate 	sigaddset((sigset_t *)&s_mask, SIGALRM);
7980Sstevel@tonic-gate 	if (s_sec < 0)
7990Sstevel@tonic-gate 		return (-1);
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	/* register an alarm handler */
8020Sstevel@tonic-gate 	now = time(NULL);
8030Sstevel@tonic-gate 	if (s_sec) {
8040Sstevel@tonic-gate 		sh = malloc(sizeof (struct snoop_handler));
8050Sstevel@tonic-gate 		sh->s_time = now + s_sec;
8060Sstevel@tonic-gate 		if (s_handler == NULL)
8070Sstevel@tonic-gate 			s_handler = sdefault;
8080Sstevel@tonic-gate 		sh->s_handler = s_handler;
8090Sstevel@tonic-gate 		sh->s_next = NULL;
8100Sstevel@tonic-gate 		(void) sigprocmask(SIG_BLOCK, (sigset_t *)&s_mask, NULL);
8110Sstevel@tonic-gate 		if (snoop_hp == NULL) {
8120Sstevel@tonic-gate 			snoop_hp = snoop_tp = (struct snoop_handler *)sh;
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 			snoop_nalarm = sh->s_time;
8150Sstevel@tonic-gate 			alarm(sh->s_time - now);
8160Sstevel@tonic-gate 		} else {
8170Sstevel@tonic-gate 			snoop_tp->s_next = (struct snoop_handler *)sh;
8180Sstevel@tonic-gate 			snoop_tp = (struct snoop_handler *)sh;
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 			if (sh->s_time < snoop_nalarm) {
8210Sstevel@tonic-gate 				snoop_nalarm = sh->s_time;
8220Sstevel@tonic-gate 				(void) alarm(sh->s_time - now);
8230Sstevel@tonic-gate 			}
8240Sstevel@tonic-gate 		}
8250Sstevel@tonic-gate 		(void) sigprocmask(SIG_UNBLOCK, (sigset_t *)&s_mask, NULL);
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 		return (0);
8280Sstevel@tonic-gate 	}
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	/* unregister an alarm handler */
8310Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, (sigset_t *)&s_mask, NULL);
8320Sstevel@tonic-gate 	tp = (struct snoop_handler *)&snoop_hp;
8330Sstevel@tonic-gate 	for (hp = snoop_hp; hp; hp = next) {
8340Sstevel@tonic-gate 		next = hp->s_next;
8350Sstevel@tonic-gate 		if (s_handler == NULL || hp->s_handler == s_handler) {
8360Sstevel@tonic-gate 			ret = 0;
8370Sstevel@tonic-gate 			tp->s_next = hp->s_next;
8380Sstevel@tonic-gate 			if (snoop_tp == hp) {
8390Sstevel@tonic-gate 				if (tp == (struct snoop_handler *)&snoop_hp)
8400Sstevel@tonic-gate 					snoop_tp = NULL;
8410Sstevel@tonic-gate 				else
8420Sstevel@tonic-gate 					snoop_tp = (struct snoop_handler *)tp;
8430Sstevel@tonic-gate 			}
8440Sstevel@tonic-gate 			free((void *)hp);
8450Sstevel@tonic-gate 		} else {
8460Sstevel@tonic-gate 			if (nalarm == 0 || nalarm > hp->s_time)
8470Sstevel@tonic-gate 				nalarm = now < hp->s_time ? hp->s_time :
8480Sstevel@tonic-gate 					now + 1;
8490Sstevel@tonic-gate 			tp = hp;
8500Sstevel@tonic-gate 		}
8510Sstevel@tonic-gate 	}
8520Sstevel@tonic-gate 	/*
8530Sstevel@tonic-gate 	 * Stop or adjust timer
8540Sstevel@tonic-gate 	 */
8550Sstevel@tonic-gate 	if (snoop_hp == NULL) {
8560Sstevel@tonic-gate 		snoop_nalarm = 0;
8570Sstevel@tonic-gate 		(void) alarm(0);
8580Sstevel@tonic-gate 	} else if (nalarm > 0 && nalarm < snoop_nalarm) {
8590Sstevel@tonic-gate 		snoop_nalarm = nalarm;
8600Sstevel@tonic-gate 		(void) alarm(nalarm - now);
8610Sstevel@tonic-gate 	}
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 	(void) sigprocmask(SIG_UNBLOCK, (sigset_t *)&s_mask, NULL);
8640Sstevel@tonic-gate 	return (ret);
8650Sstevel@tonic-gate }
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate /*
8680Sstevel@tonic-gate  * snoop_recover: reset snoop's output area, and any internal variables,
8690Sstevel@tonic-gate  * to allow continuation.
8700Sstevel@tonic-gate  * XXX: make this an interface such that each interpreter can
8710Sstevel@tonic-gate  * register a reset routine.
8720Sstevel@tonic-gate  */
8730Sstevel@tonic-gate void
8740Sstevel@tonic-gate snoop_recover(void)
8750Sstevel@tonic-gate {
8760Sstevel@tonic-gate 	int i;
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	/* Error recovery: reset output_area and associated variables */
8790Sstevel@tonic-gate 	for (i = 0; i < MAXSUM; i++)
8800Sstevel@tonic-gate 		sumline[i][0] = '\0';
8810Sstevel@tonic-gate 	detail_line[0] = '\0';
8820Sstevel@tonic-gate 	line[0] = '\0';
8830Sstevel@tonic-gate 	encap[0] = '\0';
8840Sstevel@tonic-gate 	sumcount = 0;
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate 	/* stacking/unstacking cannot be relied upon */
8870Sstevel@tonic-gate 	encap_levels = 0;
8880Sstevel@tonic-gate 	total_encap_levels = 1;
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 	/* remove any pending timeouts */
8910Sstevel@tonic-gate 	(void) snoop_alarm(0, NULL);
8920Sstevel@tonic-gate }
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate /*
8950Sstevel@tonic-gate  * snoop_sigrecover: global sigaction routine to manage recovery
8960Sstevel@tonic-gate  * from catastrophic interpreter failures while interpreting
8970Sstevel@tonic-gate  * corrupt trace files/packets. SIGALRM timeouts, program errors,
8980Sstevel@tonic-gate  * and user termination are all handled. In the case of a corrupt
8990Sstevel@tonic-gate  * packet or confused interpreter, the packet will be skipped, and
9000Sstevel@tonic-gate  * execution will continue in scan().
9010Sstevel@tonic-gate  *
9020Sstevel@tonic-gate  * Global alarm handling (see snoop_alarm()) is managed here.
9030Sstevel@tonic-gate  *
9040Sstevel@tonic-gate  * Variables must be volatile to force the compiler to not optimize
9050Sstevel@tonic-gate  * out the signal blocking.
9060Sstevel@tonic-gate  */
9070Sstevel@tonic-gate /*ARGSUSED*/
9080Sstevel@tonic-gate void
9090Sstevel@tonic-gate snoop_sigrecover(int sig, siginfo_t *info, void *p)
9100Sstevel@tonic-gate {
9110Sstevel@tonic-gate 	volatile time_t now;
9120Sstevel@tonic-gate 	volatile time_t nalarm = 0;
9130Sstevel@tonic-gate 	volatile struct snoop_handler *hp;
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 	/*
9160Sstevel@tonic-gate 	 * Invoke any registered alarms. This involves first calculating
9170Sstevel@tonic-gate 	 * the time for the next alarm, setting it up, then progressing
9180Sstevel@tonic-gate 	 * through handler invocations. Note that since handlers may
9190Sstevel@tonic-gate 	 * use siglongjmp(), in the worst case handlers may be serviced
9200Sstevel@tonic-gate 	 * at a later time.
9210Sstevel@tonic-gate 	 */
9220Sstevel@tonic-gate 	if (sig == SIGALRM) {
9230Sstevel@tonic-gate 		now = time(NULL);
9240Sstevel@tonic-gate 		/* Calculate next alarm time */
9250Sstevel@tonic-gate 		for (hp = snoop_hp; hp; hp = hp->s_next) {
9260Sstevel@tonic-gate 			if (hp->s_time) {
9270Sstevel@tonic-gate 				if ((hp->s_time - now) > 0) {
9280Sstevel@tonic-gate 					if (nalarm == 0 || nalarm > hp->s_time)
9290Sstevel@tonic-gate 						nalarm = now < hp->s_time ?
9300Sstevel@tonic-gate 							hp->s_time : now + 1;
9310Sstevel@tonic-gate 				}
9320Sstevel@tonic-gate 			}
9330Sstevel@tonic-gate 		}
9340Sstevel@tonic-gate 		/* Setup next alarm */
9350Sstevel@tonic-gate 		if (nalarm) {
9360Sstevel@tonic-gate 			snoop_nalarm = nalarm;
9370Sstevel@tonic-gate 			alarm(nalarm - now);
9380Sstevel@tonic-gate 		} else {
9390Sstevel@tonic-gate 			snoop_nalarm = 0;
9400Sstevel@tonic-gate 		}
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 		/* Invoke alarm handlers (may not return) */
9430Sstevel@tonic-gate 		for (hp = snoop_hp; hp; hp = hp->s_next) {
9440Sstevel@tonic-gate 			if (hp->s_time) {
9450Sstevel@tonic-gate 				if ((now - hp->s_time) >= 0) {
9460Sstevel@tonic-gate 					hp->s_time = 0;	/* only invoke once */
9470Sstevel@tonic-gate 					if (hp->s_handler)
9480Sstevel@tonic-gate 						hp->s_handler();
9490Sstevel@tonic-gate 				}
9500Sstevel@tonic-gate 			}
9510Sstevel@tonic-gate 		}
9520Sstevel@tonic-gate 	} else {
9530Sstevel@tonic-gate 		snoop_nrecover++;
9540Sstevel@tonic-gate 	}
9550Sstevel@tonic-gate 
9560Sstevel@tonic-gate 	/*
9570Sstevel@tonic-gate 	 * Exit if a signal has occurred after snoop has begun the process
9580Sstevel@tonic-gate 	 * of quitting.
9590Sstevel@tonic-gate 	 */
9600Sstevel@tonic-gate 	if (quitting)
9610Sstevel@tonic-gate 		exit(1);
9620Sstevel@tonic-gate 
9630Sstevel@tonic-gate 	/*
9640Sstevel@tonic-gate 	 * If an alarm handler has timed out, and snoop_nrecover has
9650Sstevel@tonic-gate 	 * reached SNOOP_MAXRECOVER, skip to the next packet.
9660Sstevel@tonic-gate 	 *
9670Sstevel@tonic-gate 	 * If any other signal has occurred, and snoop_nrecover has
9680Sstevel@tonic-gate 	 * reached SNOOP_MAXRECOVER, give up.
9690Sstevel@tonic-gate 	 */
9700Sstevel@tonic-gate 	if (sig == SIGALRM) {
9710Sstevel@tonic-gate 		if (ioctl(STDOUT_FILENO, I_CANPUT, 0) == 0) {
9720Sstevel@tonic-gate 			/*
9730Sstevel@tonic-gate 			 * We've stalled on output, which is not a critical
9740Sstevel@tonic-gate 			 * failure.  Reset the recovery counter so we do not
9750Sstevel@tonic-gate 			 * consider this a persistent failure, and return so
9760Sstevel@tonic-gate 			 * we do not skip this packet.
9770Sstevel@tonic-gate 			 */
9780Sstevel@tonic-gate 			snoop_nrecover = 0;
9790Sstevel@tonic-gate 			return;
9800Sstevel@tonic-gate 		}
9810Sstevel@tonic-gate 		if (snoop_nrecover >= SNOOP_MAXRECOVER) {
9820Sstevel@tonic-gate 			fprintf(stderr,
9830Sstevel@tonic-gate 				"snoop: WARNING: skipping from packet %d\n",
9840Sstevel@tonic-gate 				count);
9850Sstevel@tonic-gate 			snoop_nrecover = 0;
9860Sstevel@tonic-gate 		} else {
9870Sstevel@tonic-gate 			/* continue trying */
9880Sstevel@tonic-gate 			return;
9890Sstevel@tonic-gate 		}
9900Sstevel@tonic-gate 	} else if (snoop_nrecover >= SNOOP_MAXRECOVER) {
9910Sstevel@tonic-gate 		fprintf(stderr,
9920Sstevel@tonic-gate 			"snoop: ERROR: cannot recover from packet %d\n", count);
9930Sstevel@tonic-gate 		exit(1);
9940Sstevel@tonic-gate 	}
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate #ifdef DEBUG
9970Sstevel@tonic-gate 	fprintf(stderr, "snoop_sigrecover(%d, %p, %p)\n", sig, info, p);
9980Sstevel@tonic-gate #endif /* DEBUG */
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate 	/*
10010Sstevel@tonic-gate 	 * Prepare to quit. This allows final processing to occur
10020Sstevel@tonic-gate 	 * after first terminal interruption.
10030Sstevel@tonic-gate 	 */
10040Sstevel@tonic-gate 	if (sig == SIGTERM || sig == SIGHUP || sig == SIGINT) {
10050Sstevel@tonic-gate 		quitting = 1;
10060Sstevel@tonic-gate 		return;
10070Sstevel@tonic-gate 	} else if (sig != -1 && sig != SIGALRM) {
10080Sstevel@tonic-gate 		/* Inform user that snoop has taken a fault */
10090Sstevel@tonic-gate 		fprintf(stderr, "WARNING: received signal %d from packet %d\n",
10100Sstevel@tonic-gate 				sig, count);
10110Sstevel@tonic-gate 	}
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate 	/* Reset interpreter variables */
10140Sstevel@tonic-gate 	snoop_recover();
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 	/* Continue in scan() with the next packet */
10170Sstevel@tonic-gate 	siglongjmp(jmp_env, 1);
10180Sstevel@tonic-gate 	/*NOTREACHED*/
10190Sstevel@tonic-gate }
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate /*
10220Sstevel@tonic-gate  * Protected malloc for global error recovery: prepare for interpreter
10230Sstevel@tonic-gate  * failures with corrupted packets or confused interpreters.  Dynamically
10240Sstevel@tonic-gate  * allocate `nbytes' bytes, and sandwich it between two PROT_NONE pages to
10250Sstevel@tonic-gate  * catch writes outside of the allocated region.
10260Sstevel@tonic-gate  */
10270Sstevel@tonic-gate static char *
10280Sstevel@tonic-gate protmalloc(size_t nbytes)
10290Sstevel@tonic-gate {
10300Sstevel@tonic-gate 	caddr_t start;
10310Sstevel@tonic-gate 	int psz = sysconf(_SC_PAGESIZE);
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate 	nbytes = P2ROUNDUP(nbytes, psz);
10340Sstevel@tonic-gate 	start = mmap(NULL, nbytes + psz * 2, PROT_READ|PROT_WRITE,
10350Sstevel@tonic-gate 	    MAP_PRIVATE|MAP_ANON, -1, 0);
10360Sstevel@tonic-gate 	if (start == MAP_FAILED) {
10370Sstevel@tonic-gate 		perror("Error: protmalloc: mmap");
10380Sstevel@tonic-gate 		return (NULL);
10390Sstevel@tonic-gate 	}
10400Sstevel@tonic-gate 	assert(IS_P2ALIGNED(start, psz));
10410Sstevel@tonic-gate 	if (mprotect(start, 1, PROT_NONE) == -1)
10420Sstevel@tonic-gate 		perror("Warning: mprotect");
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 	start += psz;
10450Sstevel@tonic-gate 	if (mprotect(start + nbytes, 1, PROT_NONE) == -1)
10460Sstevel@tonic-gate 		perror("Warning: mprotect");
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate 	return (start);
10490Sstevel@tonic-gate }
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate /*
10520Sstevel@tonic-gate  * resetperm - reduce security vulnerabilities by resetting
10530Sstevel@tonic-gate  * owner/group/permissions. Always attempt setuid() - if we have
10540Sstevel@tonic-gate  * permission to drop our privilege level, do so.
10550Sstevel@tonic-gate  */
10560Sstevel@tonic-gate void
10570Sstevel@tonic-gate resetperm(void)
10580Sstevel@tonic-gate {
10590Sstevel@tonic-gate 	if (geteuid() == 0) {
10600Sstevel@tonic-gate 		(void) setgid(GID_NOBODY);
10610Sstevel@tonic-gate 		(void) setuid(UID_NOBODY);
10620Sstevel@tonic-gate 	}
10630Sstevel@tonic-gate }
1064