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