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