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*8868SPeter.Memishian@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #include <stdio.h>
280Sstevel@tonic-gate #include <unistd.h>
290Sstevel@tonic-gate #include <stropts.h>
300Sstevel@tonic-gate #include <string.h>
310Sstevel@tonic-gate #include <stdlib.h>
320Sstevel@tonic-gate #include <fcntl.h>
330Sstevel@tonic-gate #include <stdarg.h>
340Sstevel@tonic-gate #include <setjmp.h>
350Sstevel@tonic-gate #include <string.h>
360Sstevel@tonic-gate #include <errno.h>
370Sstevel@tonic-gate #include <sys/types.h>
380Sstevel@tonic-gate #include <sys/time.h>
390Sstevel@tonic-gate #include <signal.h>
400Sstevel@tonic-gate #include <sys/mman.h>
410Sstevel@tonic-gate #include <assert.h>
420Sstevel@tonic-gate #include <sys/sysmacros.h>
430Sstevel@tonic-gate
440Sstevel@tonic-gate #include <sys/socket.h>
450Sstevel@tonic-gate #include <sys/pfmod.h>
460Sstevel@tonic-gate #include <net/if.h>
470Sstevel@tonic-gate #include <netinet/in_systm.h>
480Sstevel@tonic-gate #include <netinet/in.h>
490Sstevel@tonic-gate #include <netinet/if_ether.h>
500Sstevel@tonic-gate #include <netdb.h>
510Sstevel@tonic-gate
520Sstevel@tonic-gate #include "snoop.h"
530Sstevel@tonic-gate
541676Sjpk static int snaplen;
550Sstevel@tonic-gate
560Sstevel@tonic-gate /* Global error recovery variables */
570Sstevel@tonic-gate sigjmp_buf jmp_env, ojmp_env; /* error recovery jmp buf */
580Sstevel@tonic-gate int snoop_nrecover; /* number of recoveries on curr pkt */
590Sstevel@tonic-gate int quitting; /* user termination flag */
600Sstevel@tonic-gate
611676Sjpk static struct snoop_handler *snoop_hp; /* global alarm handler head */
621676Sjpk static struct snoop_handler *snoop_tp; /* global alarm handler tail */
631676Sjpk static time_t snoop_nalarm; /* time of next alarm */
640Sstevel@tonic-gate
650Sstevel@tonic-gate /* protected interpreter output areas */
660Sstevel@tonic-gate #define MAXSUM 8
670Sstevel@tonic-gate #define REDZONE 64
680Sstevel@tonic-gate static char *sumline[MAXSUM];
690Sstevel@tonic-gate static char *detail_line;
700Sstevel@tonic-gate static char *line;
710Sstevel@tonic-gate static char *encap;
720Sstevel@tonic-gate
731676Sjpk static int audio;
740Sstevel@tonic-gate int maxcount; /* maximum no of packets to capture */
750Sstevel@tonic-gate int count; /* count of packets captured */
761676Sjpk static int sumcount;
770Sstevel@tonic-gate int x_offset = -1;
780Sstevel@tonic-gate int x_length = 0x7fffffff;
790Sstevel@tonic-gate FILE *namefile;
808023SPhil.Kirk@Sun.COM boolean_t Pflg;
818023SPhil.Kirk@Sun.COM boolean_t Iflg;
828023SPhil.Kirk@Sun.COM boolean_t qflg;
838023SPhil.Kirk@Sun.COM boolean_t rflg;
840Sstevel@tonic-gate #ifdef DEBUG
858023SPhil.Kirk@Sun.COM boolean_t zflg;
860Sstevel@tonic-gate #endif
870Sstevel@tonic-gate struct Pf_ext_packetfilt pf;
880Sstevel@tonic-gate
892760Sdg199075 static int vlanid = 0;
902760Sdg199075
911676Sjpk static void usage(void);
921676Sjpk static void snoop_sigrecover(int sig, siginfo_t *info, void *p);
930Sstevel@tonic-gate static char *protmalloc(size_t);
940Sstevel@tonic-gate static void resetperm(void);
950Sstevel@tonic-gate
96410Skcpoon int
main(int argc,char ** argv)97410Skcpoon main(int argc, char **argv)
980Sstevel@tonic-gate {
990Sstevel@tonic-gate int c;
1000Sstevel@tonic-gate int filter = 0;
1010Sstevel@tonic-gate int flags = F_SUM;
1020Sstevel@tonic-gate struct Pf_ext_packetfilt *fp = NULL;
1030Sstevel@tonic-gate char *icapfile = NULL;
1040Sstevel@tonic-gate char *ocapfile = NULL;
1058023SPhil.Kirk@Sun.COM boolean_t nflg = B_FALSE;
1068023SPhil.Kirk@Sun.COM boolean_t Nflg = B_FALSE;
1070Sstevel@tonic-gate int Cflg = 0;
1088023SPhil.Kirk@Sun.COM boolean_t Uflg = B_FALSE;
1090Sstevel@tonic-gate int first = 1;
1100Sstevel@tonic-gate int last = 0x7fffffff;
1118023SPhil.Kirk@Sun.COM boolean_t use_kern_pf;
1120Sstevel@tonic-gate char *p, *p2;
1130Sstevel@tonic-gate char names[MAXPATHLEN + 1];
1140Sstevel@tonic-gate char self[MAXHOSTNAMELEN + 1];
1150Sstevel@tonic-gate char *argstr = NULL;
1160Sstevel@tonic-gate void (*proc)();
1170Sstevel@tonic-gate char *audiodev;
1180Sstevel@tonic-gate int ret;
1190Sstevel@tonic-gate struct sigaction sigact;
1200Sstevel@tonic-gate stack_t sigstk;
1210Sstevel@tonic-gate char *output_area;
1220Sstevel@tonic-gate int nbytes;
123*8868SPeter.Memishian@Sun.COM char *datalink = NULL;
1243628Sss150715 dlpi_handle_t dh;
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate names[0] = '\0';
1270Sstevel@tonic-gate /*
1280Sstevel@tonic-gate * Global error recovery: Prepare for interpreter failures
1290Sstevel@tonic-gate * with corrupted packets or confused interpreters.
1300Sstevel@tonic-gate * Allocate protected output and stack areas, with generous
1310Sstevel@tonic-gate * red-zones.
1320Sstevel@tonic-gate */
1330Sstevel@tonic-gate nbytes = (MAXSUM + 3) * (MAXLINE + REDZONE);
1340Sstevel@tonic-gate output_area = protmalloc(nbytes);
1350Sstevel@tonic-gate if (output_area == NULL) {
1360Sstevel@tonic-gate perror("Warning: mmap");
1370Sstevel@tonic-gate exit(1);
1380Sstevel@tonic-gate }
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate /* Allocate protected output areas */
1410Sstevel@tonic-gate for (ret = 0; ret < MAXSUM; ret++) {
1420Sstevel@tonic-gate sumline[ret] = (char *)output_area;
1430Sstevel@tonic-gate output_area += (MAXLINE + REDZONE);
1440Sstevel@tonic-gate }
1450Sstevel@tonic-gate detail_line = output_area;
1460Sstevel@tonic-gate output_area += MAXLINE + REDZONE;
1470Sstevel@tonic-gate line = output_area;
1480Sstevel@tonic-gate output_area += MAXLINE + REDZONE;
1490Sstevel@tonic-gate encap = output_area;
1500Sstevel@tonic-gate output_area += MAXLINE + REDZONE;
1510Sstevel@tonic-gate
1520Sstevel@tonic-gate /* Initialize an alternate signal stack to increase robustness */
1530Sstevel@tonic-gate if ((sigstk.ss_sp = (char *)malloc(SIGSTKSZ+REDZONE)) == NULL) {
1540Sstevel@tonic-gate perror("Warning: malloc");
1550Sstevel@tonic-gate exit(1);
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate sigstk.ss_size = SIGSTKSZ;
1580Sstevel@tonic-gate sigstk.ss_flags = 0;
1590Sstevel@tonic-gate if (sigaltstack(&sigstk, (stack_t *)NULL) < 0) {
1600Sstevel@tonic-gate perror("Warning: sigaltstack");
1610Sstevel@tonic-gate exit(1);
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate /* Initialize a master signal handler */
1650Sstevel@tonic-gate sigact.sa_handler = NULL;
1660Sstevel@tonic-gate sigact.sa_sigaction = snoop_sigrecover;
1671676Sjpk (void) sigemptyset(&sigact.sa_mask);
1680Sstevel@tonic-gate sigact.sa_flags = SA_ONSTACK|SA_SIGINFO;
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate /* Register master signal handler */
1710Sstevel@tonic-gate if (sigaction(SIGHUP, &sigact, (struct sigaction *)NULL) < 0) {
1720Sstevel@tonic-gate perror("Warning: sigaction");
1730Sstevel@tonic-gate exit(1);
1740Sstevel@tonic-gate }
1750Sstevel@tonic-gate if (sigaction(SIGINT, &sigact, (struct sigaction *)NULL) < 0) {
1760Sstevel@tonic-gate perror("Warning: sigaction");
1770Sstevel@tonic-gate exit(1);
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate if (sigaction(SIGQUIT, &sigact, (struct sigaction *)NULL) < 0) {
1800Sstevel@tonic-gate perror("Warning: sigaction");
1810Sstevel@tonic-gate exit(1);
1820Sstevel@tonic-gate }
1830Sstevel@tonic-gate if (sigaction(SIGILL, &sigact, (struct sigaction *)NULL) < 0) {
1840Sstevel@tonic-gate perror("Warning: sigaction");
1850Sstevel@tonic-gate exit(1);
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate if (sigaction(SIGTRAP, &sigact, (struct sigaction *)NULL) < 0) {
1880Sstevel@tonic-gate perror("Warning: sigaction");
1890Sstevel@tonic-gate exit(1);
1900Sstevel@tonic-gate }
1910Sstevel@tonic-gate if (sigaction(SIGIOT, &sigact, (struct sigaction *)NULL) < 0) {
1920Sstevel@tonic-gate perror("Warning: sigaction");
1930Sstevel@tonic-gate exit(1);
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate if (sigaction(SIGEMT, &sigact, (struct sigaction *)NULL) < 0) {
1960Sstevel@tonic-gate perror("Warning: sigaction");
1970Sstevel@tonic-gate exit(1);
1980Sstevel@tonic-gate }
1990Sstevel@tonic-gate if (sigaction(SIGFPE, &sigact, (struct sigaction *)NULL) < 0) {
2000Sstevel@tonic-gate perror("Warning: sigaction");
2010Sstevel@tonic-gate exit(1);
2020Sstevel@tonic-gate }
2030Sstevel@tonic-gate if (sigaction(SIGBUS, &sigact, (struct sigaction *)NULL) < 0) {
2040Sstevel@tonic-gate perror("Warning: sigaction");
2050Sstevel@tonic-gate exit(1);
2060Sstevel@tonic-gate }
2070Sstevel@tonic-gate if (sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL) < 0) {
2080Sstevel@tonic-gate perror("Warning: sigaction");
2090Sstevel@tonic-gate exit(1);
2100Sstevel@tonic-gate }
2110Sstevel@tonic-gate if (sigaction(SIGSYS, &sigact, (struct sigaction *)NULL) < 0) {
2120Sstevel@tonic-gate perror("Warning: sigaction");
2130Sstevel@tonic-gate exit(1);
2140Sstevel@tonic-gate }
2150Sstevel@tonic-gate if (sigaction(SIGALRM, &sigact, (struct sigaction *)NULL) < 0) {
2160Sstevel@tonic-gate perror("Warning: sigaction");
2170Sstevel@tonic-gate exit(1);
2180Sstevel@tonic-gate }
2190Sstevel@tonic-gate if (sigaction(SIGTERM, &sigact, (struct sigaction *)NULL) < 0) {
2200Sstevel@tonic-gate perror("Warning: sigaction");
2210Sstevel@tonic-gate exit(1);
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate /* Prepare for failure during program initialization/exit */
2250Sstevel@tonic-gate if (sigsetjmp(jmp_env, 1)) {
2260Sstevel@tonic-gate exit(1);
2270Sstevel@tonic-gate }
2281676Sjpk (void) setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
2290Sstevel@tonic-gate
2308023SPhil.Kirk@Sun.COM while ((c = getopt(argc, argv, "at:CPDSi:o:Nn:s:d:I:vVp:f:c:x:U?rqz"))
2318023SPhil.Kirk@Sun.COM != EOF) {
2320Sstevel@tonic-gate switch (c) {
2330Sstevel@tonic-gate case 'a':
2340Sstevel@tonic-gate audiodev = getenv("AUDIODEV");
2350Sstevel@tonic-gate if (audiodev == NULL)
2360Sstevel@tonic-gate audiodev = "/dev/audio";
2370Sstevel@tonic-gate audio = open(audiodev, O_WRONLY);
2380Sstevel@tonic-gate if (audio < 0) {
2390Sstevel@tonic-gate pr_err("Audio device %s: %m",
2408023SPhil.Kirk@Sun.COM audiodev);
2410Sstevel@tonic-gate exit(1);
2420Sstevel@tonic-gate }
2430Sstevel@tonic-gate break;
2440Sstevel@tonic-gate case 't':
2450Sstevel@tonic-gate flags |= F_TIME;
2460Sstevel@tonic-gate switch (*optarg) {
2470Sstevel@tonic-gate case 'r': flags |= F_RTIME; break;
2480Sstevel@tonic-gate case 'a': flags |= F_ATIME; break;
2490Sstevel@tonic-gate case 'd': break;
2500Sstevel@tonic-gate default: usage();
2510Sstevel@tonic-gate }
2520Sstevel@tonic-gate break;
2538023SPhil.Kirk@Sun.COM case 'I':
254*8868SPeter.Memishian@Sun.COM if (datalink != NULL)
2558023SPhil.Kirk@Sun.COM usage();
2568023SPhil.Kirk@Sun.COM Iflg = B_TRUE;
257*8868SPeter.Memishian@Sun.COM datalink = optarg;
2588023SPhil.Kirk@Sun.COM break;
2590Sstevel@tonic-gate case 'P':
2608023SPhil.Kirk@Sun.COM Pflg = B_TRUE;
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':
2758023SPhil.Kirk@Sun.COM Nflg = B_TRUE;
2760Sstevel@tonic-gate break;
2770Sstevel@tonic-gate case 'n':
2788023SPhil.Kirk@Sun.COM nflg = B_TRUE;
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':
2858023SPhil.Kirk@Sun.COM if (Iflg)
2868023SPhil.Kirk@Sun.COM usage();
287*8868SPeter.Memishian@Sun.COM datalink = optarg;
2880Sstevel@tonic-gate break;
2890Sstevel@tonic-gate case 'v':
2900Sstevel@tonic-gate flags &= ~(F_SUM);
2910Sstevel@tonic-gate flags |= F_DTAIL;
2920Sstevel@tonic-gate break;
2930Sstevel@tonic-gate case 'V':
2940Sstevel@tonic-gate flags |= F_ALLSUM;
2950Sstevel@tonic-gate break;
2960Sstevel@tonic-gate case 'p':
2970Sstevel@tonic-gate p = optarg;
2980Sstevel@tonic-gate p2 = strpbrk(p, ",:-");
2990Sstevel@tonic-gate if (p2 == NULL) {
3000Sstevel@tonic-gate first = last = atoi(p);
3010Sstevel@tonic-gate } else {
3020Sstevel@tonic-gate *p2++ = '\0';
3030Sstevel@tonic-gate first = atoi(p);
3040Sstevel@tonic-gate last = atoi(p2);
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate break;
3070Sstevel@tonic-gate case 'f':
3080Sstevel@tonic-gate (void) gethostname(self, MAXHOSTNAMELEN);
3090Sstevel@tonic-gate p = strchr(optarg, ':');
3100Sstevel@tonic-gate if (p) {
3110Sstevel@tonic-gate *p = '\0';
3120Sstevel@tonic-gate if (strcmp(optarg, self) == 0 ||
3130Sstevel@tonic-gate strcmp(p+1, self) == 0)
3140Sstevel@tonic-gate (void) fprintf(stderr,
3150Sstevel@tonic-gate "Warning: cannot capture packets from %s\n",
3168023SPhil.Kirk@Sun.COM self);
3170Sstevel@tonic-gate *p = ' ';
3180Sstevel@tonic-gate } else if (strcmp(optarg, self) == 0)
3190Sstevel@tonic-gate (void) fprintf(stderr,
3200Sstevel@tonic-gate "Warning: cannot capture packets from %s\n",
3218023SPhil.Kirk@Sun.COM self);
3220Sstevel@tonic-gate argstr = optarg;
3230Sstevel@tonic-gate break;
3240Sstevel@tonic-gate case 'x':
3250Sstevel@tonic-gate p = optarg;
3260Sstevel@tonic-gate p2 = strpbrk(p, ",:-");
3270Sstevel@tonic-gate if (p2 == NULL) {
3280Sstevel@tonic-gate x_offset = atoi(p);
3290Sstevel@tonic-gate x_length = -1;
3300Sstevel@tonic-gate } else {
3310Sstevel@tonic-gate *p2++ = '\0';
3320Sstevel@tonic-gate x_offset = atoi(p);
3330Sstevel@tonic-gate x_length = atoi(p2);
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate break;
3360Sstevel@tonic-gate case 'c':
3370Sstevel@tonic-gate maxcount = atoi(optarg);
3380Sstevel@tonic-gate break;
3390Sstevel@tonic-gate case 'C':
3408023SPhil.Kirk@Sun.COM Cflg = B_TRUE;
3410Sstevel@tonic-gate break;
3420Sstevel@tonic-gate case 'q':
3430Sstevel@tonic-gate qflg = B_TRUE;
3440Sstevel@tonic-gate break;
3450Sstevel@tonic-gate case 'r':
3460Sstevel@tonic-gate rflg = B_TRUE;
3470Sstevel@tonic-gate break;
3488023SPhil.Kirk@Sun.COM case 'U':
3498023SPhil.Kirk@Sun.COM Uflg = B_TRUE;
3508023SPhil.Kirk@Sun.COM break;
3510Sstevel@tonic-gate #ifdef DEBUG
3520Sstevel@tonic-gate case 'z':
3530Sstevel@tonic-gate zflg = B_TRUE;
3540Sstevel@tonic-gate break;
3550Sstevel@tonic-gate #endif /* DEBUG */
3560Sstevel@tonic-gate case '?':
3570Sstevel@tonic-gate default:
3580Sstevel@tonic-gate usage();
3590Sstevel@tonic-gate }
3600Sstevel@tonic-gate }
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate if (argc > optind)
3630Sstevel@tonic-gate argstr = (char *)concat_args(&argv[optind], argc - optind);
3640Sstevel@tonic-gate
3650Sstevel@tonic-gate /*
3660Sstevel@tonic-gate * Need to know before we decide on filtering method some things
3670Sstevel@tonic-gate * about the interface. So, go ahead and do part of the initialization
368*8868SPeter.Memishian@Sun.COM * now so we have that data. Note that if no datalink is specified,
369*8868SPeter.Memishian@Sun.COM * open_datalink() selects one and returns it. In an ideal world,
3700Sstevel@tonic-gate * it might be nice if the "correct" interface for the filter
3710Sstevel@tonic-gate * requested was chosen, but that's too hard.
3720Sstevel@tonic-gate */
3730Sstevel@tonic-gate if (!icapfile) {
374*8868SPeter.Memishian@Sun.COM use_kern_pf = open_datalink(&dh, datalink);
3750Sstevel@tonic-gate } else {
3768023SPhil.Kirk@Sun.COM use_kern_pf = B_FALSE;
3770Sstevel@tonic-gate cap_open_read(icapfile);
3780Sstevel@tonic-gate
3790Sstevel@tonic-gate if (!nflg) {
3800Sstevel@tonic-gate names[0] = '\0';
3810Sstevel@tonic-gate (void) strlcpy(names, icapfile, MAXPATHLEN);
3820Sstevel@tonic-gate (void) strlcat(names, ".names", MAXPATHLEN);
3830Sstevel@tonic-gate }
3840Sstevel@tonic-gate }
3850Sstevel@tonic-gate
3868023SPhil.Kirk@Sun.COM if (Uflg)
3878023SPhil.Kirk@Sun.COM use_kern_pf = B_FALSE;
3888023SPhil.Kirk@Sun.COM
3890Sstevel@tonic-gate /* attempt to read .names file if it exists before filtering */
3900Sstevel@tonic-gate if ((!Nflg) && names[0] != '\0') {
3910Sstevel@tonic-gate if (access(names, F_OK) == 0) {
3920Sstevel@tonic-gate load_names(names);
3930Sstevel@tonic-gate } else if (nflg) {
3940Sstevel@tonic-gate (void) fprintf(stderr, "%s not found\n", names);
3950Sstevel@tonic-gate exit(1);
3960Sstevel@tonic-gate }
3970Sstevel@tonic-gate }
3980Sstevel@tonic-gate
3990Sstevel@tonic-gate if (argstr) {
4008023SPhil.Kirk@Sun.COM if (use_kern_pf) {
4010Sstevel@tonic-gate ret = pf_compile(argstr, Cflg);
4020Sstevel@tonic-gate switch (ret) {
4030Sstevel@tonic-gate case 0:
4040Sstevel@tonic-gate filter++;
4050Sstevel@tonic-gate compile(argstr, Cflg);
4060Sstevel@tonic-gate break;
4070Sstevel@tonic-gate case 1:
4080Sstevel@tonic-gate fp = &pf;
4090Sstevel@tonic-gate break;
4100Sstevel@tonic-gate case 2:
4110Sstevel@tonic-gate fp = &pf;
4120Sstevel@tonic-gate filter++;
4130Sstevel@tonic-gate break;
4140Sstevel@tonic-gate }
4150Sstevel@tonic-gate } else {
4160Sstevel@tonic-gate filter++;
4170Sstevel@tonic-gate compile(argstr, Cflg);
4180Sstevel@tonic-gate }
4190Sstevel@tonic-gate
4200Sstevel@tonic-gate if (Cflg)
4210Sstevel@tonic-gate exit(0);
4220Sstevel@tonic-gate }
4230Sstevel@tonic-gate
4240Sstevel@tonic-gate if (flags & F_SUM)
4250Sstevel@tonic-gate flags |= F_WHO;
4260Sstevel@tonic-gate
4270Sstevel@tonic-gate /*
4280Sstevel@tonic-gate * If the -o flag is set then capture packets
4290Sstevel@tonic-gate * directly to a file. Don't attempt to
4300Sstevel@tonic-gate * interpret them on the fly (F_NOW).
4310Sstevel@tonic-gate * Note: capture to file is much less likely
4320Sstevel@tonic-gate * to drop packets since we don't spend cpu
4330Sstevel@tonic-gate * cycles running through the interpreters
4340Sstevel@tonic-gate * and possibly hanging in address-to-name
4350Sstevel@tonic-gate * mappings through the name service.
4360Sstevel@tonic-gate */
4370Sstevel@tonic-gate if (ocapfile) {
4380Sstevel@tonic-gate cap_open_write(ocapfile);
4390Sstevel@tonic-gate proc = cap_write;
4400Sstevel@tonic-gate } else {
4410Sstevel@tonic-gate flags |= F_NOW;
4420Sstevel@tonic-gate proc = process_pkt;
4430Sstevel@tonic-gate }
4440Sstevel@tonic-gate
4450Sstevel@tonic-gate
4460Sstevel@tonic-gate /*
4470Sstevel@tonic-gate * If the -i flag is set then get packets from
4480Sstevel@tonic-gate * the log file which has been previously captured
4490Sstevel@tonic-gate * with the -o option.
4500Sstevel@tonic-gate */
4510Sstevel@tonic-gate if (icapfile) {
4520Sstevel@tonic-gate names[0] = '\0';
4530Sstevel@tonic-gate (void) strlcpy(names, icapfile, MAXPATHLEN);
4540Sstevel@tonic-gate (void) strlcat(names, ".names", MAXPATHLEN);
4550Sstevel@tonic-gate
4560Sstevel@tonic-gate if (Nflg) {
4570Sstevel@tonic-gate namefile = fopen(names, "w");
4580Sstevel@tonic-gate if (namefile == NULL) {
4590Sstevel@tonic-gate perror(names);
4600Sstevel@tonic-gate exit(1);
4610Sstevel@tonic-gate }
4620Sstevel@tonic-gate flags = 0;
4630Sstevel@tonic-gate (void) fprintf(stderr,
4648023SPhil.Kirk@Sun.COM "Creating name file %s\n", names);
4650Sstevel@tonic-gate }
4660Sstevel@tonic-gate
4670Sstevel@tonic-gate if (flags & F_DTAIL)
4680Sstevel@tonic-gate flags = F_DTAIL;
4690Sstevel@tonic-gate else
4700Sstevel@tonic-gate flags |= F_NUM | F_TIME;
4710Sstevel@tonic-gate
4720Sstevel@tonic-gate resetperm();
4730Sstevel@tonic-gate cap_read(first, last, filter, proc, flags);
4740Sstevel@tonic-gate
4750Sstevel@tonic-gate if (Nflg)
4760Sstevel@tonic-gate (void) fclose(namefile);
4770Sstevel@tonic-gate
4780Sstevel@tonic-gate } else {
4790Sstevel@tonic-gate const int chunksize = 8 * 8192;
4800Sstevel@tonic-gate struct timeval timeout;
4810Sstevel@tonic-gate
4820Sstevel@tonic-gate /*
4830Sstevel@tonic-gate * If listening to packets on audio
4840Sstevel@tonic-gate * then set the buffer timeout down
4850Sstevel@tonic-gate * to 1/10 sec. A higher value
4860Sstevel@tonic-gate * makes the audio "bursty".
4870Sstevel@tonic-gate */
4880Sstevel@tonic-gate if (audio) {
4890Sstevel@tonic-gate timeout.tv_sec = 0;
4900Sstevel@tonic-gate timeout.tv_usec = 100000;
4910Sstevel@tonic-gate } else {
4920Sstevel@tonic-gate timeout.tv_sec = 1;
4930Sstevel@tonic-gate timeout.tv_usec = 0;
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate
496*8868SPeter.Memishian@Sun.COM init_datalink(dh, snaplen, chunksize, &timeout, fp);
4970Sstevel@tonic-gate if (! qflg && ocapfile)
4980Sstevel@tonic-gate show_count();
4990Sstevel@tonic-gate resetperm();
5003628Sss150715 net_read(dh, chunksize, filter, proc, flags);
5013628Sss150715 dlpi_close(dh);
5020Sstevel@tonic-gate
5030Sstevel@tonic-gate if (!(flags & F_NOW))
5041676Sjpk (void) printf("\n");
5050Sstevel@tonic-gate }
5060Sstevel@tonic-gate
5070Sstevel@tonic-gate if (ocapfile)
5080Sstevel@tonic-gate cap_close();
5090Sstevel@tonic-gate
5100Sstevel@tonic-gate return (0);
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate
5131676Sjpk static int tone[] = {
5141293Smh138676 0x076113, 0x153333, 0x147317, 0x144311, 0x147315, 0x050353, 0x037103, 0x051106,
5151293Smh138676 0x157155, 0x142723, 0x133273, 0x134664, 0x051712, 0x024465, 0x026447, 0x072473,
5161293Smh138676 0x136715, 0x126257, 0x135256, 0x047344, 0x034476, 0x027464, 0x036062, 0x133334,
5171293Smh138676 0x127256, 0x130660, 0x136262, 0x040724, 0x016446, 0x025437, 0x137171, 0x127672,
5181293Smh138676 0x124655, 0x134654, 0x032741, 0x021447, 0x037450, 0x125675, 0x127650, 0x077277,
5191293Smh138676 0x046514, 0x036077, 0x035471, 0x147131, 0x136272, 0x162720, 0x166151, 0x037527,
5200Sstevel@tonic-gate };
5210Sstevel@tonic-gate
5220Sstevel@tonic-gate /*
5231293Smh138676 * Make a sound on /dev/audio according to the length of the packet. The
5241293Smh138676 * tone data was ripped from /usr/share/audio/samples/au/bark.au. The
5251293Smh138676 * amount of waveform used is a function of packet length e.g. a series
5261293Smh138676 * of small packets is heard as clicks, whereas a series of NFS packets in
5271293Smh138676 * an 8k read sounds like a "WHAAAARP".
5280Sstevel@tonic-gate */
5290Sstevel@tonic-gate void
click(len)5300Sstevel@tonic-gate click(len)
5310Sstevel@tonic-gate int len;
5320Sstevel@tonic-gate {
5330Sstevel@tonic-gate len /= 8;
5340Sstevel@tonic-gate len = len ? len : 4;
5350Sstevel@tonic-gate
5360Sstevel@tonic-gate if (audio) {
5371676Sjpk (void) write(audio, tone, len);
5380Sstevel@tonic-gate }
5390Sstevel@tonic-gate }
5400Sstevel@tonic-gate
5410Sstevel@tonic-gate /* Display a count of packets */
5420Sstevel@tonic-gate void
show_count()5430Sstevel@tonic-gate show_count()
5440Sstevel@tonic-gate {
5450Sstevel@tonic-gate static int prev = -1;
5460Sstevel@tonic-gate
5470Sstevel@tonic-gate if (count == prev)
5480Sstevel@tonic-gate return;
5490Sstevel@tonic-gate
5500Sstevel@tonic-gate prev = count;
5510Sstevel@tonic-gate (void) fprintf(stderr, "\r%d ", count);
5520Sstevel@tonic-gate }
5530Sstevel@tonic-gate
5540Sstevel@tonic-gate #define ENCAP_LEN 16 /* Hold "(NN encap)" */
5550Sstevel@tonic-gate
5560Sstevel@tonic-gate /*
5570Sstevel@tonic-gate * Display data that's external to the packet.
5580Sstevel@tonic-gate * This constitutes the first half of the summary
5590Sstevel@tonic-gate * line display.
5600Sstevel@tonic-gate */
5610Sstevel@tonic-gate void
show_pktinfo(flags,num,src,dst,ptvp,tvp,drops,len)5620Sstevel@tonic-gate show_pktinfo(flags, num, src, dst, ptvp, tvp, drops, len)
5630Sstevel@tonic-gate int flags, num, drops, len;
5640Sstevel@tonic-gate char *src, *dst;
5650Sstevel@tonic-gate struct timeval *ptvp, *tvp;
5660Sstevel@tonic-gate {
5670Sstevel@tonic-gate struct tm *tm;
5680Sstevel@tonic-gate static struct timeval tvp0;
5690Sstevel@tonic-gate int sec, usec;
5700Sstevel@tonic-gate char *lp = line;
5710Sstevel@tonic-gate int i, start;
5720Sstevel@tonic-gate
5730Sstevel@tonic-gate if (flags & F_NUM) {
5741676Sjpk (void) sprintf(lp, "%3d ", num);
5750Sstevel@tonic-gate lp += strlen(lp);
5760Sstevel@tonic-gate }
5770Sstevel@tonic-gate tm = localtime(&tvp->tv_sec);
5780Sstevel@tonic-gate
5790Sstevel@tonic-gate if (flags & F_TIME) {
5800Sstevel@tonic-gate if (flags & F_ATIME) {
5811676Sjpk (void) sprintf(lp, "%d:%02d:%d.%05d ",
5820Sstevel@tonic-gate tm->tm_hour, tm->tm_min, tm->tm_sec,
5831676Sjpk (int)tvp->tv_usec / 10);
5840Sstevel@tonic-gate lp += strlen(lp);
5850Sstevel@tonic-gate } else {
5860Sstevel@tonic-gate if (flags & F_RTIME) {
5870Sstevel@tonic-gate if (tvp0.tv_sec == 0) {
5880Sstevel@tonic-gate tvp0.tv_sec = tvp->tv_sec;
5890Sstevel@tonic-gate tvp0.tv_usec = tvp->tv_usec;
5900Sstevel@tonic-gate }
5910Sstevel@tonic-gate ptvp = &tvp0;
5920Sstevel@tonic-gate }
5930Sstevel@tonic-gate sec = tvp->tv_sec - ptvp->tv_sec;
5940Sstevel@tonic-gate usec = tvp->tv_usec - ptvp->tv_usec;
5950Sstevel@tonic-gate if (usec < 0) {
5960Sstevel@tonic-gate usec += 1000000;
5970Sstevel@tonic-gate sec -= 1;
5980Sstevel@tonic-gate }
5991676Sjpk (void) sprintf(lp, "%3d.%05d ", sec, usec / 10);
6000Sstevel@tonic-gate lp += strlen(lp);
6010Sstevel@tonic-gate }
6020Sstevel@tonic-gate }
6030Sstevel@tonic-gate
6042760Sdg199075 if ((flags & F_SUM) && !(flags & F_ALLSUM) && (vlanid != 0)) {
6052760Sdg199075 (void) snprintf(lp, MAXLINE, "VLAN#%i: ", vlanid);
6062760Sdg199075 lp += strlen(lp);
6072760Sdg199075 }
6082760Sdg199075
6090Sstevel@tonic-gate if (flags & F_WHO) {
6101676Sjpk (void) sprintf(lp, "%12s -> %-12s ", src, dst);
6110Sstevel@tonic-gate lp += strlen(lp);
6120Sstevel@tonic-gate }
6130Sstevel@tonic-gate
6140Sstevel@tonic-gate if (flags & F_DROPS) {
6151676Sjpk (void) sprintf(lp, "drops: %d ", drops);
6160Sstevel@tonic-gate lp += strlen(lp);
6170Sstevel@tonic-gate }
6180Sstevel@tonic-gate
6190Sstevel@tonic-gate if (flags & F_LEN) {
6201676Sjpk (void) sprintf(lp, "length: %4d ", len);
6210Sstevel@tonic-gate lp += strlen(lp);
6220Sstevel@tonic-gate }
6230Sstevel@tonic-gate
6240Sstevel@tonic-gate if (flags & F_SUM) {
6250Sstevel@tonic-gate if (flags & F_ALLSUM)
6261676Sjpk (void) printf("________________________________\n");
6270Sstevel@tonic-gate
6280Sstevel@tonic-gate start = flags & F_ALLSUM ? 0 : sumcount - 1;
6291676Sjpk (void) sprintf(encap, " (%d encap)", total_encap_levels - 1);
6301676Sjpk (void) printf("%s%s%s\n", line, sumline[start],
6310Sstevel@tonic-gate ((flags & F_ALLSUM) || (total_encap_levels == 1)) ? "" :
6320Sstevel@tonic-gate encap);
6330Sstevel@tonic-gate
6340Sstevel@tonic-gate for (i = start + 1; i < sumcount; i++)
6351676Sjpk (void) printf("%s%s\n", line, sumline[i]);
6360Sstevel@tonic-gate
6370Sstevel@tonic-gate sumcount = 0;
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate
6400Sstevel@tonic-gate if (flags & F_DTAIL) {
6411676Sjpk (void) printf("%s\n\n", detail_line);
6420Sstevel@tonic-gate detail_line[0] = '\0';
6430Sstevel@tonic-gate }
6440Sstevel@tonic-gate }
6450Sstevel@tonic-gate
6460Sstevel@tonic-gate /*
6472760Sdg199075 * The following three routines are called back
6480Sstevel@tonic-gate * from the interpreters to display their stuff.
6490Sstevel@tonic-gate * The theory is that when snoop becomes a window
6500Sstevel@tonic-gate * based tool we can just supply a new version of
6510Sstevel@tonic-gate * get_sum_line and get_detail_line and not have
6520Sstevel@tonic-gate * to touch the interpreters at all.
6530Sstevel@tonic-gate */
6540Sstevel@tonic-gate char *
get_sum_line()6550Sstevel@tonic-gate get_sum_line()
6560Sstevel@tonic-gate {
6570Sstevel@tonic-gate int tsumcount = sumcount;
6580Sstevel@tonic-gate
6590Sstevel@tonic-gate if (sumcount >= MAXSUM) {
6600Sstevel@tonic-gate sumcount = 0; /* error recovery */
6610Sstevel@tonic-gate pr_err(
6620Sstevel@tonic-gate "get_sum_line: sumline overflow (sumcount=%d, MAXSUM=%d)\n",
6638023SPhil.Kirk@Sun.COM tsumcount, MAXSUM);
6640Sstevel@tonic-gate }
6650Sstevel@tonic-gate
6660Sstevel@tonic-gate sumline[sumcount][0] = '\0';
6670Sstevel@tonic-gate return (sumline[sumcount++]);
6680Sstevel@tonic-gate }
6690Sstevel@tonic-gate
6700Sstevel@tonic-gate /*ARGSUSED*/
6710Sstevel@tonic-gate char *
get_detail_line(off,len)6720Sstevel@tonic-gate get_detail_line(off, len)
6730Sstevel@tonic-gate int off, len;
6740Sstevel@tonic-gate {
6750Sstevel@tonic-gate if (detail_line[0]) {
6761676Sjpk (void) printf("%s\n", detail_line);
6770Sstevel@tonic-gate detail_line[0] = '\0';
6780Sstevel@tonic-gate }
6790Sstevel@tonic-gate return (detail_line);
6800Sstevel@tonic-gate }
6810Sstevel@tonic-gate
6820Sstevel@tonic-gate /*
6832760Sdg199075 * This function exists to make sure that VLAN information is
6842760Sdg199075 * prepended to summary lines displayed. The problem this function
6852760Sdg199075 * solves is how to display VLAN information while in summary mode.
6862760Sdg199075 * Each interpretor uses the get_sum_line and get_detail_line functions
6872760Sdg199075 * to get a character buffer to display information to the user.
6882760Sdg199075 * get_sum_line is the important one here. Each call to get_sum_line
6892760Sdg199075 * gets a buffer which stores one line of information. In summary mode,
6902760Sdg199075 * the last line generated is the line printed. Instead of changing each
6912760Sdg199075 * interpreter to add VLAN information to the summary line, the ethernet
6922760Sdg199075 * interpreter changes to call this function and set an ID. If the ID is not
6932760Sdg199075 * zero and snoop is in default summary mode, snoop displays the
6942760Sdg199075 * VLAN information at the beginning of the output line. Otherwise,
6952760Sdg199075 * no VLAN information is displayed.
6962760Sdg199075 */
6972760Sdg199075 void
set_vlan_id(int id)6982760Sdg199075 set_vlan_id(int id)
6992760Sdg199075 {
7002760Sdg199075 vlanid = id;
7012760Sdg199075 }
7022760Sdg199075
7032760Sdg199075 /*
7040Sstevel@tonic-gate * Print an error.
7050Sstevel@tonic-gate * Works like printf (fmt string and variable args)
7061676Sjpk * except that it will substitute an error message
7070Sstevel@tonic-gate * for a "%m" string (like syslog) and it calls
7080Sstevel@tonic-gate * long_jump - it doesn't return to where it was
7090Sstevel@tonic-gate * called from - it goes to the last setjmp().
7100Sstevel@tonic-gate */
7111676Sjpk /* VARARGS1 */
7120Sstevel@tonic-gate void
pr_err(const char * fmt,...)7131676Sjpk pr_err(const char *fmt, ...)
7140Sstevel@tonic-gate {
7150Sstevel@tonic-gate va_list ap;
7161676Sjpk char buf[1024], *p2;
7171676Sjpk const char *p1;
7180Sstevel@tonic-gate
7191676Sjpk (void) strcpy(buf, "snoop: ");
7200Sstevel@tonic-gate p2 = buf + strlen(buf);
7210Sstevel@tonic-gate
7221676Sjpk /*
7231676Sjpk * Note that we terminate the buffer with '\n' and '\0'.
7241676Sjpk */
7251676Sjpk for (p1 = fmt; *p1 != '\0' && p2 < buf + sizeof (buf) - 2; p1++) {
7260Sstevel@tonic-gate if (*p1 == '%' && *(p1+1) == 'm') {
7271676Sjpk const char *errstr;
7280Sstevel@tonic-gate
7291676Sjpk if ((errstr = strerror(errno)) != NULL) {
7301676Sjpk *p2 = '\0';
7311676Sjpk (void) strlcat(buf, errstr, sizeof (buf));
7320Sstevel@tonic-gate p2 += strlen(p2);
7330Sstevel@tonic-gate }
7340Sstevel@tonic-gate p1++;
7350Sstevel@tonic-gate } else {
7360Sstevel@tonic-gate *p2++ = *p1;
7370Sstevel@tonic-gate }
7380Sstevel@tonic-gate }
7390Sstevel@tonic-gate if (p2 > buf && *(p2-1) != '\n')
7400Sstevel@tonic-gate *p2++ = '\n';
7410Sstevel@tonic-gate *p2 = '\0';
7420Sstevel@tonic-gate
7430Sstevel@tonic-gate va_start(ap, fmt);
7441676Sjpk /* LINTED: E_SEC_PRINTF_VAR_FMT */
7450Sstevel@tonic-gate (void) vfprintf(stderr, buf, ap);
7460Sstevel@tonic-gate va_end(ap);
7470Sstevel@tonic-gate snoop_sigrecover(-1, NULL, NULL); /* global error recovery */
7480Sstevel@tonic-gate }
7490Sstevel@tonic-gate
7500Sstevel@tonic-gate /*
7513628Sss150715 * Store a copy of linkname associated with the DLPI handle.
7523628Sss150715 * Save errno before closing the dlpi handle so that the
7533628Sss150715 * correct error value is used if 'err' is a system error.
7543628Sss150715 */
7553628Sss150715 void
pr_errdlpi(dlpi_handle_t dh,const char * cmd,int err)7563628Sss150715 pr_errdlpi(dlpi_handle_t dh, const char *cmd, int err)
7573628Sss150715 {
7583628Sss150715 int save_errno = errno;
7593628Sss150715 char linkname[DLPI_LINKNAME_MAX];
7603628Sss150715
7613628Sss150715 (void) strlcpy(linkname, dlpi_linkname(dh), sizeof (linkname));
7623628Sss150715
7633628Sss150715 dlpi_close(dh);
7643628Sss150715 errno = save_errno;
7653628Sss150715
7663628Sss150715 pr_err("%s on \"%s\": %s", cmd, linkname, dlpi_strerror(err));
7673628Sss150715 }
7683628Sss150715
7693628Sss150715 /*
7700Sstevel@tonic-gate * Ye olde usage proc
7710Sstevel@tonic-gate * PLEASE keep this up to date!
7720Sstevel@tonic-gate * Naive users *love* this stuff.
7730Sstevel@tonic-gate */
7741676Sjpk static void
usage(void)7751676Sjpk usage(void)
7760Sstevel@tonic-gate {
7770Sstevel@tonic-gate (void) fprintf(stderr, "\nUsage: snoop\n");
7780Sstevel@tonic-gate (void) fprintf(stderr,
7790Sstevel@tonic-gate "\t[ -a ] # Listen to packets on audio\n");
7800Sstevel@tonic-gate (void) fprintf(stderr,
7818023SPhil.Kirk@Sun.COM "\t[ -d link ] # Listen on named link\n");
7820Sstevel@tonic-gate (void) fprintf(stderr,
7830Sstevel@tonic-gate "\t[ -s snaplen ] # Truncate packets\n");
7840Sstevel@tonic-gate (void) fprintf(stderr,
7858023SPhil.Kirk@Sun.COM "\t[ -I IP interface ] # Listen on named IP interface\n");
7868023SPhil.Kirk@Sun.COM (void) fprintf(stderr,
7870Sstevel@tonic-gate "\t[ -c count ] # Quit after count packets\n");
7880Sstevel@tonic-gate (void) fprintf(stderr,
7890Sstevel@tonic-gate "\t[ -P ] # Turn OFF promiscuous mode\n");
7900Sstevel@tonic-gate (void) fprintf(stderr,
7910Sstevel@tonic-gate "\t[ -D ] # Report dropped packets\n");
7920Sstevel@tonic-gate (void) fprintf(stderr,
7930Sstevel@tonic-gate "\t[ -S ] # Report packet size\n");
7940Sstevel@tonic-gate (void) fprintf(stderr,
7950Sstevel@tonic-gate "\t[ -i file ] # Read previously captured packets\n");
7960Sstevel@tonic-gate (void) fprintf(stderr,
7970Sstevel@tonic-gate "\t[ -o file ] # Capture packets in file\n");
7980Sstevel@tonic-gate (void) fprintf(stderr,
7990Sstevel@tonic-gate "\t[ -n file ] # Load addr-to-name table from file\n");
8000Sstevel@tonic-gate (void) fprintf(stderr,
8010Sstevel@tonic-gate "\t[ -N ] # Create addr-to-name table\n");
8020Sstevel@tonic-gate (void) fprintf(stderr,
8030Sstevel@tonic-gate "\t[ -t r|a|d ] # Time: Relative, Absolute or Delta\n");
8040Sstevel@tonic-gate (void) fprintf(stderr,
8050Sstevel@tonic-gate "\t[ -v ] # Verbose packet display\n");
8060Sstevel@tonic-gate (void) fprintf(stderr,
8070Sstevel@tonic-gate "\t[ -V ] # Show all summary lines\n");
8080Sstevel@tonic-gate (void) fprintf(stderr,
8090Sstevel@tonic-gate "\t[ -p first[,last] ] # Select packet(s) to display\n");
8100Sstevel@tonic-gate (void) fprintf(stderr,
8110Sstevel@tonic-gate "\t[ -x offset[,length] ] # Hex dump from offset for length\n");
8120Sstevel@tonic-gate (void) fprintf(stderr,
8130Sstevel@tonic-gate "\t[ -C ] # Print packet filter code\n");
8140Sstevel@tonic-gate (void) fprintf(stderr,
8150Sstevel@tonic-gate "\t[ -q ] # Suppress printing packet count\n");
8160Sstevel@tonic-gate (void) fprintf(stderr,
8170Sstevel@tonic-gate "\t[ -r ] # Do not resolve address to name\n");
8180Sstevel@tonic-gate (void) fprintf(stderr,
8190Sstevel@tonic-gate "\n\t[ filter expression ]\n");
8200Sstevel@tonic-gate (void) fprintf(stderr, "\nExample:\n");
8210Sstevel@tonic-gate (void) fprintf(stderr, "\tsnoop -o saved host fred\n\n");
8220Sstevel@tonic-gate (void) fprintf(stderr, "\tsnoop -i saved -tr -v -p19\n");
8230Sstevel@tonic-gate exit(1);
8240Sstevel@tonic-gate }
8250Sstevel@tonic-gate
8260Sstevel@tonic-gate /*
8270Sstevel@tonic-gate * sdefault: default global alarm handler. Causes the current packet
8280Sstevel@tonic-gate * to be skipped.
8290Sstevel@tonic-gate */
8300Sstevel@tonic-gate static void
sdefault(void)8310Sstevel@tonic-gate sdefault(void)
8320Sstevel@tonic-gate {
8330Sstevel@tonic-gate snoop_nrecover = SNOOP_MAXRECOVER;
8340Sstevel@tonic-gate }
8350Sstevel@tonic-gate
8360Sstevel@tonic-gate /*
8370Sstevel@tonic-gate * snoop_alarm: register or unregister an alarm handler to be called after
8380Sstevel@tonic-gate * s_sec seconds. Because snoop wasn't written to tolerate random signal
8390Sstevel@tonic-gate * delivery, periodic SIGALRM delivery (or SA_RESTART) cannot be used.
8400Sstevel@tonic-gate *
8410Sstevel@tonic-gate * s_sec argument of 0 seconds unregisters the handler.
8420Sstevel@tonic-gate * s_handler argument of NULL registers default handler sdefault(), or
8430Sstevel@tonic-gate * unregisters all signal handlers (for error recovery).
8440Sstevel@tonic-gate *
8450Sstevel@tonic-gate * Variables must be volatile to force the compiler to not optimize
8460Sstevel@tonic-gate * out the signal blocking.
8470Sstevel@tonic-gate */
8480Sstevel@tonic-gate /*ARGSUSED*/
8490Sstevel@tonic-gate int
snoop_alarm(int s_sec,void (* s_handler)())8500Sstevel@tonic-gate snoop_alarm(int s_sec, void (*s_handler)())
8510Sstevel@tonic-gate {
8520Sstevel@tonic-gate volatile time_t now;
8530Sstevel@tonic-gate volatile time_t nalarm = 0;
8540Sstevel@tonic-gate volatile struct snoop_handler *sh = NULL;
8550Sstevel@tonic-gate volatile struct snoop_handler *hp, *tp, *next;
8560Sstevel@tonic-gate volatile sigset_t s_mask;
8570Sstevel@tonic-gate volatile int ret = -1;
8580Sstevel@tonic-gate
8591676Sjpk (void) sigemptyset((sigset_t *)&s_mask);
8601676Sjpk (void) sigaddset((sigset_t *)&s_mask, SIGALRM);
8610Sstevel@tonic-gate if (s_sec < 0)
8620Sstevel@tonic-gate return (-1);
8630Sstevel@tonic-gate
8640Sstevel@tonic-gate /* register an alarm handler */
8650Sstevel@tonic-gate now = time(NULL);
8660Sstevel@tonic-gate if (s_sec) {
8670Sstevel@tonic-gate sh = malloc(sizeof (struct snoop_handler));
8680Sstevel@tonic-gate sh->s_time = now + s_sec;
8690Sstevel@tonic-gate if (s_handler == NULL)
8700Sstevel@tonic-gate s_handler = sdefault;
8710Sstevel@tonic-gate sh->s_handler = s_handler;
8720Sstevel@tonic-gate sh->s_next = NULL;
8730Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, (sigset_t *)&s_mask, NULL);
8740Sstevel@tonic-gate if (snoop_hp == NULL) {
8750Sstevel@tonic-gate snoop_hp = snoop_tp = (struct snoop_handler *)sh;
8760Sstevel@tonic-gate
8770Sstevel@tonic-gate snoop_nalarm = sh->s_time;
8781676Sjpk (void) alarm(sh->s_time - now);
8790Sstevel@tonic-gate } else {
8800Sstevel@tonic-gate snoop_tp->s_next = (struct snoop_handler *)sh;
8810Sstevel@tonic-gate snoop_tp = (struct snoop_handler *)sh;
8820Sstevel@tonic-gate
8830Sstevel@tonic-gate if (sh->s_time < snoop_nalarm) {
8840Sstevel@tonic-gate snoop_nalarm = sh->s_time;
8850Sstevel@tonic-gate (void) alarm(sh->s_time - now);
8860Sstevel@tonic-gate }
8870Sstevel@tonic-gate }
8880Sstevel@tonic-gate (void) sigprocmask(SIG_UNBLOCK, (sigset_t *)&s_mask, NULL);
8890Sstevel@tonic-gate
8900Sstevel@tonic-gate return (0);
8910Sstevel@tonic-gate }
8920Sstevel@tonic-gate
8930Sstevel@tonic-gate /* unregister an alarm handler */
8940Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, (sigset_t *)&s_mask, NULL);
8950Sstevel@tonic-gate tp = (struct snoop_handler *)&snoop_hp;
8960Sstevel@tonic-gate for (hp = snoop_hp; hp; hp = next) {
8970Sstevel@tonic-gate next = hp->s_next;
8980Sstevel@tonic-gate if (s_handler == NULL || hp->s_handler == s_handler) {
8990Sstevel@tonic-gate ret = 0;
9000Sstevel@tonic-gate tp->s_next = hp->s_next;
9010Sstevel@tonic-gate if (snoop_tp == hp) {
9020Sstevel@tonic-gate if (tp == (struct snoop_handler *)&snoop_hp)
9030Sstevel@tonic-gate snoop_tp = NULL;
9040Sstevel@tonic-gate else
9050Sstevel@tonic-gate snoop_tp = (struct snoop_handler *)tp;
9060Sstevel@tonic-gate }
9070Sstevel@tonic-gate free((void *)hp);
9080Sstevel@tonic-gate } else {
9090Sstevel@tonic-gate if (nalarm == 0 || nalarm > hp->s_time)
9100Sstevel@tonic-gate nalarm = now < hp->s_time ? hp->s_time :
9118023SPhil.Kirk@Sun.COM now + 1;
9120Sstevel@tonic-gate tp = hp;
9130Sstevel@tonic-gate }
9140Sstevel@tonic-gate }
9150Sstevel@tonic-gate /*
9160Sstevel@tonic-gate * Stop or adjust timer
9170Sstevel@tonic-gate */
9180Sstevel@tonic-gate if (snoop_hp == NULL) {
9190Sstevel@tonic-gate snoop_nalarm = 0;
9200Sstevel@tonic-gate (void) alarm(0);
9210Sstevel@tonic-gate } else if (nalarm > 0 && nalarm < snoop_nalarm) {
9220Sstevel@tonic-gate snoop_nalarm = nalarm;
9230Sstevel@tonic-gate (void) alarm(nalarm - now);
9240Sstevel@tonic-gate }
9250Sstevel@tonic-gate
9260Sstevel@tonic-gate (void) sigprocmask(SIG_UNBLOCK, (sigset_t *)&s_mask, NULL);
9270Sstevel@tonic-gate return (ret);
9280Sstevel@tonic-gate }
9290Sstevel@tonic-gate
9300Sstevel@tonic-gate /*
9310Sstevel@tonic-gate * snoop_recover: reset snoop's output area, and any internal variables,
9320Sstevel@tonic-gate * to allow continuation.
9330Sstevel@tonic-gate * XXX: make this an interface such that each interpreter can
9340Sstevel@tonic-gate * register a reset routine.
9350Sstevel@tonic-gate */
9360Sstevel@tonic-gate void
snoop_recover(void)9370Sstevel@tonic-gate snoop_recover(void)
9380Sstevel@tonic-gate {
9390Sstevel@tonic-gate int i;
9400Sstevel@tonic-gate
9410Sstevel@tonic-gate /* Error recovery: reset output_area and associated variables */
9420Sstevel@tonic-gate for (i = 0; i < MAXSUM; i++)
9430Sstevel@tonic-gate sumline[i][0] = '\0';
9440Sstevel@tonic-gate detail_line[0] = '\0';
9450Sstevel@tonic-gate line[0] = '\0';
9460Sstevel@tonic-gate encap[0] = '\0';
9470Sstevel@tonic-gate sumcount = 0;
9480Sstevel@tonic-gate
9490Sstevel@tonic-gate /* stacking/unstacking cannot be relied upon */
9500Sstevel@tonic-gate encap_levels = 0;
9510Sstevel@tonic-gate total_encap_levels = 1;
9520Sstevel@tonic-gate
9530Sstevel@tonic-gate /* remove any pending timeouts */
9540Sstevel@tonic-gate (void) snoop_alarm(0, NULL);
9550Sstevel@tonic-gate }
9560Sstevel@tonic-gate
9570Sstevel@tonic-gate /*
9580Sstevel@tonic-gate * snoop_sigrecover: global sigaction routine to manage recovery
9590Sstevel@tonic-gate * from catastrophic interpreter failures while interpreting
9600Sstevel@tonic-gate * corrupt trace files/packets. SIGALRM timeouts, program errors,
9610Sstevel@tonic-gate * and user termination are all handled. In the case of a corrupt
9620Sstevel@tonic-gate * packet or confused interpreter, the packet will be skipped, and
9630Sstevel@tonic-gate * execution will continue in scan().
9640Sstevel@tonic-gate *
9650Sstevel@tonic-gate * Global alarm handling (see snoop_alarm()) is managed here.
9660Sstevel@tonic-gate *
9670Sstevel@tonic-gate * Variables must be volatile to force the compiler to not optimize
9680Sstevel@tonic-gate * out the signal blocking.
9690Sstevel@tonic-gate */
9700Sstevel@tonic-gate /*ARGSUSED*/
9711676Sjpk static void
snoop_sigrecover(int sig,siginfo_t * info,void * p)9720Sstevel@tonic-gate snoop_sigrecover(int sig, siginfo_t *info, void *p)
9730Sstevel@tonic-gate {
9740Sstevel@tonic-gate volatile time_t now;
9750Sstevel@tonic-gate volatile time_t nalarm = 0;
9760Sstevel@tonic-gate volatile struct snoop_handler *hp;
9770Sstevel@tonic-gate
9780Sstevel@tonic-gate /*
9790Sstevel@tonic-gate * Invoke any registered alarms. This involves first calculating
9800Sstevel@tonic-gate * the time for the next alarm, setting it up, then progressing
9810Sstevel@tonic-gate * through handler invocations. Note that since handlers may
9820Sstevel@tonic-gate * use siglongjmp(), in the worst case handlers may be serviced
9830Sstevel@tonic-gate * at a later time.
9840Sstevel@tonic-gate */
9850Sstevel@tonic-gate if (sig == SIGALRM) {
9860Sstevel@tonic-gate now = time(NULL);
9870Sstevel@tonic-gate /* Calculate next alarm time */
9880Sstevel@tonic-gate for (hp = snoop_hp; hp; hp = hp->s_next) {
9890Sstevel@tonic-gate if (hp->s_time) {
9900Sstevel@tonic-gate if ((hp->s_time - now) > 0) {
9910Sstevel@tonic-gate if (nalarm == 0 || nalarm > hp->s_time)
9920Sstevel@tonic-gate nalarm = now < hp->s_time ?
9938023SPhil.Kirk@Sun.COM hp->s_time : now + 1;
9940Sstevel@tonic-gate }
9950Sstevel@tonic-gate }
9960Sstevel@tonic-gate }
9970Sstevel@tonic-gate /* Setup next alarm */
9980Sstevel@tonic-gate if (nalarm) {
9990Sstevel@tonic-gate snoop_nalarm = nalarm;
10001676Sjpk (void) alarm(nalarm - now);
10010Sstevel@tonic-gate } else {
10020Sstevel@tonic-gate snoop_nalarm = 0;
10030Sstevel@tonic-gate }
10040Sstevel@tonic-gate
10050Sstevel@tonic-gate /* Invoke alarm handlers (may not return) */
10060Sstevel@tonic-gate for (hp = snoop_hp; hp; hp = hp->s_next) {
10070Sstevel@tonic-gate if (hp->s_time) {
10080Sstevel@tonic-gate if ((now - hp->s_time) >= 0) {
10090Sstevel@tonic-gate hp->s_time = 0; /* only invoke once */
10100Sstevel@tonic-gate if (hp->s_handler)
10110Sstevel@tonic-gate hp->s_handler();
10120Sstevel@tonic-gate }
10130Sstevel@tonic-gate }
10140Sstevel@tonic-gate }
10150Sstevel@tonic-gate } else {
10160Sstevel@tonic-gate snoop_nrecover++;
10170Sstevel@tonic-gate }
10180Sstevel@tonic-gate
10190Sstevel@tonic-gate /*
10200Sstevel@tonic-gate * Exit if a signal has occurred after snoop has begun the process
10210Sstevel@tonic-gate * of quitting.
10220Sstevel@tonic-gate */
10230Sstevel@tonic-gate if (quitting)
10240Sstevel@tonic-gate exit(1);
10250Sstevel@tonic-gate
10260Sstevel@tonic-gate /*
10270Sstevel@tonic-gate * If an alarm handler has timed out, and snoop_nrecover has
10280Sstevel@tonic-gate * reached SNOOP_MAXRECOVER, skip to the next packet.
10290Sstevel@tonic-gate *
10300Sstevel@tonic-gate * If any other signal has occurred, and snoop_nrecover has
10310Sstevel@tonic-gate * reached SNOOP_MAXRECOVER, give up.
10320Sstevel@tonic-gate */
10330Sstevel@tonic-gate if (sig == SIGALRM) {
10340Sstevel@tonic-gate if (ioctl(STDOUT_FILENO, I_CANPUT, 0) == 0) {
10350Sstevel@tonic-gate /*
10360Sstevel@tonic-gate * We've stalled on output, which is not a critical
10370Sstevel@tonic-gate * failure. Reset the recovery counter so we do not
10380Sstevel@tonic-gate * consider this a persistent failure, and return so
10390Sstevel@tonic-gate * we do not skip this packet.
10400Sstevel@tonic-gate */
10410Sstevel@tonic-gate snoop_nrecover = 0;
10420Sstevel@tonic-gate return;
10430Sstevel@tonic-gate }
10440Sstevel@tonic-gate if (snoop_nrecover >= SNOOP_MAXRECOVER) {
10451676Sjpk (void) fprintf(stderr,
10468023SPhil.Kirk@Sun.COM "snoop: WARNING: skipping from packet %d\n",
10478023SPhil.Kirk@Sun.COM count);
10480Sstevel@tonic-gate snoop_nrecover = 0;
10490Sstevel@tonic-gate } else {
10500Sstevel@tonic-gate /* continue trying */
10510Sstevel@tonic-gate return;
10520Sstevel@tonic-gate }
10530Sstevel@tonic-gate } else if (snoop_nrecover >= SNOOP_MAXRECOVER) {
10541676Sjpk (void) fprintf(stderr,
10558023SPhil.Kirk@Sun.COM "snoop: ERROR: cannot recover from packet %d\n", count);
10560Sstevel@tonic-gate exit(1);
10570Sstevel@tonic-gate }
10580Sstevel@tonic-gate
10590Sstevel@tonic-gate #ifdef DEBUG
10601676Sjpk (void) fprintf(stderr, "snoop_sigrecover(%d, %p, %p)\n", sig, info, p);
10610Sstevel@tonic-gate #endif /* DEBUG */
10620Sstevel@tonic-gate
10630Sstevel@tonic-gate /*
10640Sstevel@tonic-gate * Prepare to quit. This allows final processing to occur
10650Sstevel@tonic-gate * after first terminal interruption.
10660Sstevel@tonic-gate */
10670Sstevel@tonic-gate if (sig == SIGTERM || sig == SIGHUP || sig == SIGINT) {
10680Sstevel@tonic-gate quitting = 1;
10690Sstevel@tonic-gate return;
10700Sstevel@tonic-gate } else if (sig != -1 && sig != SIGALRM) {
10710Sstevel@tonic-gate /* Inform user that snoop has taken a fault */
10721676Sjpk (void) fprintf(stderr,
10731676Sjpk "WARNING: received signal %d from packet %d\n",
10748023SPhil.Kirk@Sun.COM sig, count);
10750Sstevel@tonic-gate }
10760Sstevel@tonic-gate
10770Sstevel@tonic-gate /* Reset interpreter variables */
10780Sstevel@tonic-gate snoop_recover();
10790Sstevel@tonic-gate
10800Sstevel@tonic-gate /* Continue in scan() with the next packet */
10810Sstevel@tonic-gate siglongjmp(jmp_env, 1);
10820Sstevel@tonic-gate /*NOTREACHED*/
10830Sstevel@tonic-gate }
10840Sstevel@tonic-gate
10850Sstevel@tonic-gate /*
10860Sstevel@tonic-gate * Protected malloc for global error recovery: prepare for interpreter
10870Sstevel@tonic-gate * failures with corrupted packets or confused interpreters. Dynamically
10880Sstevel@tonic-gate * allocate `nbytes' bytes, and sandwich it between two PROT_NONE pages to
10890Sstevel@tonic-gate * catch writes outside of the allocated region.
10900Sstevel@tonic-gate */
10910Sstevel@tonic-gate static char *
protmalloc(size_t nbytes)10920Sstevel@tonic-gate protmalloc(size_t nbytes)
10930Sstevel@tonic-gate {
10940Sstevel@tonic-gate caddr_t start;
10950Sstevel@tonic-gate int psz = sysconf(_SC_PAGESIZE);
10960Sstevel@tonic-gate
10970Sstevel@tonic-gate nbytes = P2ROUNDUP(nbytes, psz);
10980Sstevel@tonic-gate start = mmap(NULL, nbytes + psz * 2, PROT_READ|PROT_WRITE,
10990Sstevel@tonic-gate MAP_PRIVATE|MAP_ANON, -1, 0);
11000Sstevel@tonic-gate if (start == MAP_FAILED) {
11010Sstevel@tonic-gate perror("Error: protmalloc: mmap");
11020Sstevel@tonic-gate return (NULL);
11030Sstevel@tonic-gate }
11040Sstevel@tonic-gate assert(IS_P2ALIGNED(start, psz));
11050Sstevel@tonic-gate if (mprotect(start, 1, PROT_NONE) == -1)
11060Sstevel@tonic-gate perror("Warning: mprotect");
11070Sstevel@tonic-gate
11080Sstevel@tonic-gate start += psz;
11090Sstevel@tonic-gate if (mprotect(start + nbytes, 1, PROT_NONE) == -1)
11100Sstevel@tonic-gate perror("Warning: mprotect");
11110Sstevel@tonic-gate
11120Sstevel@tonic-gate return (start);
11130Sstevel@tonic-gate }
11140Sstevel@tonic-gate
11150Sstevel@tonic-gate /*
11160Sstevel@tonic-gate * resetperm - reduce security vulnerabilities by resetting
11170Sstevel@tonic-gate * owner/group/permissions. Always attempt setuid() - if we have
11180Sstevel@tonic-gate * permission to drop our privilege level, do so.
11190Sstevel@tonic-gate */
11200Sstevel@tonic-gate void
resetperm(void)11210Sstevel@tonic-gate resetperm(void)
11220Sstevel@tonic-gate {
11230Sstevel@tonic-gate if (geteuid() == 0) {
11240Sstevel@tonic-gate (void) setgid(GID_NOBODY);
11250Sstevel@tonic-gate (void) setuid(UID_NOBODY);
11260Sstevel@tonic-gate }
11270Sstevel@tonic-gate }
1128