Home | History | Annotate | Download | only in snoop
      1     0    stevel /*
      2     0    stevel  * CDDL HEADER START
      3     0    stevel  *
      4     0    stevel  * The contents of this file are subject to the terms of the
      5  1106       mrj  * Common Development and Distribution License (the "License").
      6  1106       mrj  * You may not use this file except in compliance with the License.
      7     0    stevel  *
      8     0    stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0    stevel  * or http://www.opensolaris.org/os/licensing.
     10     0    stevel  * See the License for the specific language governing permissions
     11     0    stevel  * and limitations under the License.
     12     0    stevel  *
     13     0    stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0    stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0    stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0    stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0    stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0    stevel  *
     19     0    stevel  * CDDL HEADER END
     20     0    stevel  */
     21  1106       mrj 
     22     0    stevel /*
     23  8868     Peter  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24     0    stevel  * Use is subject to license terms.
     25     0    stevel  */
     26     0    stevel 
     27     0    stevel #include <stdio.h>
     28     0    stevel #include <unistd.h>
     29     0    stevel #include <stropts.h>
     30     0    stevel #include <string.h>
     31     0    stevel #include <stdlib.h>
     32     0    stevel #include <fcntl.h>
     33     0    stevel #include <stdarg.h>
     34     0    stevel #include <setjmp.h>
     35     0    stevel #include <string.h>
     36     0    stevel #include <errno.h>
     37     0    stevel #include <sys/types.h>
     38     0    stevel #include <sys/time.h>
     39     0    stevel #include <signal.h>
     40     0    stevel #include <sys/mman.h>
     41     0    stevel #include <assert.h>
     42     0    stevel #include <sys/sysmacros.h>
     43     0    stevel 
     44     0    stevel #include <sys/socket.h>
     45     0    stevel #include <sys/pfmod.h>
     46     0    stevel #include <net/if.h>
     47     0    stevel #include <netinet/in_systm.h>
     48     0    stevel #include <netinet/in.h>
     49     0    stevel #include <netinet/if_ether.h>
     50     0    stevel #include <netdb.h>
     51     0    stevel 
     52     0    stevel #include "snoop.h"
     53     0    stevel 
     54  1676       jpk static int snaplen;
     55     0    stevel 
     56     0    stevel /* Global error recovery variables */
     57     0    stevel sigjmp_buf jmp_env, ojmp_env;		/* error recovery jmp buf */
     58     0    stevel int snoop_nrecover;			/* number of recoveries on curr pkt */
     59     0    stevel int quitting;				/* user termination flag */
     60     0    stevel 
     61  1676       jpk static struct snoop_handler *snoop_hp;		/* global alarm handler head */
     62  1676       jpk static struct snoop_handler *snoop_tp;		/* global alarm handler tail */
     63  1676       jpk static time_t snoop_nalarm;			/* time of next alarm */
     64     0    stevel 
     65     0    stevel /* protected interpreter output areas */
     66     0    stevel #define	MAXSUM		8
     67     0    stevel #define	REDZONE		64
     68     0    stevel static char *sumline[MAXSUM];
     69     0    stevel static char *detail_line;
     70     0    stevel static char *line;
     71     0    stevel static char *encap;
     72     0    stevel 
     73  1676       jpk static int audio;
     74     0    stevel int maxcount;	/* maximum no of packets to capture */
     75     0    stevel int count;	/* count of packets captured */
     76  1676       jpk static int sumcount;
     77     0    stevel int x_offset = -1;
     78     0    stevel int x_length = 0x7fffffff;
     79     0    stevel FILE *namefile;
     80  8023      Phil boolean_t Pflg;
     81  8023      Phil boolean_t Iflg;
     82  8023      Phil boolean_t qflg;
     83  8023      Phil boolean_t rflg;
     84     0    stevel #ifdef	DEBUG
     85  8023      Phil boolean_t zflg;
     86     0    stevel #endif
     87     0    stevel struct Pf_ext_packetfilt pf;
     88  2760  dg199075 
     89  2760  dg199075 static int vlanid = 0;
     90     0    stevel 
     91  1676       jpk static void usage(void);
     92  1676       jpk static void snoop_sigrecover(int sig, siginfo_t *info, void *p);
     93     0    stevel static char *protmalloc(size_t);
     94     0    stevel static void resetperm(void);
     95     0    stevel 
     96   410    kcpoon int
     97   410    kcpoon main(int argc, char **argv)
     98     0    stevel {
     99     0    stevel 	int c;
    100     0    stevel 	int filter = 0;
    101     0    stevel 	int flags = F_SUM;
    102     0    stevel 	struct Pf_ext_packetfilt *fp = NULL;
    103     0    stevel 	char *icapfile = NULL;
    104     0    stevel 	char *ocapfile = NULL;
    105  8023      Phil 	boolean_t nflg = B_FALSE;
    106  8023      Phil 	boolean_t Nflg = B_FALSE;
    107     0    stevel 	int Cflg = 0;
    108  8023      Phil 	boolean_t Uflg = B_FALSE;
    109     0    stevel 	int first = 1;
    110     0    stevel 	int last  = 0x7fffffff;
    111  8023      Phil 	boolean_t use_kern_pf;
    112     0    stevel 	char *p, *p2;
    113     0    stevel 	char names[MAXPATHLEN + 1];
    114     0    stevel 	char self[MAXHOSTNAMELEN + 1];
    115     0    stevel 	char *argstr = NULL;
    116     0    stevel 	void (*proc)();
    117     0    stevel 	char *audiodev;
    118     0    stevel 	int ret;
    119     0    stevel 	struct sigaction sigact;
    120     0    stevel 	stack_t sigstk;
    121     0    stevel 	char *output_area;
    122     0    stevel 	int nbytes;
    123  8868     Peter 	char *datalink = NULL;
    124  3628  ss150715 	dlpi_handle_t dh;
    125     0    stevel 
    126     0    stevel 	names[0] = '\0';
    127     0    stevel 	/*
    128     0    stevel 	 * Global error recovery: Prepare for interpreter failures
    129     0    stevel 	 * with corrupted packets or confused interpreters.
    130     0    stevel 	 * Allocate protected output and stack areas, with generous
    131     0    stevel 	 * red-zones.
    132     0    stevel 	 */
    133     0    stevel 	nbytes = (MAXSUM + 3) * (MAXLINE + REDZONE);
    134     0    stevel 	output_area = protmalloc(nbytes);
    135     0    stevel 	if (output_area == NULL) {
    136     0    stevel 		perror("Warning: mmap");
    137     0    stevel 		exit(1);
    138     0    stevel 	}
    139     0    stevel 
    140     0    stevel 	/* Allocate protected output areas */
    141     0    stevel 	for (ret = 0; ret < MAXSUM; ret++) {
    142     0    stevel 		sumline[ret] = (char *)output_area;
    143     0    stevel 		output_area += (MAXLINE + REDZONE);
    144     0    stevel 	}
    145     0    stevel 	detail_line = output_area;
    146     0    stevel 	output_area += MAXLINE + REDZONE;
    147     0    stevel 	line = output_area;
    148     0    stevel 	output_area += MAXLINE + REDZONE;
    149     0    stevel 	encap = output_area;
    150     0    stevel 	output_area += MAXLINE + REDZONE;
    151     0    stevel 
    152     0    stevel 	/* Initialize an alternate signal stack to increase robustness */
    153     0    stevel 	if ((sigstk.ss_sp = (char *)malloc(SIGSTKSZ+REDZONE)) == NULL) {
    154     0    stevel 		perror("Warning: malloc");
    155     0    stevel 		exit(1);
    156     0    stevel 	}
    157     0    stevel 	sigstk.ss_size = SIGSTKSZ;
    158     0    stevel 	sigstk.ss_flags = 0;
    159     0    stevel 	if (sigaltstack(&sigstk, (stack_t *)NULL) < 0) {
    160     0    stevel 		perror("Warning: sigaltstack");
    161     0    stevel 		exit(1);
    162     0    stevel 	}
    163     0    stevel 
    164     0    stevel 	/* Initialize a master signal handler */
    165     0    stevel 	sigact.sa_handler = NULL;
    166     0    stevel 	sigact.sa_sigaction = snoop_sigrecover;
    167  1676       jpk 	(void) sigemptyset(&sigact.sa_mask);
    168     0    stevel 	sigact.sa_flags = SA_ONSTACK|SA_SIGINFO;
    169     0    stevel 
    170     0    stevel 	/* Register master signal handler */
    171     0    stevel 	if (sigaction(SIGHUP, &sigact, (struct sigaction *)NULL) < 0) {
    172     0    stevel 		perror("Warning: sigaction");
    173     0    stevel 		exit(1);
    174     0    stevel 	}
    175     0    stevel 	if (sigaction(SIGINT, &sigact, (struct sigaction *)NULL) < 0) {
    176     0    stevel 		perror("Warning: sigaction");
    177     0    stevel 		exit(1);
    178     0    stevel 	}
    179     0    stevel 	if (sigaction(SIGQUIT, &sigact, (struct sigaction *)NULL) < 0) {
    180     0    stevel 		perror("Warning: sigaction");
    181     0    stevel 		exit(1);
    182     0    stevel 	}
    183     0    stevel 	if (sigaction(SIGILL, &sigact, (struct sigaction *)NULL) < 0) {
    184     0    stevel 		perror("Warning: sigaction");
    185     0    stevel 		exit(1);
    186     0    stevel 	}
    187     0    stevel 	if (sigaction(SIGTRAP, &sigact, (struct sigaction *)NULL) < 0) {
    188     0    stevel 		perror("Warning: sigaction");
    189     0    stevel 		exit(1);
    190     0    stevel 	}
    191     0    stevel 	if (sigaction(SIGIOT, &sigact, (struct sigaction *)NULL) < 0) {
    192     0    stevel 		perror("Warning: sigaction");
    193     0    stevel 		exit(1);
    194     0    stevel 	}
    195     0    stevel 	if (sigaction(SIGEMT, &sigact, (struct sigaction *)NULL) < 0) {
    196     0    stevel 		perror("Warning: sigaction");
    197     0    stevel 		exit(1);
    198     0    stevel 	}
    199     0    stevel 	if (sigaction(SIGFPE, &sigact, (struct sigaction *)NULL) < 0) {
    200     0    stevel 		perror("Warning: sigaction");
    201     0    stevel 		exit(1);
    202     0    stevel 	}
    203     0    stevel 	if (sigaction(SIGBUS, &sigact, (struct sigaction *)NULL) < 0) {
    204     0    stevel 		perror("Warning: sigaction");
    205     0    stevel 		exit(1);
    206     0    stevel 	}
    207     0    stevel 	if (sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL) < 0) {
    208     0    stevel 		perror("Warning: sigaction");
    209     0    stevel 		exit(1);
    210     0    stevel 	}
    211     0    stevel 	if (sigaction(SIGSYS, &sigact, (struct sigaction *)NULL) < 0) {
    212     0    stevel 		perror("Warning: sigaction");
    213     0    stevel 		exit(1);
    214     0    stevel 	}
    215     0    stevel 	if (sigaction(SIGALRM, &sigact, (struct sigaction *)NULL) < 0) {
    216     0    stevel 		perror("Warning: sigaction");
    217     0    stevel 		exit(1);
    218     0    stevel 	}
    219     0    stevel 	if (sigaction(SIGTERM, &sigact, (struct sigaction *)NULL) < 0) {
    220     0    stevel 		perror("Warning: sigaction");
    221     0    stevel 		exit(1);
    222     0    stevel 	}
    223     0    stevel 
    224     0    stevel 	/* Prepare for failure during program initialization/exit */
    225     0    stevel 	if (sigsetjmp(jmp_env, 1)) {
    226     0    stevel 		exit(1);
    227     0    stevel 	}
    228  1676       jpk 	(void) setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
    229     0    stevel 
    230  8023      Phil 	while ((c = getopt(argc, argv, "at:CPDSi:o:Nn:s:d:I:vVp:f:c:x:U?rqz"))
    231  8023      Phil 	    != EOF) {
    232     0    stevel 		switch (c) {
    233     0    stevel 		case 'a':
    234     0    stevel 			audiodev = getenv("AUDIODEV");
    235     0    stevel 			if (audiodev == NULL)
    236     0    stevel 				audiodev = "/dev/audio";
    237     0    stevel 			audio = open(audiodev, O_WRONLY);
    238     0    stevel 			if (audio < 0) {
    239     0    stevel 				pr_err("Audio device %s: %m",
    240  8023      Phil 				    audiodev);
    241     0    stevel 				exit(1);
    242     0    stevel 			}
    243     0    stevel 			break;
    244     0    stevel 		case 't':
    245     0    stevel 			flags |= F_TIME;
    246     0    stevel 			switch (*optarg) {
    247     0    stevel 			case 'r':	flags |= F_RTIME; break;
    248     0    stevel 			case 'a':	flags |= F_ATIME; break;
    249     0    stevel 			case 'd':	break;
    250     0    stevel 			default:	usage();
    251     0    stevel 			}
    252     0    stevel 			break;
    253  8023      Phil 		case 'I':
    254  8868     Peter 			if (datalink != NULL)
    255  8023      Phil 				usage();
    256  8023      Phil 			Iflg = B_TRUE;
    257  8868     Peter 			datalink = optarg;
    258  8023      Phil 			break;
    259     0    stevel 		case 'P':
    260  8023      Phil 			Pflg = B_TRUE;
    261     0    stevel 			break;
    262     0    stevel 		case 'D':
    263     0    stevel 			flags |= F_DROPS;
    264     0    stevel 			break;
    265     0    stevel 		case 'S':
    266     0    stevel 			flags |= F_LEN;
    267     0    stevel 			break;
    268     0    stevel 		case 'i':
    269     0    stevel 			icapfile = optarg;
    270     0    stevel 			break;
    271     0    stevel 		case 'o':
    272     0    stevel 			ocapfile = optarg;
    273     0    stevel 			break;
    274     0    stevel 		case 'N':
    275  8023      Phil 			Nflg = B_TRUE;
    276     0    stevel 			break;
    277     0    stevel 		case 'n':
    278  8023      Phil 			nflg = B_TRUE;
    279     0    stevel 			(void) strlcpy(names, optarg, MAXPATHLEN);
    280     0    stevel 			break;
    281     0    stevel 		case 's':
    282     0    stevel 			snaplen = atoi(optarg);
    283     0    stevel 			break;
    284     0    stevel 		case 'd':
    285  8023      Phil 			if (Iflg)
    286  8023      Phil 				usage();
    287  8868     Peter 			datalink = optarg;
    288     0    stevel 			break;
    289     0    stevel 		case 'v':
    290     0    stevel 			flags &= ~(F_SUM);
    291     0    stevel 			flags |= F_DTAIL;
    292     0    stevel 			break;
    293     0    stevel 		case 'V':
    294     0    stevel 			flags |= F_ALLSUM;
    295     0    stevel 			break;
    296     0    stevel 		case 'p':
    297     0    stevel 			p = optarg;
    298     0    stevel 			p2 = strpbrk(p, ",:-");
    299     0    stevel 			if (p2 == NULL) {
    300     0    stevel 				first = last = atoi(p);
    301     0    stevel 			} else {
    302     0    stevel 				*p2++ = '\0';
    303     0    stevel 				first = atoi(p);
    304     0    stevel 				last = atoi(p2);
    305     0    stevel 			}
    306     0    stevel 			break;
    307     0    stevel 		case 'f':
    308     0    stevel 			(void) gethostname(self, MAXHOSTNAMELEN);
    309     0    stevel 			p = strchr(optarg, ':');
    310     0    stevel 			if (p) {
    311     0    stevel 				*p = '\0';
    312     0    stevel 				if (strcmp(optarg, self) == 0 ||
    313     0    stevel 				    strcmp(p+1, self) == 0)
    314     0    stevel 				(void) fprintf(stderr,
    315     0    stevel 				"Warning: cannot capture packets from %s\n",
    316  8023      Phil 				    self);
    317     0    stevel 				*p = ' ';
    318     0    stevel 			} else if (strcmp(optarg, self) == 0)
    319     0    stevel 				(void) fprintf(stderr,
    320     0    stevel 				"Warning: cannot capture packets from %s\n",
    321  8023      Phil 				    self);
    322     0    stevel 			argstr = optarg;
    323     0    stevel 			break;
    324     0    stevel 		case 'x':
    325     0    stevel 			p = optarg;
    326     0    stevel 			p2 = strpbrk(p, ",:-");
    327     0    stevel 			if (p2 == NULL) {
    328     0    stevel 				x_offset = atoi(p);
    329     0    stevel 				x_length = -1;
    330     0    stevel 			} else {
    331     0    stevel 				*p2++ = '\0';
    332     0    stevel 				x_offset = atoi(p);
    333     0    stevel 				x_length = atoi(p2);
    334     0    stevel 			}
    335     0    stevel 			break;
    336     0    stevel 		case 'c':
    337     0    stevel 			maxcount = atoi(optarg);
    338     0    stevel 			break;
    339     0    stevel 		case 'C':
    340  8023      Phil 			Cflg = B_TRUE;
    341     0    stevel 			break;
    342     0    stevel 		case 'q':
    343     0    stevel 			qflg = B_TRUE;
    344     0    stevel 			break;
    345     0    stevel 		case 'r':
    346     0    stevel 			rflg = B_TRUE;
    347  8023      Phil 			break;
    348  8023      Phil 		case 'U':
    349  8023      Phil 			Uflg = B_TRUE;
    350     0    stevel 			break;
    351     0    stevel #ifdef	DEBUG
    352     0    stevel 		case 'z':
    353     0    stevel 			zflg = B_TRUE;
    354     0    stevel 			break;
    355     0    stevel #endif	/* DEBUG */
    356     0    stevel 		case '?':
    357     0    stevel 		default:
    358     0    stevel 			usage();
    359     0    stevel 		}
    360     0    stevel 	}
    361     0    stevel 
    362     0    stevel 	if (argc > optind)
    363     0    stevel 		argstr = (char *)concat_args(&argv[optind], argc - optind);
    364     0    stevel 
    365     0    stevel 	/*
    366     0    stevel 	 * Need to know before we decide on filtering method some things
    367     0    stevel 	 * about the interface.  So, go ahead and do part of the initialization
    368  8868     Peter 	 * now so we have that data.  Note that if no datalink is specified,
    369  8868     Peter 	 * open_datalink() selects one and returns it.  In an ideal world,
    370     0    stevel 	 * it might be nice if the "correct" interface for the filter
    371     0    stevel 	 * requested was chosen, but that's too hard.
    372     0    stevel 	 */
    373     0    stevel 	if (!icapfile) {
    374  8868     Peter 		use_kern_pf = open_datalink(&dh, datalink);
    375     0    stevel 	} else {
    376  8023      Phil 		use_kern_pf = B_FALSE;
    377     0    stevel 		cap_open_read(icapfile);
    378     0    stevel 
    379     0    stevel 		if (!nflg) {
    380     0    stevel 			names[0] = '\0';
    381     0    stevel 			(void) strlcpy(names, icapfile, MAXPATHLEN);
    382     0    stevel 			(void) strlcat(names, ".names", MAXPATHLEN);
    383     0    stevel 		}
    384     0    stevel 	}
    385  8023      Phil 
    386  8023      Phil 	if (Uflg)
    387  8023      Phil 		use_kern_pf = B_FALSE;
    388     0    stevel 
    389     0    stevel 	/* attempt to read .names file if it exists before filtering */
    390     0    stevel 	if ((!Nflg) && names[0] != '\0') {
    391     0    stevel 		if (access(names, F_OK) == 0) {
    392     0    stevel 			load_names(names);
    393     0    stevel 		} else if (nflg) {
    394     0    stevel 			(void) fprintf(stderr, "%s not found\n", names);
    395     0    stevel 			exit(1);
    396     0    stevel 		}
    397     0    stevel 	}
    398     0    stevel 
    399     0    stevel 	if (argstr) {
    400  8023      Phil 		if (use_kern_pf) {
    401     0    stevel 			ret = pf_compile(argstr, Cflg);
    402     0    stevel 			switch (ret) {
    403     0    stevel 			case 0:
    404     0    stevel 				filter++;
    405     0    stevel 				compile(argstr, Cflg);
    406     0    stevel 				break;
    407     0    stevel 			case 1:
    408     0    stevel 				fp = &pf;
    409     0    stevel 				break;
    410     0    stevel 			case 2:
    411     0    stevel 				fp = &pf;
    412     0    stevel 				filter++;
    413     0    stevel 				break;
    414     0    stevel 			}
    415     0    stevel 		} else {
    416     0    stevel 			filter++;
    417     0    stevel 			compile(argstr, Cflg);
    418     0    stevel 		}
    419     0    stevel 
    420     0    stevel 		if (Cflg)
    421     0    stevel 			exit(0);
    422     0    stevel 	}
    423     0    stevel 
    424     0    stevel 	if (flags & F_SUM)
    425     0    stevel 		flags |= F_WHO;
    426     0    stevel 
    427     0    stevel 	/*
    428     0    stevel 	 * If the -o flag is set then capture packets
    429     0    stevel 	 * directly to a file.  Don't attempt to
    430     0    stevel 	 * interpret them on the fly (F_NOW).
    431     0    stevel 	 * Note: capture to file is much less likely
    432     0    stevel 	 * to drop packets since we don't spend cpu
    433     0    stevel 	 * cycles running through the interpreters
    434     0    stevel 	 * and possibly hanging in address-to-name
    435     0    stevel 	 * mappings through the name service.
    436     0    stevel 	 */
    437     0    stevel 	if (ocapfile) {
    438     0    stevel 		cap_open_write(ocapfile);
    439     0    stevel 		proc = cap_write;
    440     0    stevel 	} else {
    441     0    stevel 		flags |= F_NOW;
    442     0    stevel 		proc = process_pkt;
    443     0    stevel 	}
    444     0    stevel 
    445     0    stevel 
    446     0    stevel 	/*
    447     0    stevel 	 * If the -i flag is set then get packets from
    448     0    stevel 	 * the log file which has been previously captured
    449     0    stevel 	 * with the -o option.
    450     0    stevel 	 */
    451     0    stevel 	if (icapfile) {
    452     0    stevel 		names[0] = '\0';
    453     0    stevel 		(void) strlcpy(names, icapfile, MAXPATHLEN);
    454     0    stevel 		(void) strlcat(names, ".names", MAXPATHLEN);
    455     0    stevel 
    456     0    stevel 		if (Nflg) {
    457     0    stevel 			namefile = fopen(names, "w");
    458     0    stevel 			if (namefile == NULL) {
    459     0    stevel 				perror(names);
    460     0    stevel 				exit(1);
    461     0    stevel 			}
    462     0    stevel 			flags = 0;
    463     0    stevel 			(void) fprintf(stderr,
    464  8023      Phil 			    "Creating name file %s\n", names);
    465     0    stevel 		}
    466     0    stevel 
    467     0    stevel 		if (flags & F_DTAIL)
    468     0    stevel 			flags = F_DTAIL;
    469     0    stevel 		else
    470     0    stevel 			flags |= F_NUM | F_TIME;
    471     0    stevel 
    472     0    stevel 		resetperm();
    473     0    stevel 		cap_read(first, last, filter, proc, flags);
    474     0    stevel 
    475     0    stevel 		if (Nflg)
    476     0    stevel 			(void) fclose(namefile);
    477     0    stevel 
    478     0    stevel 	} else {
    479     0    stevel 		const int chunksize = 8 * 8192;
    480     0    stevel 		struct timeval timeout;
    481     0    stevel 
    482     0    stevel 		/*
    483     0    stevel 		 * If listening to packets on audio
    484     0    stevel 		 * then set the buffer timeout down
    485     0    stevel 		 * to 1/10 sec.  A higher value
    486     0    stevel 		 * makes the audio "bursty".
    487     0    stevel 		 */
    488     0    stevel 		if (audio) {
    489     0    stevel 			timeout.tv_sec = 0;
    490     0    stevel 			timeout.tv_usec = 100000;
    491     0    stevel 		} else {
    492     0    stevel 			timeout.tv_sec = 1;
    493     0    stevel 			timeout.tv_usec = 0;
    494     0    stevel 		}
    495     0    stevel 
    496  8868     Peter 		init_datalink(dh, snaplen, chunksize, &timeout, fp);
    497     0    stevel 		if (! qflg && ocapfile)
    498     0    stevel 			show_count();
    499     0    stevel 		resetperm();
    500  3628  ss150715 		net_read(dh, chunksize, filter, proc, flags);
    501  3628  ss150715 		dlpi_close(dh);
    502     0    stevel 
    503     0    stevel 		if (!(flags & F_NOW))
    504  1676       jpk 			(void) printf("\n");
    505     0    stevel 	}
    506     0    stevel 
    507     0    stevel 	if (ocapfile)
    508     0    stevel 		cap_close();
    509     0    stevel 
    510     0    stevel 	return (0);
    511     0    stevel }
    512     0    stevel 
    513  1676       jpk static int tone[] = {
    514  1293  mh138676 0x076113, 0x153333, 0x147317, 0x144311, 0x147315, 0x050353, 0x037103, 0x051106,
    515  1293  mh138676 0x157155, 0x142723, 0x133273, 0x134664, 0x051712, 0x024465, 0x026447, 0x072473,
    516  1293  mh138676 0x136715, 0x126257, 0x135256, 0x047344, 0x034476, 0x027464, 0x036062, 0x133334,
    517  1293  mh138676 0x127256, 0x130660, 0x136262, 0x040724, 0x016446, 0x025437, 0x137171, 0x127672,
    518  1293  mh138676 0x124655, 0x134654, 0x032741, 0x021447, 0x037450, 0x125675, 0x127650, 0x077277,
    519  1293  mh138676 0x046514, 0x036077, 0x035471, 0x147131, 0x136272, 0x162720, 0x166151, 0x037527,
    520     0    stevel };
    521     0    stevel 
    522     0    stevel /*
    523  1293  mh138676  * Make a sound on /dev/audio according to the length of the packet.  The
    524  1293  mh138676  * tone data was ripped from /usr/share/audio/samples/au/bark.au.  The
    525  1293  mh138676  * amount of waveform used is a function of packet length e.g.  a series
    526  1293  mh138676  * of small packets is heard as clicks, whereas a series of NFS packets in
    527  1293  mh138676  * an 8k read sounds like a "WHAAAARP".
    528     0    stevel  */
    529     0    stevel void
    530     0    stevel click(len)
    531     0    stevel 	int len;
    532     0    stevel {
    533     0    stevel 	len /= 8;
    534     0    stevel 	len = len ? len : 4;
    535     0    stevel 
    536     0    stevel 	if (audio) {
    537  1676       jpk 		(void) write(audio, tone, len);
    538     0    stevel 	}
    539     0    stevel }
    540     0    stevel 
    541     0    stevel /* Display a count of packets */
    542     0    stevel void
    543     0    stevel show_count()
    544     0    stevel {
    545     0    stevel 	static int prev = -1;
    546     0    stevel 
    547     0    stevel 	if (count == prev)
    548     0    stevel 		return;
    549     0    stevel 
    550     0    stevel 	prev = count;
    551     0    stevel 	(void) fprintf(stderr, "\r%d ", count);
    552     0    stevel }
    553     0    stevel 
    554     0    stevel #define	ENCAP_LEN	16	/* Hold "(NN encap)" */
    555     0    stevel 
    556     0    stevel /*
    557     0    stevel  * Display data that's external to the packet.
    558     0    stevel  * This constitutes the first half of the summary
    559     0    stevel  * line display.
    560     0    stevel  */
    561     0    stevel void
    562     0    stevel show_pktinfo(flags, num, src, dst, ptvp, tvp, drops, len)
    563     0    stevel 	int flags, num, drops, len;
    564     0    stevel 	char *src, *dst;
    565     0    stevel 	struct timeval *ptvp, *tvp;
    566     0    stevel {
    567     0    stevel 	struct tm *tm;
    568     0    stevel 	static struct timeval tvp0;
    569     0    stevel 	int sec, usec;
    570     0    stevel 	char *lp = line;
    571     0    stevel 	int i, start;
    572     0    stevel 
    573     0    stevel 	if (flags & F_NUM) {
    574  1676       jpk 		(void) sprintf(lp, "%3d ", num);
    575     0    stevel 		lp += strlen(lp);
    576     0    stevel 	}
    577     0    stevel 	tm = localtime(&tvp->tv_sec);
    578     0    stevel 
    579     0    stevel 	if (flags & F_TIME) {
    580     0    stevel 		if (flags & F_ATIME) {
    581  1676       jpk 			(void) sprintf(lp, "%d:%02d:%d.%05d ",
    582     0    stevel 				tm->tm_hour, tm->tm_min, tm->tm_sec,
    583  1676       jpk 				(int)tvp->tv_usec / 10);
    584     0    stevel 			lp += strlen(lp);
    585     0    stevel 		} else {
    586     0    stevel 			if (flags & F_RTIME) {
    587     0    stevel 				if (tvp0.tv_sec == 0) {
    588     0    stevel 					tvp0.tv_sec = tvp->tv_sec;
    589     0    stevel 					tvp0.tv_usec = tvp->tv_usec;
    590     0    stevel 				}
    591     0    stevel 				ptvp = &tvp0;
    592     0    stevel 			}
    593     0    stevel 			sec  = tvp->tv_sec  - ptvp->tv_sec;
    594     0    stevel 			usec = tvp->tv_usec - ptvp->tv_usec;
    595     0    stevel 			if (usec < 0) {
    596     0    stevel 				usec += 1000000;
    597     0    stevel 				sec  -= 1;
    598     0    stevel 			}
    599  1676       jpk 			(void) sprintf(lp, "%3d.%05d ", sec, usec / 10);
    600     0    stevel 			lp += strlen(lp);
    601     0    stevel 		}
    602     0    stevel 	}
    603     0    stevel 
    604  2760  dg199075 	if ((flags & F_SUM) && !(flags & F_ALLSUM) && (vlanid != 0)) {
    605  2760  dg199075 		(void) snprintf(lp, MAXLINE, "VLAN#%i: ", vlanid);
    606  2760  dg199075 		lp += strlen(lp);
    607  2760  dg199075 	}
    608  2760  dg199075 
    609     0    stevel 	if (flags & F_WHO) {
    610  1676       jpk 		(void) sprintf(lp, "%12s -> %-12s ", src, dst);
    611     0    stevel 		lp += strlen(lp);
    612     0    stevel 	}
    613     0    stevel 
    614     0    stevel 	if (flags & F_DROPS) {
    615  1676       jpk 		(void) sprintf(lp, "drops: %d ", drops);
    616     0    stevel 		lp += strlen(lp);
    617     0    stevel 	}
    618     0    stevel 
    619     0    stevel 	if (flags & F_LEN) {
    620  1676       jpk 		(void) sprintf(lp, "length: %4d  ", len);
    621     0    stevel 		lp += strlen(lp);
    622     0    stevel 	}
    623     0    stevel 
    624     0    stevel 	if (flags & F_SUM) {
    625     0    stevel 		if (flags & F_ALLSUM)
    626  1676       jpk 			(void) printf("________________________________\n");
    627     0    stevel 
    628     0    stevel 		start = flags & F_ALLSUM ? 0 : sumcount - 1;
    629  1676       jpk 		(void) sprintf(encap, "  (%d encap)", total_encap_levels - 1);
    630  1676       jpk 		(void) printf("%s%s%s\n", line, sumline[start],
    631     0    stevel 		    ((flags & F_ALLSUM) || (total_encap_levels == 1)) ? "" :
    632     0    stevel 			encap);
    633     0    stevel 
    634     0    stevel 		for (i = start + 1; i < sumcount; i++)
    635  1676       jpk 			(void) printf("%s%s\n", line, sumline[i]);
    636     0    stevel 
    637     0    stevel 		sumcount = 0;
    638     0    stevel 	}
    639     0    stevel 
    640     0    stevel 	if (flags & F_DTAIL) {
    641  1676       jpk 		(void) printf("%s\n\n", detail_line);
    642     0    stevel 		detail_line[0] = '\0';
    643     0    stevel 	}
    644     0    stevel }
    645     0    stevel 
    646     0    stevel /*
    647  2760  dg199075  * The following three routines are called back
    648     0    stevel  * from the interpreters to display their stuff.
    649     0    stevel  * The theory is that when snoop becomes a window
    650     0    stevel  * based tool we can just supply a new version of
    651     0    stevel  * get_sum_line and get_detail_line and not have
    652     0    stevel  * to touch the interpreters at all.
    653     0    stevel  */
    654     0    stevel char *
    655     0    stevel get_sum_line()
    656     0    stevel {
    657     0    stevel 	int tsumcount = sumcount;
    658     0    stevel 
    659     0    stevel 	if (sumcount >= MAXSUM) {
    660     0    stevel 		sumcount = 0;			/* error recovery */
    661     0    stevel 		pr_err(
    662     0    stevel 		    "get_sum_line: sumline overflow (sumcount=%d, MAXSUM=%d)\n",
    663  8023      Phil 		    tsumcount, MAXSUM);
    664     0    stevel 	}
    665     0    stevel 
    666     0    stevel 	sumline[sumcount][0] = '\0';
    667     0    stevel 	return (sumline[sumcount++]);
    668     0    stevel }
    669     0    stevel 
    670     0    stevel /*ARGSUSED*/
    671     0    stevel char *
    672     0    stevel get_detail_line(off, len)
    673     0    stevel 	int off, len;
    674     0    stevel {
    675     0    stevel 	if (detail_line[0]) {
    676  1676       jpk 		(void) printf("%s\n", detail_line);
    677     0    stevel 		detail_line[0] = '\0';
    678     0    stevel 	}
    679     0    stevel 	return (detail_line);
    680  2760  dg199075 }
    681  2760  dg199075 
    682  2760  dg199075 /*
    683  2760  dg199075  * This function exists to make sure that VLAN information is
    684  2760  dg199075  * prepended to summary lines displayed.  The problem this function
    685  2760  dg199075  * solves is how to display VLAN information while in summary mode.
    686  2760  dg199075  * Each interpretor uses the get_sum_line and get_detail_line functions
    687  2760  dg199075  * to get a character buffer to display information to the user.
    688  2760  dg199075  * get_sum_line is the important one here.  Each call to get_sum_line
    689  2760  dg199075  * gets a buffer which stores one line of information.  In summary mode,
    690  2760  dg199075  * the last line generated is the line printed.  Instead of changing each
    691  2760  dg199075  * interpreter to add VLAN information to the summary line, the ethernet
    692  2760  dg199075  * interpreter changes to call this function and set an ID.  If the ID is not
    693  2760  dg199075  * zero and snoop is in default summary mode, snoop displays the
    694  2760  dg199075  * VLAN information at the beginning of the output line.  Otherwise,
    695  2760  dg199075  * no VLAN information is displayed.
    696  2760  dg199075  */
    697  2760  dg199075 void
    698  2760  dg199075 set_vlan_id(int id)
    699  2760  dg199075 {
    700  2760  dg199075 	vlanid = id;
    701     0    stevel }
    702     0    stevel 
    703     0    stevel /*
    704     0    stevel  * Print an error.
    705     0    stevel  * Works like printf (fmt string and variable args)
    706  1676       jpk  * except that it will substitute an error message
    707     0    stevel  * for a "%m" string (like syslog) and it calls
    708     0    stevel  * long_jump - it doesn't return to where it was
    709     0    stevel  * called from - it goes to the last setjmp().
    710     0    stevel  */
    711  1676       jpk /* VARARGS1 */
    712     0    stevel void
    713  1676       jpk pr_err(const char *fmt, ...)
    714     0    stevel {
    715     0    stevel 	va_list ap;
    716  1676       jpk 	char buf[1024], *p2;
    717  1676       jpk 	const char *p1;
    718     0    stevel 
    719  1676       jpk 	(void) strcpy(buf, "snoop: ");
    720     0    stevel 	p2 = buf + strlen(buf);
    721     0    stevel 
    722  1676       jpk 	/*
    723  1676       jpk 	 * Note that we terminate the buffer with '\n' and '\0'.
    724  1676       jpk 	 */
    725  1676       jpk 	for (p1 = fmt; *p1 != '\0' && p2 < buf + sizeof (buf) - 2; p1++) {
    726     0    stevel 		if (*p1 == '%' && *(p1+1) == 'm') {
    727  1676       jpk 			const char *errstr;
    728     0    stevel 
    729  1676       jpk 			if ((errstr = strerror(errno)) != NULL) {
    730  1676       jpk 				*p2 = '\0';
    731  1676       jpk 				(void) strlcat(buf, errstr, sizeof (buf));
    732     0    stevel 				p2 += strlen(p2);
    733     0    stevel 			}
    734     0    stevel 			p1++;
    735     0    stevel 		} else {
    736     0    stevel 			*p2++ = *p1;
    737     0    stevel 		}
    738     0    stevel 	}
    739     0    stevel 	if (p2 > buf && *(p2-1) != '\n')
    740     0    stevel 		*p2++ = '\n';
    741     0    stevel 	*p2 = '\0';
    742     0    stevel 
    743     0    stevel 	va_start(ap, fmt);
    744  1676       jpk 	/* LINTED: E_SEC_PRINTF_VAR_FMT */
    745     0    stevel 	(void) vfprintf(stderr, buf, ap);
    746     0    stevel 	va_end(ap);
    747     0    stevel 	snoop_sigrecover(-1, NULL, NULL);	/* global error recovery */
    748  3628  ss150715 }
    749  3628  ss150715 
    750  3628  ss150715 /*
    751  3628  ss150715  * Store a copy of linkname associated with the DLPI handle.
    752  3628  ss150715  * Save errno before closing the dlpi handle so that the
    753  3628  ss150715  * correct error value is used if 'err' is a system error.
    754  3628  ss150715  */
    755  3628  ss150715 void
    756  3628  ss150715 pr_errdlpi(dlpi_handle_t dh, const char *cmd, int err)
    757  3628  ss150715 {
    758  3628  ss150715 	int save_errno = errno;
    759  3628  ss150715 	char linkname[DLPI_LINKNAME_MAX];
    760  3628  ss150715 
    761  3628  ss150715 	(void) strlcpy(linkname, dlpi_linkname(dh), sizeof (linkname));
    762  3628  ss150715 
    763  3628  ss150715 	dlpi_close(dh);
    764  3628  ss150715 	errno = save_errno;
    765  3628  ss150715 
    766  3628  ss150715 	pr_err("%s on \"%s\": %s", cmd, linkname, dlpi_strerror(err));
    767     0    stevel }
    768     0    stevel 
    769     0    stevel /*
    770     0    stevel  * Ye olde usage proc
    771     0    stevel  * PLEASE keep this up to date!
    772     0    stevel  * Naive users *love* this stuff.
    773     0    stevel  */
    774  1676       jpk static void
    775  1676       jpk usage(void)
    776     0    stevel {
    777     0    stevel 	(void) fprintf(stderr, "\nUsage:  snoop\n");
    778     0    stevel 	(void) fprintf(stderr,
    779     0    stevel 	"\t[ -a ]			# Listen to packets on audio\n");
    780     0    stevel 	(void) fprintf(stderr,
    781  8023      Phil 	"\t[ -d link ]		# Listen on named link\n");
    782     0    stevel 	(void) fprintf(stderr,
    783     0    stevel 	"\t[ -s snaplen ]		# Truncate packets\n");
    784  8023      Phil 	(void) fprintf(stderr,
    785  8023      Phil 	"\t[ -I IP interface ]		# Listen on named IP interface\n");
    786     0    stevel 	(void) fprintf(stderr,
    787     0    stevel 	"\t[ -c count ]		# Quit after count packets\n");
    788     0    stevel 	(void) fprintf(stderr,
    789     0    stevel 	"\t[ -P ]			# Turn OFF promiscuous mode\n");
    790     0    stevel 	(void) fprintf(stderr,
    791     0    stevel 	"\t[ -D ]			# Report dropped packets\n");
    792     0    stevel 	(void) fprintf(stderr,
    793     0    stevel 	"\t[ -S ]			# Report packet size\n");
    794     0    stevel 	(void) fprintf(stderr,
    795     0    stevel 	"\t[ -i file ]		# Read previously captured packets\n");
    796     0    stevel 	(void) fprintf(stderr,
    797     0    stevel 	"\t[ -o file ]		# Capture packets in file\n");
    798     0    stevel 	(void) fprintf(stderr,
    799     0    stevel 	"\t[ -n file ]		# Load addr-to-name table from file\n");
    800     0    stevel 	(void) fprintf(stderr,
    801     0    stevel 	"\t[ -N ]			# Create addr-to-name table\n");
    802     0    stevel 	(void) fprintf(stderr,
    803     0    stevel 	"\t[ -t  r|a|d ]		# Time: Relative, Absolute or Delta\n");
    804     0    stevel 	(void) fprintf(stderr,
    805     0    stevel 	"\t[ -v ]			# Verbose packet display\n");
    806     0    stevel 	(void) fprintf(stderr,
    807     0    stevel 	"\t[ -V ]			# Show all summary lines\n");
    808     0    stevel 	(void) fprintf(stderr,
    809     0    stevel 	"\t[ -p first[,last] ]	# Select packet(s) to display\n");
    810     0    stevel 	(void) fprintf(stderr,
    811     0    stevel 	"\t[ -x offset[,length] ]	# Hex dump from offset for length\n");
    812     0    stevel 	(void) fprintf(stderr,
    813     0    stevel 	"\t[ -C ]			# Print packet filter code\n");
    814     0    stevel 	(void) fprintf(stderr,
    815     0    stevel 	"\t[ -q ]			# Suppress printing packet count\n");
    816     0    stevel 	(void) fprintf(stderr,
    817     0    stevel 	"\t[ -r ]			# Do not resolve address to name\n");
    818     0    stevel 	(void) fprintf(stderr,
    819     0    stevel 	"\n\t[ filter expression ]\n");
    820     0    stevel 	(void) fprintf(stderr, "\nExample:\n");
    821     0    stevel 	(void) fprintf(stderr, "\tsnoop -o saved  host fred\n\n");
    822     0    stevel 	(void) fprintf(stderr, "\tsnoop -i saved -tr -v -p19\n");
    823     0    stevel 	exit(1);
    824     0    stevel }
    825     0    stevel 
    826     0    stevel /*
    827     0    stevel  * sdefault: default global alarm handler. Causes the current packet
    828     0    stevel  * to be skipped.
    829     0    stevel  */
    830     0    stevel static void
    831     0    stevel sdefault(void)
    832     0    stevel {
    833     0    stevel 	snoop_nrecover = SNOOP_MAXRECOVER;
    834     0    stevel }
    835     0    stevel 
    836     0    stevel /*
    837     0    stevel  * snoop_alarm: register or unregister an alarm handler to be called after
    838     0    stevel  * s_sec seconds. Because snoop wasn't written to tolerate random signal
    839     0    stevel  * delivery, periodic SIGALRM delivery (or SA_RESTART) cannot be used.
    840     0    stevel  *
    841     0    stevel  * s_sec argument of 0 seconds unregisters the handler.
    842     0    stevel  * s_handler argument of NULL registers default handler sdefault(), or
    843     0    stevel  * unregisters all signal handlers (for error recovery).
    844     0    stevel  *
    845     0    stevel  * Variables must be volatile to force the compiler to not optimize
    846     0    stevel  * out the signal blocking.
    847     0    stevel  */
    848     0    stevel /*ARGSUSED*/
    849     0    stevel int
    850     0    stevel snoop_alarm(int s_sec, void (*s_handler)())
    851     0    stevel {
    852     0    stevel 	volatile time_t now;
    853     0    stevel 	volatile time_t nalarm = 0;
    854     0    stevel 	volatile struct snoop_handler *sh = NULL;
    855     0    stevel 	volatile struct snoop_handler *hp, *tp, *next;
    856     0    stevel 	volatile sigset_t s_mask;
    857     0    stevel 	volatile int ret = -1;
    858     0    stevel 
    859  1676       jpk 	(void) sigemptyset((sigset_t *)&s_mask);
    860  1676       jpk 	(void) sigaddset((sigset_t *)&s_mask, SIGALRM);
    861     0    stevel 	if (s_sec < 0)
    862     0    stevel 		return (-1);
    863     0    stevel 
    864     0    stevel 	/* register an alarm handler */
    865     0    stevel 	now = time(NULL);
    866     0    stevel 	if (s_sec) {
    867     0    stevel 		sh = malloc(sizeof (struct snoop_handler));
    868     0    stevel 		sh->s_time = now + s_sec;
    869     0    stevel 		if (s_handler == NULL)
    870     0    stevel 			s_handler = sdefault;
    871     0    stevel 		sh->s_handler = s_handler;
    872     0    stevel 		sh->s_next = NULL;
    873     0    stevel 		(void) sigprocmask(SIG_BLOCK, (sigset_t *)&s_mask, NULL);
    874     0    stevel 		if (snoop_hp == NULL) {
    875     0    stevel 			snoop_hp = snoop_tp = (struct snoop_handler *)sh;
    876     0    stevel 
    877     0    stevel 			snoop_nalarm = sh->s_time;
    878  1676       jpk 			(void) alarm(sh->s_time - now);
    879     0    stevel 		} else {
    880     0    stevel 			snoop_tp->s_next = (struct snoop_handler *)sh;
    881     0    stevel 			snoop_tp = (struct snoop_handler *)sh;
    882     0    stevel 
    883     0    stevel 			if (sh->s_time < snoop_nalarm) {
    884     0    stevel 				snoop_nalarm = sh->s_time;
    885     0    stevel 				(void) alarm(sh->s_time - now);
    886     0    stevel 			}
    887     0    stevel 		}
    888     0    stevel 		(void) sigprocmask(SIG_UNBLOCK, (sigset_t *)&s_mask, NULL);
    889     0    stevel 
    890     0    stevel 		return (0);
    891     0    stevel 	}
    892     0    stevel 
    893     0    stevel 	/* unregister an alarm handler */
    894     0    stevel 	(void) sigprocmask(SIG_BLOCK, (sigset_t *)&s_mask, NULL);
    895     0    stevel 	tp = (struct snoop_handler *)&snoop_hp;
    896     0    stevel 	for (hp = snoop_hp; hp; hp = next) {
    897     0    stevel 		next = hp->s_next;
    898     0    stevel 		if (s_handler == NULL || hp->s_handler == s_handler) {
    899     0    stevel 			ret = 0;
    900     0    stevel 			tp->s_next = hp->s_next;
    901     0    stevel 			if (snoop_tp == hp) {
    902     0    stevel 				if (tp == (struct snoop_handler *)&snoop_hp)
    903     0    stevel 					snoop_tp = NULL;
    904     0    stevel 				else
    905     0    stevel 					snoop_tp = (struct snoop_handler *)tp;
    906     0    stevel 			}
    907     0    stevel 			free((void *)hp);
    908     0    stevel 		} else {
    909     0    stevel 			if (nalarm == 0 || nalarm > hp->s_time)
    910     0    stevel 				nalarm = now < hp->s_time ? hp->s_time :
    911  8023      Phil 				    now + 1;
    912     0    stevel 			tp = hp;
    913     0    stevel 		}
    914     0    stevel 	}
    915     0    stevel 	/*
    916     0    stevel 	 * Stop or adjust timer
    917     0    stevel 	 */
    918     0    stevel 	if (snoop_hp == NULL) {
    919     0    stevel 		snoop_nalarm = 0;
    920     0    stevel 		(void) alarm(0);
    921     0    stevel 	} else if (nalarm > 0 && nalarm < snoop_nalarm) {
    922     0    stevel 		snoop_nalarm = nalarm;
    923     0    stevel 		(void) alarm(nalarm - now);
    924     0    stevel 	}
    925     0    stevel 
    926     0    stevel 	(void) sigprocmask(SIG_UNBLOCK, (sigset_t *)&s_mask, NULL);
    927     0    stevel 	return (ret);
    928     0    stevel }
    929     0    stevel 
    930     0    stevel /*
    931     0    stevel  * snoop_recover: reset snoop's output area, and any internal variables,
    932     0    stevel  * to allow continuation.
    933     0    stevel  * XXX: make this an interface such that each interpreter can
    934     0    stevel  * register a reset routine.
    935     0    stevel  */
    936     0    stevel void
    937     0    stevel snoop_recover(void)
    938     0    stevel {
    939     0    stevel 	int i;
    940     0    stevel 
    941     0    stevel 	/* Error recovery: reset output_area and associated variables */
    942     0    stevel 	for (i = 0; i < MAXSUM; i++)
    943     0    stevel 		sumline[i][0] = '\0';
    944     0    stevel 	detail_line[0] = '\0';
    945     0    stevel 	line[0] = '\0';
    946     0    stevel 	encap[0] = '\0';
    947     0    stevel 	sumcount = 0;
    948     0    stevel 
    949     0    stevel 	/* stacking/unstacking cannot be relied upon */
    950     0    stevel 	encap_levels = 0;
    951     0    stevel 	total_encap_levels = 1;
    952     0    stevel 
    953     0    stevel 	/* remove any pending timeouts */
    954     0    stevel 	(void) snoop_alarm(0, NULL);
    955     0    stevel }
    956     0    stevel 
    957     0    stevel /*
    958     0    stevel  * snoop_sigrecover: global sigaction routine to manage recovery
    959     0    stevel  * from catastrophic interpreter failures while interpreting
    960     0    stevel  * corrupt trace files/packets. SIGALRM timeouts, program errors,
    961     0    stevel  * and user termination are all handled. In the case of a corrupt
    962     0    stevel  * packet or confused interpreter, the packet will be skipped, and
    963     0    stevel  * execution will continue in scan().
    964     0    stevel  *
    965     0    stevel  * Global alarm handling (see snoop_alarm()) is managed here.
    966     0    stevel  *
    967     0    stevel  * Variables must be volatile to force the compiler to not optimize
    968     0    stevel  * out the signal blocking.
    969     0    stevel  */
    970     0    stevel /*ARGSUSED*/
    971  1676       jpk static void
    972     0    stevel snoop_sigrecover(int sig, siginfo_t *info, void *p)
    973     0    stevel {
    974     0    stevel 	volatile time_t now;
    975     0    stevel 	volatile time_t nalarm = 0;
    976     0    stevel 	volatile struct snoop_handler *hp;
    977     0    stevel 
    978     0    stevel 	/*
    979     0    stevel 	 * Invoke any registered alarms. This involves first calculating
    980     0    stevel 	 * the time for the next alarm, setting it up, then progressing
    981     0    stevel 	 * through handler invocations. Note that since handlers may
    982     0    stevel 	 * use siglongjmp(), in the worst case handlers may be serviced
    983     0    stevel 	 * at a later time.
    984     0    stevel 	 */
    985     0    stevel 	if (sig == SIGALRM) {
    986     0    stevel 		now = time(NULL);
    987     0    stevel 		/* Calculate next alarm time */
    988     0    stevel 		for (hp = snoop_hp; hp; hp = hp->s_next) {
    989     0    stevel 			if (hp->s_time) {
    990     0    stevel 				if ((hp->s_time - now) > 0) {
    991     0    stevel 					if (nalarm == 0 || nalarm > hp->s_time)
    992     0    stevel 						nalarm = now < hp->s_time ?
    993  8023      Phil 						    hp->s_time : now + 1;
    994     0    stevel 				}
    995     0    stevel 			}
    996     0    stevel 		}
    997     0    stevel 		/* Setup next alarm */
    998     0    stevel 		if (nalarm) {
    999     0    stevel 			snoop_nalarm = nalarm;
   1000  1676       jpk 			(void) alarm(nalarm - now);
   1001     0    stevel 		} else {
   1002     0    stevel 			snoop_nalarm = 0;
   1003     0    stevel 		}
   1004     0    stevel 
   1005     0    stevel 		/* Invoke alarm handlers (may not return) */
   1006     0    stevel 		for (hp = snoop_hp; hp; hp = hp->s_next) {
   1007     0    stevel 			if (hp->s_time) {
   1008     0    stevel 				if ((now - hp->s_time) >= 0) {
   1009     0    stevel 					hp->s_time = 0;	/* only invoke once */
   1010     0    stevel 					if (hp->s_handler)
   1011     0    stevel 						hp->s_handler();
   1012     0    stevel 				}
   1013     0    stevel 			}
   1014     0    stevel 		}
   1015     0    stevel 	} else {
   1016     0    stevel 		snoop_nrecover++;
   1017     0    stevel 	}
   1018     0    stevel 
   1019     0    stevel 	/*
   1020     0    stevel 	 * Exit if a signal has occurred after snoop has begun the process
   1021     0    stevel 	 * of quitting.
   1022     0    stevel 	 */
   1023     0    stevel 	if (quitting)
   1024     0    stevel 		exit(1);
   1025     0    stevel 
   1026     0    stevel 	/*
   1027     0    stevel 	 * If an alarm handler has timed out, and snoop_nrecover has
   1028     0    stevel 	 * reached SNOOP_MAXRECOVER, skip to the next packet.
   1029     0    stevel 	 *
   1030     0    stevel 	 * If any other signal has occurred, and snoop_nrecover has
   1031     0    stevel 	 * reached SNOOP_MAXRECOVER, give up.
   1032     0    stevel 	 */
   1033     0    stevel 	if (sig == SIGALRM) {
   1034     0    stevel 		if (ioctl(STDOUT_FILENO, I_CANPUT, 0) == 0) {
   1035     0    stevel 			/*
   1036     0    stevel 			 * We've stalled on output, which is not a critical
   1037     0    stevel 			 * failure.  Reset the recovery counter so we do not
   1038     0    stevel 			 * consider this a persistent failure, and return so
   1039     0    stevel 			 * we do not skip this packet.
   1040     0    stevel 			 */
   1041     0    stevel 			snoop_nrecover = 0;
   1042     0    stevel 			return;
   1043     0    stevel 		}
   1044     0    stevel 		if (snoop_nrecover >= SNOOP_MAXRECOVER) {
   1045  1676       jpk 			(void) fprintf(stderr,
   1046  8023      Phil 			    "snoop: WARNING: skipping from packet %d\n",
   1047  8023      Phil 			    count);
   1048     0    stevel 			snoop_nrecover = 0;
   1049     0    stevel 		} else {
   1050     0    stevel 			/* continue trying */
   1051     0    stevel 			return;
   1052     0    stevel 		}
   1053     0    stevel 	} else if (snoop_nrecover >= SNOOP_MAXRECOVER) {
   1054  1676       jpk 		(void) fprintf(stderr,
   1055  8023      Phil 		    "snoop: ERROR: cannot recover from packet %d\n", count);
   1056     0    stevel 		exit(1);
   1057     0    stevel 	}
   1058     0    stevel 
   1059     0    stevel #ifdef DEBUG
   1060  1676       jpk 	(void) fprintf(stderr, "snoop_sigrecover(%d, %p, %p)\n", sig, info, p);
   1061     0    stevel #endif /* DEBUG */
   1062     0    stevel 
   1063     0    stevel 	/*
   1064     0    stevel 	 * Prepare to quit. This allows final processing to occur
   1065     0    stevel 	 * after first terminal interruption.
   1066     0    stevel 	 */
   1067     0    stevel 	if (sig == SIGTERM || sig == SIGHUP || sig == SIGINT) {
   1068     0    stevel 		quitting = 1;
   1069     0    stevel 		return;
   1070     0    stevel 	} else if (sig != -1 && sig != SIGALRM) {
   1071     0    stevel 		/* Inform user that snoop has taken a fault */
   1072  1676       jpk 		(void) fprintf(stderr,
   1073  1676       jpk 		    "WARNING: received signal %d from packet %d\n",
   1074  8023      Phil 		    sig, count);
   1075     0    stevel 	}
   1076     0    stevel 
   1077     0    stevel 	/* Reset interpreter variables */
   1078     0    stevel 	snoop_recover();
   1079     0    stevel 
   1080     0    stevel 	/* Continue in scan() with the next packet */
   1081     0    stevel 	siglongjmp(jmp_env, 1);
   1082     0    stevel 	/*NOTREACHED*/
   1083     0    stevel }
   1084     0    stevel 
   1085     0    stevel /*
   1086     0    stevel  * Protected malloc for global error recovery: prepare for interpreter
   1087     0    stevel  * failures with corrupted packets or confused interpreters.  Dynamically
   1088     0    stevel  * allocate `nbytes' bytes, and sandwich it between two PROT_NONE pages to
   1089     0    stevel  * catch writes outside of the allocated region.
   1090     0    stevel  */
   1091     0    stevel static char *
   1092     0    stevel protmalloc(size_t nbytes)
   1093     0    stevel {
   1094     0    stevel 	caddr_t start;
   1095     0    stevel 	int psz = sysconf(_SC_PAGESIZE);
   1096     0    stevel 
   1097     0    stevel 	nbytes = P2ROUNDUP(nbytes, psz);
   1098     0    stevel 	start = mmap(NULL, nbytes + psz * 2, PROT_READ|PROT_WRITE,
   1099     0    stevel 	    MAP_PRIVATE|MAP_ANON, -1, 0);
   1100     0    stevel 	if (start == MAP_FAILED) {
   1101     0    stevel 		perror("Error: protmalloc: mmap");
   1102     0    stevel 		return (NULL);
   1103     0    stevel 	}
   1104     0    stevel 	assert(IS_P2ALIGNED(start, psz));
   1105     0    stevel 	if (mprotect(start, 1, PROT_NONE) == -1)
   1106     0    stevel 		perror("Warning: mprotect");
   1107     0    stevel 
   1108     0    stevel 	start += psz;
   1109     0    stevel 	if (mprotect(start + nbytes, 1, PROT_NONE) == -1)
   1110     0    stevel 		perror("Warning: mprotect");
   1111     0    stevel 
   1112     0    stevel 	return (start);
   1113     0    stevel }
   1114     0    stevel 
   1115     0    stevel /*
   1116     0    stevel  * resetperm - reduce security vulnerabilities by resetting
   1117     0    stevel  * owner/group/permissions. Always attempt setuid() - if we have
   1118     0    stevel  * permission to drop our privilege level, do so.
   1119     0    stevel  */
   1120     0    stevel void
   1121     0    stevel resetperm(void)
   1122     0    stevel {
   1123     0    stevel 	if (geteuid() == 0) {
   1124     0    stevel 		(void) setgid(GID_NOBODY);
   1125     0    stevel 		(void) setuid(UID_NOBODY);
   1126     0    stevel 	}
   1127     0    stevel }
   1128