17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 54ab75253Smrj * Common Development and Distribution License (the "License"). 64ab75253Smrj * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 214ab75253Smrj 227c478bd9Sstevel@tonic-gate /* 23b78ff649Smeem * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <stdio.h> 287c478bd9Sstevel@tonic-gate #include <unistd.h> 297c478bd9Sstevel@tonic-gate #include <stropts.h> 307c478bd9Sstevel@tonic-gate #include <string.h> 317c478bd9Sstevel@tonic-gate #include <stdlib.h> 327c478bd9Sstevel@tonic-gate #include <fcntl.h> 337c478bd9Sstevel@tonic-gate #include <stdarg.h> 347c478bd9Sstevel@tonic-gate #include <setjmp.h> 357c478bd9Sstevel@tonic-gate #include <string.h> 367c478bd9Sstevel@tonic-gate #include <errno.h> 377c478bd9Sstevel@tonic-gate #include <sys/types.h> 387c478bd9Sstevel@tonic-gate #include <sys/time.h> 397c478bd9Sstevel@tonic-gate #include <signal.h> 407c478bd9Sstevel@tonic-gate #include <sys/mman.h> 417c478bd9Sstevel@tonic-gate #include <assert.h> 427c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate #include <sys/socket.h> 457c478bd9Sstevel@tonic-gate #include <sys/pfmod.h> 467c478bd9Sstevel@tonic-gate #include <net/if.h> 477c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h> 487c478bd9Sstevel@tonic-gate #include <netinet/in.h> 497c478bd9Sstevel@tonic-gate #include <netinet/if_ether.h> 507c478bd9Sstevel@tonic-gate #include <netdb.h> 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate #include "snoop.h" 537c478bd9Sstevel@tonic-gate 5445916cd2Sjpk static int snaplen; 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate /* Global error recovery variables */ 577c478bd9Sstevel@tonic-gate sigjmp_buf jmp_env, ojmp_env; /* error recovery jmp buf */ 587c478bd9Sstevel@tonic-gate int snoop_nrecover; /* number of recoveries on curr pkt */ 597c478bd9Sstevel@tonic-gate int quitting; /* user termination flag */ 607c478bd9Sstevel@tonic-gate 6145916cd2Sjpk static struct snoop_handler *snoop_hp; /* global alarm handler head */ 6245916cd2Sjpk static struct snoop_handler *snoop_tp; /* global alarm handler tail */ 6345916cd2Sjpk static time_t snoop_nalarm; /* time of next alarm */ 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate /* protected interpreter output areas */ 667c478bd9Sstevel@tonic-gate #define MAXSUM 8 677c478bd9Sstevel@tonic-gate #define REDZONE 64 687c478bd9Sstevel@tonic-gate static char *sumline[MAXSUM]; 697c478bd9Sstevel@tonic-gate static char *detail_line; 707c478bd9Sstevel@tonic-gate static char *line; 717c478bd9Sstevel@tonic-gate static char *encap; 727c478bd9Sstevel@tonic-gate 7345916cd2Sjpk static int audio; 747c478bd9Sstevel@tonic-gate int maxcount; /* maximum no of packets to capture */ 757c478bd9Sstevel@tonic-gate int count; /* count of packets captured */ 7645916cd2Sjpk static int sumcount; 777c478bd9Sstevel@tonic-gate int x_offset = -1; 787c478bd9Sstevel@tonic-gate int x_length = 0x7fffffff; 797c478bd9Sstevel@tonic-gate FILE *namefile; 80b127ac41SPhilip Kirk boolean_t Pflg; 81b127ac41SPhilip Kirk boolean_t Iflg; 82b127ac41SPhilip Kirk boolean_t qflg; 83b127ac41SPhilip Kirk boolean_t rflg; 847c478bd9Sstevel@tonic-gate #ifdef DEBUG 85b127ac41SPhilip Kirk boolean_t zflg; 867c478bd9Sstevel@tonic-gate #endif 877c478bd9Sstevel@tonic-gate struct Pf_ext_packetfilt pf; 887c478bd9Sstevel@tonic-gate 89605445d5Sdg199075 static int vlanid = 0; 90605445d5Sdg199075 9145916cd2Sjpk static void usage(void); 9245916cd2Sjpk static void snoop_sigrecover(int sig, siginfo_t *info, void *p); 937c478bd9Sstevel@tonic-gate static char *protmalloc(size_t); 947c478bd9Sstevel@tonic-gate static void resetperm(void); 957c478bd9Sstevel@tonic-gate 962e3b6467Skcpoon int 972e3b6467Skcpoon main(int argc, char **argv) 987c478bd9Sstevel@tonic-gate { 997c478bd9Sstevel@tonic-gate int c; 1007c478bd9Sstevel@tonic-gate int filter = 0; 1017c478bd9Sstevel@tonic-gate int flags = F_SUM; 1027c478bd9Sstevel@tonic-gate struct Pf_ext_packetfilt *fp = NULL; 1037c478bd9Sstevel@tonic-gate char *icapfile = NULL; 1047c478bd9Sstevel@tonic-gate char *ocapfile = NULL; 105b127ac41SPhilip Kirk boolean_t nflg = B_FALSE; 106b127ac41SPhilip Kirk boolean_t Nflg = B_FALSE; 1077c478bd9Sstevel@tonic-gate int Cflg = 0; 108b127ac41SPhilip Kirk boolean_t Uflg = B_FALSE; 1097c478bd9Sstevel@tonic-gate int first = 1; 1107c478bd9Sstevel@tonic-gate int last = 0x7fffffff; 111b127ac41SPhilip Kirk boolean_t use_kern_pf; 1127c478bd9Sstevel@tonic-gate char *p, *p2; 1137c478bd9Sstevel@tonic-gate char names[MAXPATHLEN + 1]; 1147c478bd9Sstevel@tonic-gate char self[MAXHOSTNAMELEN + 1]; 1157c478bd9Sstevel@tonic-gate char *argstr = NULL; 1167c478bd9Sstevel@tonic-gate void (*proc)(); 1177c478bd9Sstevel@tonic-gate char *audiodev; 1187c478bd9Sstevel@tonic-gate int ret; 1197c478bd9Sstevel@tonic-gate struct sigaction sigact; 1207c478bd9Sstevel@tonic-gate stack_t sigstk; 1217c478bd9Sstevel@tonic-gate char *output_area; 1227c478bd9Sstevel@tonic-gate int nbytes; 123b78ff649Smeem char *datalink = NULL; 124c7e4935fSss150715 dlpi_handle_t dh; 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate names[0] = '\0'; 1277c478bd9Sstevel@tonic-gate /* 1287c478bd9Sstevel@tonic-gate * Global error recovery: Prepare for interpreter failures 1297c478bd9Sstevel@tonic-gate * with corrupted packets or confused interpreters. 1307c478bd9Sstevel@tonic-gate * Allocate protected output and stack areas, with generous 1317c478bd9Sstevel@tonic-gate * red-zones. 1327c478bd9Sstevel@tonic-gate */ 1337c478bd9Sstevel@tonic-gate nbytes = (MAXSUM + 3) * (MAXLINE + REDZONE); 1347c478bd9Sstevel@tonic-gate output_area = protmalloc(nbytes); 1357c478bd9Sstevel@tonic-gate if (output_area == NULL) { 1367c478bd9Sstevel@tonic-gate perror("Warning: mmap"); 1377c478bd9Sstevel@tonic-gate exit(1); 1387c478bd9Sstevel@tonic-gate } 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate /* Allocate protected output areas */ 1417c478bd9Sstevel@tonic-gate for (ret = 0; ret < MAXSUM; ret++) { 1427c478bd9Sstevel@tonic-gate sumline[ret] = (char *)output_area; 1437c478bd9Sstevel@tonic-gate output_area += (MAXLINE + REDZONE); 1447c478bd9Sstevel@tonic-gate } 1457c478bd9Sstevel@tonic-gate detail_line = output_area; 1467c478bd9Sstevel@tonic-gate output_area += MAXLINE + REDZONE; 1477c478bd9Sstevel@tonic-gate line = output_area; 1487c478bd9Sstevel@tonic-gate output_area += MAXLINE + REDZONE; 1497c478bd9Sstevel@tonic-gate encap = output_area; 1507c478bd9Sstevel@tonic-gate output_area += MAXLINE + REDZONE; 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate /* Initialize an alternate signal stack to increase robustness */ 1537c478bd9Sstevel@tonic-gate if ((sigstk.ss_sp = (char *)malloc(SIGSTKSZ+REDZONE)) == NULL) { 1547c478bd9Sstevel@tonic-gate perror("Warning: malloc"); 1557c478bd9Sstevel@tonic-gate exit(1); 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate sigstk.ss_size = SIGSTKSZ; 1587c478bd9Sstevel@tonic-gate sigstk.ss_flags = 0; 1597c478bd9Sstevel@tonic-gate if (sigaltstack(&sigstk, (stack_t *)NULL) < 0) { 1607c478bd9Sstevel@tonic-gate perror("Warning: sigaltstack"); 1617c478bd9Sstevel@tonic-gate exit(1); 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate /* Initialize a master signal handler */ 1657c478bd9Sstevel@tonic-gate sigact.sa_handler = NULL; 1667c478bd9Sstevel@tonic-gate sigact.sa_sigaction = snoop_sigrecover; 16745916cd2Sjpk (void) sigemptyset(&sigact.sa_mask); 1687c478bd9Sstevel@tonic-gate sigact.sa_flags = SA_ONSTACK|SA_SIGINFO; 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate /* Register master signal handler */ 1717c478bd9Sstevel@tonic-gate if (sigaction(SIGHUP, &sigact, (struct sigaction *)NULL) < 0) { 1727c478bd9Sstevel@tonic-gate perror("Warning: sigaction"); 1737c478bd9Sstevel@tonic-gate exit(1); 1747c478bd9Sstevel@tonic-gate } 1757c478bd9Sstevel@tonic-gate if (sigaction(SIGINT, &sigact, (struct sigaction *)NULL) < 0) { 1767c478bd9Sstevel@tonic-gate perror("Warning: sigaction"); 1777c478bd9Sstevel@tonic-gate exit(1); 1787c478bd9Sstevel@tonic-gate } 1797c478bd9Sstevel@tonic-gate if (sigaction(SIGQUIT, &sigact, (struct sigaction *)NULL) < 0) { 1807c478bd9Sstevel@tonic-gate perror("Warning: sigaction"); 1817c478bd9Sstevel@tonic-gate exit(1); 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate if (sigaction(SIGILL, &sigact, (struct sigaction *)NULL) < 0) { 1847c478bd9Sstevel@tonic-gate perror("Warning: sigaction"); 1857c478bd9Sstevel@tonic-gate exit(1); 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate if (sigaction(SIGTRAP, &sigact, (struct sigaction *)NULL) < 0) { 1887c478bd9Sstevel@tonic-gate perror("Warning: sigaction"); 1897c478bd9Sstevel@tonic-gate exit(1); 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate if (sigaction(SIGIOT, &sigact, (struct sigaction *)NULL) < 0) { 1927c478bd9Sstevel@tonic-gate perror("Warning: sigaction"); 1937c478bd9Sstevel@tonic-gate exit(1); 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate if (sigaction(SIGEMT, &sigact, (struct sigaction *)NULL) < 0) { 1967c478bd9Sstevel@tonic-gate perror("Warning: sigaction"); 1977c478bd9Sstevel@tonic-gate exit(1); 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate if (sigaction(SIGFPE, &sigact, (struct sigaction *)NULL) < 0) { 2007c478bd9Sstevel@tonic-gate perror("Warning: sigaction"); 2017c478bd9Sstevel@tonic-gate exit(1); 2027c478bd9Sstevel@tonic-gate } 2037c478bd9Sstevel@tonic-gate if (sigaction(SIGBUS, &sigact, (struct sigaction *)NULL) < 0) { 2047c478bd9Sstevel@tonic-gate perror("Warning: sigaction"); 2057c478bd9Sstevel@tonic-gate exit(1); 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate if (sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL) < 0) { 2087c478bd9Sstevel@tonic-gate perror("Warning: sigaction"); 2097c478bd9Sstevel@tonic-gate exit(1); 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate if (sigaction(SIGSYS, &sigact, (struct sigaction *)NULL) < 0) { 2127c478bd9Sstevel@tonic-gate perror("Warning: sigaction"); 2137c478bd9Sstevel@tonic-gate exit(1); 2147c478bd9Sstevel@tonic-gate } 2157c478bd9Sstevel@tonic-gate if (sigaction(SIGALRM, &sigact, (struct sigaction *)NULL) < 0) { 2167c478bd9Sstevel@tonic-gate perror("Warning: sigaction"); 2177c478bd9Sstevel@tonic-gate exit(1); 2187c478bd9Sstevel@tonic-gate } 2197c478bd9Sstevel@tonic-gate if (sigaction(SIGTERM, &sigact, (struct sigaction *)NULL) < 0) { 2207c478bd9Sstevel@tonic-gate perror("Warning: sigaction"); 2217c478bd9Sstevel@tonic-gate exit(1); 2227c478bd9Sstevel@tonic-gate } 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate /* Prepare for failure during program initialization/exit */ 2257c478bd9Sstevel@tonic-gate if (sigsetjmp(jmp_env, 1)) { 2267c478bd9Sstevel@tonic-gate exit(1); 2277c478bd9Sstevel@tonic-gate } 22845916cd2Sjpk (void) setvbuf(stdout, NULL, _IOLBF, BUFSIZ); 2297c478bd9Sstevel@tonic-gate 230b127ac41SPhilip Kirk while ((c = getopt(argc, argv, "at:CPDSi:o:Nn:s:d:I:vVp:f:c:x:U?rqz")) 2317c478bd9Sstevel@tonic-gate != EOF) { 2327c478bd9Sstevel@tonic-gate switch (c) { 2337c478bd9Sstevel@tonic-gate case 'a': 2347c478bd9Sstevel@tonic-gate audiodev = getenv("AUDIODEV"); 2357c478bd9Sstevel@tonic-gate if (audiodev == NULL) 2367c478bd9Sstevel@tonic-gate audiodev = "/dev/audio"; 2377c478bd9Sstevel@tonic-gate audio = open(audiodev, O_WRONLY); 2387c478bd9Sstevel@tonic-gate if (audio < 0) { 2397c478bd9Sstevel@tonic-gate pr_err("Audio device %s: %m", 2407c478bd9Sstevel@tonic-gate audiodev); 2417c478bd9Sstevel@tonic-gate exit(1); 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate break; 2447c478bd9Sstevel@tonic-gate case 't': 2457c478bd9Sstevel@tonic-gate flags |= F_TIME; 2467c478bd9Sstevel@tonic-gate switch (*optarg) { 2477c478bd9Sstevel@tonic-gate case 'r': flags |= F_RTIME; break; 2487c478bd9Sstevel@tonic-gate case 'a': flags |= F_ATIME; break; 2497c478bd9Sstevel@tonic-gate case 'd': break; 2507c478bd9Sstevel@tonic-gate default: usage(); 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate break; 253b127ac41SPhilip Kirk case 'I': 254b78ff649Smeem if (datalink != NULL) 255b127ac41SPhilip Kirk usage(); 256b127ac41SPhilip Kirk Iflg = B_TRUE; 257b78ff649Smeem datalink = optarg; 258b127ac41SPhilip Kirk break; 2597c478bd9Sstevel@tonic-gate case 'P': 260b127ac41SPhilip Kirk Pflg = B_TRUE; 2617c478bd9Sstevel@tonic-gate break; 2627c478bd9Sstevel@tonic-gate case 'D': 2637c478bd9Sstevel@tonic-gate flags |= F_DROPS; 2647c478bd9Sstevel@tonic-gate break; 2657c478bd9Sstevel@tonic-gate case 'S': 2667c478bd9Sstevel@tonic-gate flags |= F_LEN; 2677c478bd9Sstevel@tonic-gate break; 2687c478bd9Sstevel@tonic-gate case 'i': 2697c478bd9Sstevel@tonic-gate icapfile = optarg; 2707c478bd9Sstevel@tonic-gate break; 2717c478bd9Sstevel@tonic-gate case 'o': 2727c478bd9Sstevel@tonic-gate ocapfile = optarg; 2737c478bd9Sstevel@tonic-gate break; 2747c478bd9Sstevel@tonic-gate case 'N': 275b127ac41SPhilip Kirk Nflg = B_TRUE; 2767c478bd9Sstevel@tonic-gate break; 2777c478bd9Sstevel@tonic-gate case 'n': 278b127ac41SPhilip Kirk nflg = B_TRUE; 2797c478bd9Sstevel@tonic-gate (void) strlcpy(names, optarg, MAXPATHLEN); 2807c478bd9Sstevel@tonic-gate break; 2817c478bd9Sstevel@tonic-gate case 's': 2827c478bd9Sstevel@tonic-gate snaplen = atoi(optarg); 2837c478bd9Sstevel@tonic-gate break; 2847c478bd9Sstevel@tonic-gate case 'd': 285b127ac41SPhilip Kirk if (Iflg) 286b127ac41SPhilip Kirk usage(); 287b78ff649Smeem datalink = optarg; 2887c478bd9Sstevel@tonic-gate break; 2897c478bd9Sstevel@tonic-gate case 'v': 2907c478bd9Sstevel@tonic-gate flags &= ~(F_SUM); 2917c478bd9Sstevel@tonic-gate flags |= F_DTAIL; 2927c478bd9Sstevel@tonic-gate break; 2937c478bd9Sstevel@tonic-gate case 'V': 2947c478bd9Sstevel@tonic-gate flags |= F_ALLSUM; 2957c478bd9Sstevel@tonic-gate break; 2967c478bd9Sstevel@tonic-gate case 'p': 2977c478bd9Sstevel@tonic-gate p = optarg; 2987c478bd9Sstevel@tonic-gate p2 = strpbrk(p, ",:-"); 2997c478bd9Sstevel@tonic-gate if (p2 == NULL) { 3007c478bd9Sstevel@tonic-gate first = last = atoi(p); 3017c478bd9Sstevel@tonic-gate } else { 3027c478bd9Sstevel@tonic-gate *p2++ = '\0'; 3037c478bd9Sstevel@tonic-gate first = atoi(p); 3047c478bd9Sstevel@tonic-gate last = atoi(p2); 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate break; 3077c478bd9Sstevel@tonic-gate case 'f': 3087c478bd9Sstevel@tonic-gate (void) gethostname(self, MAXHOSTNAMELEN); 3097c478bd9Sstevel@tonic-gate p = strchr(optarg, ':'); 3107c478bd9Sstevel@tonic-gate if (p) { 3117c478bd9Sstevel@tonic-gate *p = '\0'; 3127c478bd9Sstevel@tonic-gate if (strcmp(optarg, self) == 0 || 3137c478bd9Sstevel@tonic-gate strcmp(p+1, self) == 0) 3147c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3157c478bd9Sstevel@tonic-gate "Warning: cannot capture packets from %s\n", 3167c478bd9Sstevel@tonic-gate self); 3177c478bd9Sstevel@tonic-gate *p = ' '; 3187c478bd9Sstevel@tonic-gate } else if (strcmp(optarg, self) == 0) 3197c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3207c478bd9Sstevel@tonic-gate "Warning: cannot capture packets from %s\n", 3217c478bd9Sstevel@tonic-gate self); 3227c478bd9Sstevel@tonic-gate argstr = optarg; 3237c478bd9Sstevel@tonic-gate break; 3247c478bd9Sstevel@tonic-gate case 'x': 3257c478bd9Sstevel@tonic-gate p = optarg; 3267c478bd9Sstevel@tonic-gate p2 = strpbrk(p, ",:-"); 3277c478bd9Sstevel@tonic-gate if (p2 == NULL) { 3287c478bd9Sstevel@tonic-gate x_offset = atoi(p); 3297c478bd9Sstevel@tonic-gate x_length = -1; 3307c478bd9Sstevel@tonic-gate } else { 3317c478bd9Sstevel@tonic-gate *p2++ = '\0'; 3327c478bd9Sstevel@tonic-gate x_offset = atoi(p); 3337c478bd9Sstevel@tonic-gate x_length = atoi(p2); 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate break; 3367c478bd9Sstevel@tonic-gate case 'c': 3377c478bd9Sstevel@tonic-gate maxcount = atoi(optarg); 3387c478bd9Sstevel@tonic-gate break; 3397c478bd9Sstevel@tonic-gate case 'C': 340b127ac41SPhilip Kirk Cflg = B_TRUE; 3417c478bd9Sstevel@tonic-gate break; 3427c478bd9Sstevel@tonic-gate case 'q': 3437c478bd9Sstevel@tonic-gate qflg = B_TRUE; 3447c478bd9Sstevel@tonic-gate break; 3457c478bd9Sstevel@tonic-gate case 'r': 3467c478bd9Sstevel@tonic-gate rflg = B_TRUE; 3477c478bd9Sstevel@tonic-gate break; 348b127ac41SPhilip Kirk case 'U': 349b127ac41SPhilip Kirk Uflg = B_TRUE; 350b127ac41SPhilip Kirk break; 3517c478bd9Sstevel@tonic-gate #ifdef DEBUG 3527c478bd9Sstevel@tonic-gate case 'z': 3537c478bd9Sstevel@tonic-gate zflg = B_TRUE; 3547c478bd9Sstevel@tonic-gate break; 3557c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 3567c478bd9Sstevel@tonic-gate case '?': 3577c478bd9Sstevel@tonic-gate default: 3587c478bd9Sstevel@tonic-gate usage(); 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate if (argc > optind) 3637c478bd9Sstevel@tonic-gate argstr = (char *)concat_args(&argv[optind], argc - optind); 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate /* 3667c478bd9Sstevel@tonic-gate * Need to know before we decide on filtering method some things 3677c478bd9Sstevel@tonic-gate * about the interface. So, go ahead and do part of the initialization 368b78ff649Smeem * now so we have that data. Note that if no datalink is specified, 369b78ff649Smeem * open_datalink() selects one and returns it. In an ideal world, 3707c478bd9Sstevel@tonic-gate * it might be nice if the "correct" interface for the filter 3717c478bd9Sstevel@tonic-gate * requested was chosen, but that's too hard. 3727c478bd9Sstevel@tonic-gate */ 3737c478bd9Sstevel@tonic-gate if (!icapfile) { 374b78ff649Smeem use_kern_pf = open_datalink(&dh, datalink); 3757c478bd9Sstevel@tonic-gate } else { 376b127ac41SPhilip Kirk use_kern_pf = B_FALSE; 3777c478bd9Sstevel@tonic-gate cap_open_read(icapfile); 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate if (!nflg) { 3807c478bd9Sstevel@tonic-gate names[0] = '\0'; 3817c478bd9Sstevel@tonic-gate (void) strlcpy(names, icapfile, MAXPATHLEN); 3827c478bd9Sstevel@tonic-gate (void) strlcat(names, ".names", MAXPATHLEN); 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate 386b127ac41SPhilip Kirk if (Uflg) 387b127ac41SPhilip Kirk use_kern_pf = B_FALSE; 388b127ac41SPhilip Kirk 3897c478bd9Sstevel@tonic-gate /* attempt to read .names file if it exists before filtering */ 3907c478bd9Sstevel@tonic-gate if ((!Nflg) && names[0] != '\0') { 3917c478bd9Sstevel@tonic-gate if (access(names, F_OK) == 0) { 3927c478bd9Sstevel@tonic-gate load_names(names); 3937c478bd9Sstevel@tonic-gate } else if (nflg) { 3947c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s not found\n", names); 3957c478bd9Sstevel@tonic-gate exit(1); 3967c478bd9Sstevel@tonic-gate } 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate if (argstr) { 400b127ac41SPhilip Kirk if (use_kern_pf) { 4017c478bd9Sstevel@tonic-gate ret = pf_compile(argstr, Cflg); 4027c478bd9Sstevel@tonic-gate switch (ret) { 4037c478bd9Sstevel@tonic-gate case 0: 4047c478bd9Sstevel@tonic-gate filter++; 4057c478bd9Sstevel@tonic-gate compile(argstr, Cflg); 4067c478bd9Sstevel@tonic-gate break; 4077c478bd9Sstevel@tonic-gate case 1: 4087c478bd9Sstevel@tonic-gate fp = &pf; 4097c478bd9Sstevel@tonic-gate break; 4107c478bd9Sstevel@tonic-gate case 2: 4117c478bd9Sstevel@tonic-gate fp = &pf; 4127c478bd9Sstevel@tonic-gate filter++; 4137c478bd9Sstevel@tonic-gate break; 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate } else { 4167c478bd9Sstevel@tonic-gate filter++; 4177c478bd9Sstevel@tonic-gate compile(argstr, Cflg); 4187c478bd9Sstevel@tonic-gate } 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate if (Cflg) 4217c478bd9Sstevel@tonic-gate exit(0); 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate if (flags & F_SUM) 4257c478bd9Sstevel@tonic-gate flags |= F_WHO; 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate /* 4287c478bd9Sstevel@tonic-gate * If the -o flag is set then capture packets 4297c478bd9Sstevel@tonic-gate * directly to a file. Don't attempt to 4307c478bd9Sstevel@tonic-gate * interpret them on the fly (F_NOW). 4317c478bd9Sstevel@tonic-gate * Note: capture to file is much less likely 4327c478bd9Sstevel@tonic-gate * to drop packets since we don't spend cpu 4337c478bd9Sstevel@tonic-gate * cycles running through the interpreters 4347c478bd9Sstevel@tonic-gate * and possibly hanging in address-to-name 4357c478bd9Sstevel@tonic-gate * mappings through the name service. 4367c478bd9Sstevel@tonic-gate */ 4377c478bd9Sstevel@tonic-gate if (ocapfile) { 4387c478bd9Sstevel@tonic-gate cap_open_write(ocapfile); 4397c478bd9Sstevel@tonic-gate proc = cap_write; 4407c478bd9Sstevel@tonic-gate } else { 4417c478bd9Sstevel@tonic-gate flags |= F_NOW; 4427c478bd9Sstevel@tonic-gate proc = process_pkt; 4437c478bd9Sstevel@tonic-gate } 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate /* 4477c478bd9Sstevel@tonic-gate * If the -i flag is set then get packets from 4487c478bd9Sstevel@tonic-gate * the log file which has been previously captured 4497c478bd9Sstevel@tonic-gate * with the -o option. 4507c478bd9Sstevel@tonic-gate */ 4517c478bd9Sstevel@tonic-gate if (icapfile) { 4527c478bd9Sstevel@tonic-gate names[0] = '\0'; 4537c478bd9Sstevel@tonic-gate (void) strlcpy(names, icapfile, MAXPATHLEN); 4547c478bd9Sstevel@tonic-gate (void) strlcat(names, ".names", MAXPATHLEN); 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate if (Nflg) { 4577c478bd9Sstevel@tonic-gate namefile = fopen(names, "w"); 4587c478bd9Sstevel@tonic-gate if (namefile == NULL) { 4597c478bd9Sstevel@tonic-gate perror(names); 4607c478bd9Sstevel@tonic-gate exit(1); 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate flags = 0; 4637c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 4647c478bd9Sstevel@tonic-gate "Creating name file %s\n", names); 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate if (flags & F_DTAIL) 4687c478bd9Sstevel@tonic-gate flags = F_DTAIL; 4697c478bd9Sstevel@tonic-gate else 4707c478bd9Sstevel@tonic-gate flags |= F_NUM | F_TIME; 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate resetperm(); 4737c478bd9Sstevel@tonic-gate cap_read(first, last, filter, proc, flags); 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate if (Nflg) 4767c478bd9Sstevel@tonic-gate (void) fclose(namefile); 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate } else { 4797c478bd9Sstevel@tonic-gate const int chunksize = 8 * 8192; 4807c478bd9Sstevel@tonic-gate struct timeval timeout; 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate /* 4837c478bd9Sstevel@tonic-gate * If listening to packets on audio 4847c478bd9Sstevel@tonic-gate * then set the buffer timeout down 4857c478bd9Sstevel@tonic-gate * to 1/10 sec. A higher value 4867c478bd9Sstevel@tonic-gate * makes the audio "bursty". 4877c478bd9Sstevel@tonic-gate */ 4887c478bd9Sstevel@tonic-gate if (audio) { 4897c478bd9Sstevel@tonic-gate timeout.tv_sec = 0; 4907c478bd9Sstevel@tonic-gate timeout.tv_usec = 100000; 4917c478bd9Sstevel@tonic-gate } else { 4927c478bd9Sstevel@tonic-gate timeout.tv_sec = 1; 4937c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 4947c478bd9Sstevel@tonic-gate } 4957c478bd9Sstevel@tonic-gate 496b78ff649Smeem init_datalink(dh, snaplen, chunksize, &timeout, fp); 4977c478bd9Sstevel@tonic-gate if (! qflg && ocapfile) 4987c478bd9Sstevel@tonic-gate show_count(); 4997c478bd9Sstevel@tonic-gate resetperm(); 500c7e4935fSss150715 net_read(dh, chunksize, filter, proc, flags); 501c7e4935fSss150715 dlpi_close(dh); 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate if (!(flags & F_NOW)) 50445916cd2Sjpk (void) printf("\n"); 5057c478bd9Sstevel@tonic-gate } 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate if (ocapfile) 5087c478bd9Sstevel@tonic-gate cap_close(); 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate return (0); 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate 51345916cd2Sjpk static int tone[] = { 514ba1637f8Smh138676 0x076113, 0x153333, 0x147317, 0x144311, 0x147315, 0x050353, 0x037103, 0x051106, 515ba1637f8Smh138676 0x157155, 0x142723, 0x133273, 0x134664, 0x051712, 0x024465, 0x026447, 0x072473, 516ba1637f8Smh138676 0x136715, 0x126257, 0x135256, 0x047344, 0x034476, 0x027464, 0x036062, 0x133334, 517ba1637f8Smh138676 0x127256, 0x130660, 0x136262, 0x040724, 0x016446, 0x025437, 0x137171, 0x127672, 518ba1637f8Smh138676 0x124655, 0x134654, 0x032741, 0x021447, 0x037450, 0x125675, 0x127650, 0x077277, 519ba1637f8Smh138676 0x046514, 0x036077, 0x035471, 0x147131, 0x136272, 0x162720, 0x166151, 0x037527, 5207c478bd9Sstevel@tonic-gate }; 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate /* 523ba1637f8Smh138676 * Make a sound on /dev/audio according to the length of the packet. The 524ba1637f8Smh138676 * tone data was ripped from /usr/share/audio/samples/au/bark.au. The 525ba1637f8Smh138676 * amount of waveform used is a function of packet length e.g. a series 526ba1637f8Smh138676 * of small packets is heard as clicks, whereas a series of NFS packets in 527ba1637f8Smh138676 * an 8k read sounds like a "WHAAAARP". 5287c478bd9Sstevel@tonic-gate */ 5297c478bd9Sstevel@tonic-gate void 530*87aafc05SYuri Pankov click(int len) 5317c478bd9Sstevel@tonic-gate { 5327c478bd9Sstevel@tonic-gate len /= 8; 5337c478bd9Sstevel@tonic-gate len = len ? len : 4; 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate if (audio) { 53645916cd2Sjpk (void) write(audio, tone, len); 5377c478bd9Sstevel@tonic-gate } 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate /* Display a count of packets */ 5417c478bd9Sstevel@tonic-gate void 5427c478bd9Sstevel@tonic-gate show_count() 5437c478bd9Sstevel@tonic-gate { 5447c478bd9Sstevel@tonic-gate static int prev = -1; 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate if (count == prev) 5477c478bd9Sstevel@tonic-gate return; 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate prev = count; 5507c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\r%d ", count); 5517c478bd9Sstevel@tonic-gate } 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate #define ENCAP_LEN 16 /* Hold "(NN encap)" */ 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate /* 5567c478bd9Sstevel@tonic-gate * Display data that's external to the packet. 5577c478bd9Sstevel@tonic-gate * This constitutes the first half of the summary 5587c478bd9Sstevel@tonic-gate * line display. 5597c478bd9Sstevel@tonic-gate */ 5607c478bd9Sstevel@tonic-gate void 561*87aafc05SYuri Pankov show_pktinfo(int flags, int num, char *src, char *dst, struct timeval *ptvp, 562*87aafc05SYuri Pankov struct timeval *tvp, int drops, int len) 5637c478bd9Sstevel@tonic-gate { 5647c478bd9Sstevel@tonic-gate struct tm *tm; 5657c478bd9Sstevel@tonic-gate static struct timeval tvp0; 5667c478bd9Sstevel@tonic-gate int sec, usec; 5677c478bd9Sstevel@tonic-gate char *lp = line; 5687c478bd9Sstevel@tonic-gate int i, start; 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate if (flags & F_NUM) { 57145916cd2Sjpk (void) sprintf(lp, "%3d ", num); 5727c478bd9Sstevel@tonic-gate lp += strlen(lp); 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate tm = localtime(&tvp->tv_sec); 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate if (flags & F_TIME) { 5777c478bd9Sstevel@tonic-gate if (flags & F_ATIME) { 578*87aafc05SYuri Pankov (void) sprintf(lp, "%02d:%02d:%02d.%05d ", 5797c478bd9Sstevel@tonic-gate tm->tm_hour, tm->tm_min, tm->tm_sec, 58045916cd2Sjpk (int)tvp->tv_usec / 10); 5817c478bd9Sstevel@tonic-gate lp += strlen(lp); 5827c478bd9Sstevel@tonic-gate } else { 5837c478bd9Sstevel@tonic-gate if (flags & F_RTIME) { 5847c478bd9Sstevel@tonic-gate if (tvp0.tv_sec == 0) { 5857c478bd9Sstevel@tonic-gate tvp0.tv_sec = tvp->tv_sec; 5867c478bd9Sstevel@tonic-gate tvp0.tv_usec = tvp->tv_usec; 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate ptvp = &tvp0; 5897c478bd9Sstevel@tonic-gate } 5907c478bd9Sstevel@tonic-gate sec = tvp->tv_sec - ptvp->tv_sec; 5917c478bd9Sstevel@tonic-gate usec = tvp->tv_usec - ptvp->tv_usec; 5927c478bd9Sstevel@tonic-gate if (usec < 0) { 5937c478bd9Sstevel@tonic-gate usec += 1000000; 5947c478bd9Sstevel@tonic-gate sec -= 1; 5957c478bd9Sstevel@tonic-gate } 59645916cd2Sjpk (void) sprintf(lp, "%3d.%05d ", sec, usec / 10); 5977c478bd9Sstevel@tonic-gate lp += strlen(lp); 5987c478bd9Sstevel@tonic-gate } 5997c478bd9Sstevel@tonic-gate } 6007c478bd9Sstevel@tonic-gate 601605445d5Sdg199075 if ((flags & F_SUM) && !(flags & F_ALLSUM) && (vlanid != 0)) { 602605445d5Sdg199075 (void) snprintf(lp, MAXLINE, "VLAN#%i: ", vlanid); 603605445d5Sdg199075 lp += strlen(lp); 604605445d5Sdg199075 } 605605445d5Sdg199075 6067c478bd9Sstevel@tonic-gate if (flags & F_WHO) { 60745916cd2Sjpk (void) sprintf(lp, "%12s -> %-12s ", src, dst); 6087c478bd9Sstevel@tonic-gate lp += strlen(lp); 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate if (flags & F_DROPS) { 61245916cd2Sjpk (void) sprintf(lp, "drops: %d ", drops); 6137c478bd9Sstevel@tonic-gate lp += strlen(lp); 6147c478bd9Sstevel@tonic-gate } 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate if (flags & F_LEN) { 61745916cd2Sjpk (void) sprintf(lp, "length: %4d ", len); 6187c478bd9Sstevel@tonic-gate lp += strlen(lp); 6197c478bd9Sstevel@tonic-gate } 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate if (flags & F_SUM) { 6227c478bd9Sstevel@tonic-gate if (flags & F_ALLSUM) 62345916cd2Sjpk (void) printf("________________________________\n"); 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate start = flags & F_ALLSUM ? 0 : sumcount - 1; 62645916cd2Sjpk (void) sprintf(encap, " (%d encap)", total_encap_levels - 1); 62745916cd2Sjpk (void) printf("%s%s%s\n", line, sumline[start], 6287c478bd9Sstevel@tonic-gate ((flags & F_ALLSUM) || (total_encap_levels == 1)) ? "" : 6297c478bd9Sstevel@tonic-gate encap); 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate for (i = start + 1; i < sumcount; i++) 63245916cd2Sjpk (void) printf("%s%s\n", line, sumline[i]); 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate sumcount = 0; 6357c478bd9Sstevel@tonic-gate } 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate if (flags & F_DTAIL) { 63845916cd2Sjpk (void) printf("%s\n\n", detail_line); 6397c478bd9Sstevel@tonic-gate detail_line[0] = '\0'; 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate /* 644605445d5Sdg199075 * The following three routines are called back 6457c478bd9Sstevel@tonic-gate * from the interpreters to display their stuff. 6467c478bd9Sstevel@tonic-gate * The theory is that when snoop becomes a window 6477c478bd9Sstevel@tonic-gate * based tool we can just supply a new version of 6487c478bd9Sstevel@tonic-gate * get_sum_line and get_detail_line and not have 6497c478bd9Sstevel@tonic-gate * to touch the interpreters at all. 6507c478bd9Sstevel@tonic-gate */ 6517c478bd9Sstevel@tonic-gate char * 6527c478bd9Sstevel@tonic-gate get_sum_line() 6537c478bd9Sstevel@tonic-gate { 6547c478bd9Sstevel@tonic-gate int tsumcount = sumcount; 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate if (sumcount >= MAXSUM) { 6577c478bd9Sstevel@tonic-gate sumcount = 0; /* error recovery */ 6587c478bd9Sstevel@tonic-gate pr_err( 6597c478bd9Sstevel@tonic-gate "get_sum_line: sumline overflow (sumcount=%d, MAXSUM=%d)\n", 6607c478bd9Sstevel@tonic-gate tsumcount, MAXSUM); 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate sumline[sumcount][0] = '\0'; 6647c478bd9Sstevel@tonic-gate return (sumline[sumcount++]); 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6687c478bd9Sstevel@tonic-gate char * 669*87aafc05SYuri Pankov get_detail_line(int off, int len) 6707c478bd9Sstevel@tonic-gate { 6717c478bd9Sstevel@tonic-gate if (detail_line[0]) { 67245916cd2Sjpk (void) printf("%s\n", detail_line); 6737c478bd9Sstevel@tonic-gate detail_line[0] = '\0'; 6747c478bd9Sstevel@tonic-gate } 6757c478bd9Sstevel@tonic-gate return (detail_line); 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate /* 679605445d5Sdg199075 * This function exists to make sure that VLAN information is 680605445d5Sdg199075 * prepended to summary lines displayed. The problem this function 681605445d5Sdg199075 * solves is how to display VLAN information while in summary mode. 682605445d5Sdg199075 * Each interpretor uses the get_sum_line and get_detail_line functions 683605445d5Sdg199075 * to get a character buffer to display information to the user. 684605445d5Sdg199075 * get_sum_line is the important one here. Each call to get_sum_line 685605445d5Sdg199075 * gets a buffer which stores one line of information. In summary mode, 686605445d5Sdg199075 * the last line generated is the line printed. Instead of changing each 687605445d5Sdg199075 * interpreter to add VLAN information to the summary line, the ethernet 688605445d5Sdg199075 * interpreter changes to call this function and set an ID. If the ID is not 689605445d5Sdg199075 * zero and snoop is in default summary mode, snoop displays the 690605445d5Sdg199075 * VLAN information at the beginning of the output line. Otherwise, 691605445d5Sdg199075 * no VLAN information is displayed. 692605445d5Sdg199075 */ 693605445d5Sdg199075 void 694605445d5Sdg199075 set_vlan_id(int id) 695605445d5Sdg199075 { 696605445d5Sdg199075 vlanid = id; 697605445d5Sdg199075 } 698605445d5Sdg199075 699605445d5Sdg199075 /* 7007c478bd9Sstevel@tonic-gate * Print an error. 7017c478bd9Sstevel@tonic-gate * Works like printf (fmt string and variable args) 70245916cd2Sjpk * except that it will substitute an error message 7037c478bd9Sstevel@tonic-gate * for a "%m" string (like syslog) and it calls 7047c478bd9Sstevel@tonic-gate * long_jump - it doesn't return to where it was 7057c478bd9Sstevel@tonic-gate * called from - it goes to the last setjmp(). 7067c478bd9Sstevel@tonic-gate */ 70745916cd2Sjpk /* VARARGS1 */ 7087c478bd9Sstevel@tonic-gate void 70945916cd2Sjpk pr_err(const char *fmt, ...) 7107c478bd9Sstevel@tonic-gate { 7117c478bd9Sstevel@tonic-gate va_list ap; 71245916cd2Sjpk char buf[1024], *p2; 71345916cd2Sjpk const char *p1; 7147c478bd9Sstevel@tonic-gate 71545916cd2Sjpk (void) strcpy(buf, "snoop: "); 7167c478bd9Sstevel@tonic-gate p2 = buf + strlen(buf); 7177c478bd9Sstevel@tonic-gate 71845916cd2Sjpk /* 71945916cd2Sjpk * Note that we terminate the buffer with '\n' and '\0'. 72045916cd2Sjpk */ 72145916cd2Sjpk for (p1 = fmt; *p1 != '\0' && p2 < buf + sizeof (buf) - 2; p1++) { 7227c478bd9Sstevel@tonic-gate if (*p1 == '%' && *(p1+1) == 'm') { 72345916cd2Sjpk const char *errstr; 7247c478bd9Sstevel@tonic-gate 72545916cd2Sjpk if ((errstr = strerror(errno)) != NULL) { 72645916cd2Sjpk *p2 = '\0'; 72745916cd2Sjpk (void) strlcat(buf, errstr, sizeof (buf)); 7287c478bd9Sstevel@tonic-gate p2 += strlen(p2); 7297c478bd9Sstevel@tonic-gate } 7307c478bd9Sstevel@tonic-gate p1++; 7317c478bd9Sstevel@tonic-gate } else { 7327c478bd9Sstevel@tonic-gate *p2++ = *p1; 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate } 7357c478bd9Sstevel@tonic-gate if (p2 > buf && *(p2-1) != '\n') 7367c478bd9Sstevel@tonic-gate *p2++ = '\n'; 7377c478bd9Sstevel@tonic-gate *p2 = '\0'; 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate va_start(ap, fmt); 74045916cd2Sjpk /* LINTED: E_SEC_PRINTF_VAR_FMT */ 7417c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, buf, ap); 7427c478bd9Sstevel@tonic-gate va_end(ap); 7437c478bd9Sstevel@tonic-gate snoop_sigrecover(-1, NULL, NULL); /* global error recovery */ 7447c478bd9Sstevel@tonic-gate } 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate /* 747c7e4935fSss150715 * Store a copy of linkname associated with the DLPI handle. 748c7e4935fSss150715 * Save errno before closing the dlpi handle so that the 749c7e4935fSss150715 * correct error value is used if 'err' is a system error. 750c7e4935fSss150715 */ 751c7e4935fSss150715 void 752c7e4935fSss150715 pr_errdlpi(dlpi_handle_t dh, const char *cmd, int err) 753c7e4935fSss150715 { 754c7e4935fSss150715 int save_errno = errno; 755c7e4935fSss150715 char linkname[DLPI_LINKNAME_MAX]; 756c7e4935fSss150715 757c7e4935fSss150715 (void) strlcpy(linkname, dlpi_linkname(dh), sizeof (linkname)); 758c7e4935fSss150715 759c7e4935fSss150715 dlpi_close(dh); 760c7e4935fSss150715 errno = save_errno; 761c7e4935fSss150715 762c7e4935fSss150715 pr_err("%s on \"%s\": %s", cmd, linkname, dlpi_strerror(err)); 763c7e4935fSss150715 } 764c7e4935fSss150715 765c7e4935fSss150715 /* 7667c478bd9Sstevel@tonic-gate * Ye olde usage proc 7677c478bd9Sstevel@tonic-gate * PLEASE keep this up to date! 7687c478bd9Sstevel@tonic-gate * Naive users *love* this stuff. 7697c478bd9Sstevel@tonic-gate */ 77045916cd2Sjpk static void 77145916cd2Sjpk usage(void) 7727c478bd9Sstevel@tonic-gate { 7737c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\nUsage: snoop\n"); 7747c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 7757c478bd9Sstevel@tonic-gate "\t[ -a ] # Listen to packets on audio\n"); 7767c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 777b127ac41SPhilip Kirk "\t[ -d link ] # Listen on named link\n"); 7787c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 7797c478bd9Sstevel@tonic-gate "\t[ -s snaplen ] # Truncate packets\n"); 7807c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 781b127ac41SPhilip Kirk "\t[ -I IP interface ] # Listen on named IP interface\n"); 782b127ac41SPhilip Kirk (void) fprintf(stderr, 7837c478bd9Sstevel@tonic-gate "\t[ -c count ] # Quit after count packets\n"); 7847c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 7857c478bd9Sstevel@tonic-gate "\t[ -P ] # Turn OFF promiscuous mode\n"); 7867c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 7877c478bd9Sstevel@tonic-gate "\t[ -D ] # Report dropped packets\n"); 7887c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 7897c478bd9Sstevel@tonic-gate "\t[ -S ] # Report packet size\n"); 7907c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 7917c478bd9Sstevel@tonic-gate "\t[ -i file ] # Read previously captured packets\n"); 7927c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 7937c478bd9Sstevel@tonic-gate "\t[ -o file ] # Capture packets in file\n"); 7947c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 7957c478bd9Sstevel@tonic-gate "\t[ -n file ] # Load addr-to-name table from file\n"); 7967c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 7977c478bd9Sstevel@tonic-gate "\t[ -N ] # Create addr-to-name table\n"); 7987c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 7997c478bd9Sstevel@tonic-gate "\t[ -t r|a|d ] # Time: Relative, Absolute or Delta\n"); 8007c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 8017c478bd9Sstevel@tonic-gate "\t[ -v ] # Verbose packet display\n"); 8027c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 8037c478bd9Sstevel@tonic-gate "\t[ -V ] # Show all summary lines\n"); 8047c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 8057c478bd9Sstevel@tonic-gate "\t[ -p first[,last] ] # Select packet(s) to display\n"); 8067c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 8077c478bd9Sstevel@tonic-gate "\t[ -x offset[,length] ] # Hex dump from offset for length\n"); 8087c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 8097c478bd9Sstevel@tonic-gate "\t[ -C ] # Print packet filter code\n"); 8107c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 8117c478bd9Sstevel@tonic-gate "\t[ -q ] # Suppress printing packet count\n"); 8127c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 8137c478bd9Sstevel@tonic-gate "\t[ -r ] # Do not resolve address to name\n"); 8147c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 8157c478bd9Sstevel@tonic-gate "\n\t[ filter expression ]\n"); 8167c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\nExample:\n"); 8177c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\tsnoop -o saved host fred\n\n"); 8187c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\tsnoop -i saved -tr -v -p19\n"); 8197c478bd9Sstevel@tonic-gate exit(1); 8207c478bd9Sstevel@tonic-gate } 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate /* 8237c478bd9Sstevel@tonic-gate * sdefault: default global alarm handler. Causes the current packet 8247c478bd9Sstevel@tonic-gate * to be skipped. 8257c478bd9Sstevel@tonic-gate */ 8267c478bd9Sstevel@tonic-gate static void 8277c478bd9Sstevel@tonic-gate sdefault(void) 8287c478bd9Sstevel@tonic-gate { 8297c478bd9Sstevel@tonic-gate snoop_nrecover = SNOOP_MAXRECOVER; 8307c478bd9Sstevel@tonic-gate } 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate /* 8337c478bd9Sstevel@tonic-gate * snoop_alarm: register or unregister an alarm handler to be called after 8347c478bd9Sstevel@tonic-gate * s_sec seconds. Because snoop wasn't written to tolerate random signal 8357c478bd9Sstevel@tonic-gate * delivery, periodic SIGALRM delivery (or SA_RESTART) cannot be used. 8367c478bd9Sstevel@tonic-gate * 8377c478bd9Sstevel@tonic-gate * s_sec argument of 0 seconds unregisters the handler. 8387c478bd9Sstevel@tonic-gate * s_handler argument of NULL registers default handler sdefault(), or 8397c478bd9Sstevel@tonic-gate * unregisters all signal handlers (for error recovery). 8407c478bd9Sstevel@tonic-gate * 8417c478bd9Sstevel@tonic-gate * Variables must be volatile to force the compiler to not optimize 8427c478bd9Sstevel@tonic-gate * out the signal blocking. 8437c478bd9Sstevel@tonic-gate */ 8447c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8457c478bd9Sstevel@tonic-gate int 8467c478bd9Sstevel@tonic-gate snoop_alarm(int s_sec, void (*s_handler)()) 8477c478bd9Sstevel@tonic-gate { 8487c478bd9Sstevel@tonic-gate volatile time_t now; 8497c478bd9Sstevel@tonic-gate volatile time_t nalarm = 0; 8507c478bd9Sstevel@tonic-gate volatile struct snoop_handler *sh = NULL; 8517c478bd9Sstevel@tonic-gate volatile struct snoop_handler *hp, *tp, *next; 8527c478bd9Sstevel@tonic-gate volatile sigset_t s_mask; 8537c478bd9Sstevel@tonic-gate volatile int ret = -1; 8547c478bd9Sstevel@tonic-gate 85545916cd2Sjpk (void) sigemptyset((sigset_t *)&s_mask); 85645916cd2Sjpk (void) sigaddset((sigset_t *)&s_mask, SIGALRM); 8577c478bd9Sstevel@tonic-gate if (s_sec < 0) 8587c478bd9Sstevel@tonic-gate return (-1); 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate /* register an alarm handler */ 8617c478bd9Sstevel@tonic-gate now = time(NULL); 8627c478bd9Sstevel@tonic-gate if (s_sec) { 8637c478bd9Sstevel@tonic-gate sh = malloc(sizeof (struct snoop_handler)); 8647c478bd9Sstevel@tonic-gate sh->s_time = now + s_sec; 8657c478bd9Sstevel@tonic-gate if (s_handler == NULL) 8667c478bd9Sstevel@tonic-gate s_handler = sdefault; 8677c478bd9Sstevel@tonic-gate sh->s_handler = s_handler; 8687c478bd9Sstevel@tonic-gate sh->s_next = NULL; 8697c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, (sigset_t *)&s_mask, NULL); 8707c478bd9Sstevel@tonic-gate if (snoop_hp == NULL) { 8717c478bd9Sstevel@tonic-gate snoop_hp = snoop_tp = (struct snoop_handler *)sh; 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate snoop_nalarm = sh->s_time; 87445916cd2Sjpk (void) alarm(sh->s_time - now); 8757c478bd9Sstevel@tonic-gate } else { 8767c478bd9Sstevel@tonic-gate snoop_tp->s_next = (struct snoop_handler *)sh; 8777c478bd9Sstevel@tonic-gate snoop_tp = (struct snoop_handler *)sh; 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate if (sh->s_time < snoop_nalarm) { 8807c478bd9Sstevel@tonic-gate snoop_nalarm = sh->s_time; 8817c478bd9Sstevel@tonic-gate (void) alarm(sh->s_time - now); 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate } 8847c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_UNBLOCK, (sigset_t *)&s_mask, NULL); 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate return (0); 8877c478bd9Sstevel@tonic-gate } 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate /* unregister an alarm handler */ 8907c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, (sigset_t *)&s_mask, NULL); 8917c478bd9Sstevel@tonic-gate tp = (struct snoop_handler *)&snoop_hp; 8927c478bd9Sstevel@tonic-gate for (hp = snoop_hp; hp; hp = next) { 8937c478bd9Sstevel@tonic-gate next = hp->s_next; 8947c478bd9Sstevel@tonic-gate if (s_handler == NULL || hp->s_handler == s_handler) { 8957c478bd9Sstevel@tonic-gate ret = 0; 8967c478bd9Sstevel@tonic-gate tp->s_next = hp->s_next; 8977c478bd9Sstevel@tonic-gate if (snoop_tp == hp) { 8987c478bd9Sstevel@tonic-gate if (tp == (struct snoop_handler *)&snoop_hp) 8997c478bd9Sstevel@tonic-gate snoop_tp = NULL; 9007c478bd9Sstevel@tonic-gate else 9017c478bd9Sstevel@tonic-gate snoop_tp = (struct snoop_handler *)tp; 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate free((void *)hp); 9047c478bd9Sstevel@tonic-gate } else { 9057c478bd9Sstevel@tonic-gate if (nalarm == 0 || nalarm > hp->s_time) 9067c478bd9Sstevel@tonic-gate nalarm = now < hp->s_time ? hp->s_time : 9077c478bd9Sstevel@tonic-gate now + 1; 9087c478bd9Sstevel@tonic-gate tp = hp; 9097c478bd9Sstevel@tonic-gate } 9107c478bd9Sstevel@tonic-gate } 9117c478bd9Sstevel@tonic-gate /* 9127c478bd9Sstevel@tonic-gate * Stop or adjust timer 9137c478bd9Sstevel@tonic-gate */ 9147c478bd9Sstevel@tonic-gate if (snoop_hp == NULL) { 9157c478bd9Sstevel@tonic-gate snoop_nalarm = 0; 9167c478bd9Sstevel@tonic-gate (void) alarm(0); 9177c478bd9Sstevel@tonic-gate } else if (nalarm > 0 && nalarm < snoop_nalarm) { 9187c478bd9Sstevel@tonic-gate snoop_nalarm = nalarm; 9197c478bd9Sstevel@tonic-gate (void) alarm(nalarm - now); 9207c478bd9Sstevel@tonic-gate } 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_UNBLOCK, (sigset_t *)&s_mask, NULL); 9237c478bd9Sstevel@tonic-gate return (ret); 9247c478bd9Sstevel@tonic-gate } 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate /* 9277c478bd9Sstevel@tonic-gate * snoop_recover: reset snoop's output area, and any internal variables, 9287c478bd9Sstevel@tonic-gate * to allow continuation. 9297c478bd9Sstevel@tonic-gate * XXX: make this an interface such that each interpreter can 9307c478bd9Sstevel@tonic-gate * register a reset routine. 9317c478bd9Sstevel@tonic-gate */ 9327c478bd9Sstevel@tonic-gate void 9337c478bd9Sstevel@tonic-gate snoop_recover(void) 9347c478bd9Sstevel@tonic-gate { 9357c478bd9Sstevel@tonic-gate int i; 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate /* Error recovery: reset output_area and associated variables */ 9387c478bd9Sstevel@tonic-gate for (i = 0; i < MAXSUM; i++) 9397c478bd9Sstevel@tonic-gate sumline[i][0] = '\0'; 9407c478bd9Sstevel@tonic-gate detail_line[0] = '\0'; 9417c478bd9Sstevel@tonic-gate line[0] = '\0'; 9427c478bd9Sstevel@tonic-gate encap[0] = '\0'; 9437c478bd9Sstevel@tonic-gate sumcount = 0; 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate /* stacking/unstacking cannot be relied upon */ 9467c478bd9Sstevel@tonic-gate encap_levels = 0; 9477c478bd9Sstevel@tonic-gate total_encap_levels = 1; 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate /* remove any pending timeouts */ 9507c478bd9Sstevel@tonic-gate (void) snoop_alarm(0, NULL); 9517c478bd9Sstevel@tonic-gate } 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate /* 9547c478bd9Sstevel@tonic-gate * snoop_sigrecover: global sigaction routine to manage recovery 9557c478bd9Sstevel@tonic-gate * from catastrophic interpreter failures while interpreting 9567c478bd9Sstevel@tonic-gate * corrupt trace files/packets. SIGALRM timeouts, program errors, 9577c478bd9Sstevel@tonic-gate * and user termination are all handled. In the case of a corrupt 9587c478bd9Sstevel@tonic-gate * packet or confused interpreter, the packet will be skipped, and 9597c478bd9Sstevel@tonic-gate * execution will continue in scan(). 9607c478bd9Sstevel@tonic-gate * 9617c478bd9Sstevel@tonic-gate * Global alarm handling (see snoop_alarm()) is managed here. 9627c478bd9Sstevel@tonic-gate * 9637c478bd9Sstevel@tonic-gate * Variables must be volatile to force the compiler to not optimize 9647c478bd9Sstevel@tonic-gate * out the signal blocking. 9657c478bd9Sstevel@tonic-gate */ 9667c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 96745916cd2Sjpk static void 9687c478bd9Sstevel@tonic-gate snoop_sigrecover(int sig, siginfo_t *info, void *p) 9697c478bd9Sstevel@tonic-gate { 9707c478bd9Sstevel@tonic-gate volatile time_t now; 9717c478bd9Sstevel@tonic-gate volatile time_t nalarm = 0; 9727c478bd9Sstevel@tonic-gate volatile struct snoop_handler *hp; 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate /* 9757c478bd9Sstevel@tonic-gate * Invoke any registered alarms. This involves first calculating 9767c478bd9Sstevel@tonic-gate * the time for the next alarm, setting it up, then progressing 9777c478bd9Sstevel@tonic-gate * through handler invocations. Note that since handlers may 9787c478bd9Sstevel@tonic-gate * use siglongjmp(), in the worst case handlers may be serviced 9797c478bd9Sstevel@tonic-gate * at a later time. 9807c478bd9Sstevel@tonic-gate */ 9817c478bd9Sstevel@tonic-gate if (sig == SIGALRM) { 9827c478bd9Sstevel@tonic-gate now = time(NULL); 9837c478bd9Sstevel@tonic-gate /* Calculate next alarm time */ 9847c478bd9Sstevel@tonic-gate for (hp = snoop_hp; hp; hp = hp->s_next) { 9857c478bd9Sstevel@tonic-gate if (hp->s_time) { 9867c478bd9Sstevel@tonic-gate if ((hp->s_time - now) > 0) { 9877c478bd9Sstevel@tonic-gate if (nalarm == 0 || nalarm > hp->s_time) 9887c478bd9Sstevel@tonic-gate nalarm = now < hp->s_time ? 9897c478bd9Sstevel@tonic-gate hp->s_time : now + 1; 9907c478bd9Sstevel@tonic-gate } 9917c478bd9Sstevel@tonic-gate } 9927c478bd9Sstevel@tonic-gate } 9937c478bd9Sstevel@tonic-gate /* Setup next alarm */ 9947c478bd9Sstevel@tonic-gate if (nalarm) { 9957c478bd9Sstevel@tonic-gate snoop_nalarm = nalarm; 99645916cd2Sjpk (void) alarm(nalarm - now); 9977c478bd9Sstevel@tonic-gate } else { 9987c478bd9Sstevel@tonic-gate snoop_nalarm = 0; 9997c478bd9Sstevel@tonic-gate } 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate /* Invoke alarm handlers (may not return) */ 10027c478bd9Sstevel@tonic-gate for (hp = snoop_hp; hp; hp = hp->s_next) { 10037c478bd9Sstevel@tonic-gate if (hp->s_time) { 10047c478bd9Sstevel@tonic-gate if ((now - hp->s_time) >= 0) { 10057c478bd9Sstevel@tonic-gate hp->s_time = 0; /* only invoke once */ 10067c478bd9Sstevel@tonic-gate if (hp->s_handler) 10077c478bd9Sstevel@tonic-gate hp->s_handler(); 10087c478bd9Sstevel@tonic-gate } 10097c478bd9Sstevel@tonic-gate } 10107c478bd9Sstevel@tonic-gate } 10117c478bd9Sstevel@tonic-gate } else { 10127c478bd9Sstevel@tonic-gate snoop_nrecover++; 10137c478bd9Sstevel@tonic-gate } 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate /* 10167c478bd9Sstevel@tonic-gate * Exit if a signal has occurred after snoop has begun the process 10177c478bd9Sstevel@tonic-gate * of quitting. 10187c478bd9Sstevel@tonic-gate */ 10197c478bd9Sstevel@tonic-gate if (quitting) 10207c478bd9Sstevel@tonic-gate exit(1); 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate /* 10237c478bd9Sstevel@tonic-gate * If an alarm handler has timed out, and snoop_nrecover has 10247c478bd9Sstevel@tonic-gate * reached SNOOP_MAXRECOVER, skip to the next packet. 10257c478bd9Sstevel@tonic-gate * 10267c478bd9Sstevel@tonic-gate * If any other signal has occurred, and snoop_nrecover has 10277c478bd9Sstevel@tonic-gate * reached SNOOP_MAXRECOVER, give up. 10287c478bd9Sstevel@tonic-gate */ 10297c478bd9Sstevel@tonic-gate if (sig == SIGALRM) { 10307c478bd9Sstevel@tonic-gate if (ioctl(STDOUT_FILENO, I_CANPUT, 0) == 0) { 10317c478bd9Sstevel@tonic-gate /* 10327c478bd9Sstevel@tonic-gate * We've stalled on output, which is not a critical 10337c478bd9Sstevel@tonic-gate * failure. Reset the recovery counter so we do not 10347c478bd9Sstevel@tonic-gate * consider this a persistent failure, and return so 10357c478bd9Sstevel@tonic-gate * we do not skip this packet. 10367c478bd9Sstevel@tonic-gate */ 10377c478bd9Sstevel@tonic-gate snoop_nrecover = 0; 10387c478bd9Sstevel@tonic-gate return; 10397c478bd9Sstevel@tonic-gate } 10407c478bd9Sstevel@tonic-gate if (snoop_nrecover >= SNOOP_MAXRECOVER) { 104145916cd2Sjpk (void) fprintf(stderr, 10427c478bd9Sstevel@tonic-gate "snoop: WARNING: skipping from packet %d\n", 10437c478bd9Sstevel@tonic-gate count); 10447c478bd9Sstevel@tonic-gate snoop_nrecover = 0; 10457c478bd9Sstevel@tonic-gate } else { 10467c478bd9Sstevel@tonic-gate /* continue trying */ 10477c478bd9Sstevel@tonic-gate return; 10487c478bd9Sstevel@tonic-gate } 10497c478bd9Sstevel@tonic-gate } else if (snoop_nrecover >= SNOOP_MAXRECOVER) { 105045916cd2Sjpk (void) fprintf(stderr, 10517c478bd9Sstevel@tonic-gate "snoop: ERROR: cannot recover from packet %d\n", count); 10527c478bd9Sstevel@tonic-gate exit(1); 10537c478bd9Sstevel@tonic-gate } 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate #ifdef DEBUG 105645916cd2Sjpk (void) fprintf(stderr, "snoop_sigrecover(%d, %p, %p)\n", sig, info, p); 10577c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate /* 10607c478bd9Sstevel@tonic-gate * Prepare to quit. This allows final processing to occur 10617c478bd9Sstevel@tonic-gate * after first terminal interruption. 10627c478bd9Sstevel@tonic-gate */ 10637c478bd9Sstevel@tonic-gate if (sig == SIGTERM || sig == SIGHUP || sig == SIGINT) { 10647c478bd9Sstevel@tonic-gate quitting = 1; 10657c478bd9Sstevel@tonic-gate return; 10667c478bd9Sstevel@tonic-gate } else if (sig != -1 && sig != SIGALRM) { 10677c478bd9Sstevel@tonic-gate /* Inform user that snoop has taken a fault */ 106845916cd2Sjpk (void) fprintf(stderr, 106945916cd2Sjpk "WARNING: received signal %d from packet %d\n", 10707c478bd9Sstevel@tonic-gate sig, count); 10717c478bd9Sstevel@tonic-gate } 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate /* Reset interpreter variables */ 10747c478bd9Sstevel@tonic-gate snoop_recover(); 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate /* Continue in scan() with the next packet */ 10777c478bd9Sstevel@tonic-gate siglongjmp(jmp_env, 1); 10787c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 10797c478bd9Sstevel@tonic-gate } 10807c478bd9Sstevel@tonic-gate 10817c478bd9Sstevel@tonic-gate /* 10827c478bd9Sstevel@tonic-gate * Protected malloc for global error recovery: prepare for interpreter 10837c478bd9Sstevel@tonic-gate * failures with corrupted packets or confused interpreters. Dynamically 10847c478bd9Sstevel@tonic-gate * allocate `nbytes' bytes, and sandwich it between two PROT_NONE pages to 10857c478bd9Sstevel@tonic-gate * catch writes outside of the allocated region. 10867c478bd9Sstevel@tonic-gate */ 10877c478bd9Sstevel@tonic-gate static char * 10887c478bd9Sstevel@tonic-gate protmalloc(size_t nbytes) 10897c478bd9Sstevel@tonic-gate { 10907c478bd9Sstevel@tonic-gate caddr_t start; 10917c478bd9Sstevel@tonic-gate int psz = sysconf(_SC_PAGESIZE); 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate nbytes = P2ROUNDUP(nbytes, psz); 10947c478bd9Sstevel@tonic-gate start = mmap(NULL, nbytes + psz * 2, PROT_READ|PROT_WRITE, 10957c478bd9Sstevel@tonic-gate MAP_PRIVATE|MAP_ANON, -1, 0); 10967c478bd9Sstevel@tonic-gate if (start == MAP_FAILED) { 10977c478bd9Sstevel@tonic-gate perror("Error: protmalloc: mmap"); 10987c478bd9Sstevel@tonic-gate return (NULL); 10997c478bd9Sstevel@tonic-gate } 11007c478bd9Sstevel@tonic-gate assert(IS_P2ALIGNED(start, psz)); 11017c478bd9Sstevel@tonic-gate if (mprotect(start, 1, PROT_NONE) == -1) 11027c478bd9Sstevel@tonic-gate perror("Warning: mprotect"); 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate start += psz; 11057c478bd9Sstevel@tonic-gate if (mprotect(start + nbytes, 1, PROT_NONE) == -1) 11067c478bd9Sstevel@tonic-gate perror("Warning: mprotect"); 11077c478bd9Sstevel@tonic-gate 11087c478bd9Sstevel@tonic-gate return (start); 11097c478bd9Sstevel@tonic-gate } 11107c478bd9Sstevel@tonic-gate 11117c478bd9Sstevel@tonic-gate /* 11127c478bd9Sstevel@tonic-gate * resetperm - reduce security vulnerabilities by resetting 11137c478bd9Sstevel@tonic-gate * owner/group/permissions. Always attempt setuid() - if we have 11147c478bd9Sstevel@tonic-gate * permission to drop our privilege level, do so. 11157c478bd9Sstevel@tonic-gate */ 11167c478bd9Sstevel@tonic-gate void 11177c478bd9Sstevel@tonic-gate resetperm(void) 11187c478bd9Sstevel@tonic-gate { 11197c478bd9Sstevel@tonic-gate if (geteuid() == 0) { 11207c478bd9Sstevel@tonic-gate (void) setgid(GID_NOBODY); 11217c478bd9Sstevel@tonic-gate (void) setuid(UID_NOBODY); 11227c478bd9Sstevel@tonic-gate } 11237c478bd9Sstevel@tonic-gate } 1124