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