1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 * 5 * Copyright (c) 1983, 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgment: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * $FreeBSD: src/sbin/routed/trace.c,v 1.6 2000/08/11 08:24:38 sheldonh Exp $ 37 */ 38 39 #include "defs.h" 40 #include "pathnames.h" 41 #include <signal.h> 42 #include <sys/stat.h> 43 #include <sys/signal.h> 44 #include <strings.h> 45 #include <fcntl.h> 46 #include <protocols/routed.h> 47 48 #define NRECORDS 50 /* size of circular trace buffer */ 49 50 int tracelevel, new_tracelevel; 51 FILE *ftrace = stdout; /* output trace file */ 52 static const char *sigtrace_pat = "%s"; 53 static char savetracename[MAXPATHLEN+1]; 54 static char *ripcmds[RIPCMD_MAX] = 55 {"#0", "REQUEST", "RESPONSE", "TRACEON", "TRACEOFF", "POLL", 56 "POLLENTRY"}; 57 char inittracename[MAXPATHLEN+1]; 58 static boolean_t file_trace; /* 1=tracing to file, not stdout */ 59 60 static void tmsg(const char *, ...); 61 62 const char * 63 rip_strerror(int err) 64 { 65 const char *cp = strerror(err); 66 static char msgbuf[64]; 67 68 if (cp == NULL) { 69 if (err == 0) { 70 cp = "success"; 71 } else { 72 (void) snprintf(msgbuf, sizeof (msgbuf), 73 "unknown error %d", err); 74 cp = msgbuf; 75 } 76 } 77 return (cp); 78 } 79 80 /* convert IP address to a string, but not into a single buffer */ 81 char * 82 naddr_ntoa(in_addr_t a) 83 { 84 #define NUM_BUFS 4 85 static int bufno; 86 static struct { 87 char str[INET_ADDRSTRLEN]; /* xxx.xxx.xxx.xxx\0 */ 88 } bufs[NUM_BUFS]; 89 char *s; 90 struct in_addr addr; 91 92 addr.s_addr = a; 93 s = strcpy(bufs[bufno].str, inet_ntoa(addr)); 94 bufno = (bufno+1) % NUM_BUFS; 95 return (s); 96 #undef NUM_BUFS 97 } 98 99 100 const char * 101 saddr_ntoa(struct sockaddr_storage *ss) 102 { 103 return (ss == NULL) ? "?" : naddr_ntoa(S_ADDR(ss)); 104 } 105 106 107 static char * 108 ts(time_t secs) 109 { 110 static char s[20]; 111 112 secs += epoch.tv_sec; 113 (void) strftime(s, sizeof (s), "%T", localtime(&secs)); 114 return (s); 115 } 116 117 static char * 118 ts_full(struct timeval *tv) 119 { 120 static char s[32]; 121 time_t secs; 122 int len; 123 124 secs = tv->tv_sec + epoch.tv_sec; 125 (void) strftime(s, sizeof (s), "%Y/%m/%d %T", localtime(&secs)); 126 len = strlen(s); 127 (void) snprintf(s + len, sizeof (s) - len, ".%06ld", tv->tv_usec); 128 return (s); 129 } 130 131 /* 132 * On each event, display a time stamp. 133 * This assumes that 'now' is update once for each event, and 134 * that at least now.tv_usec changes. 135 */ 136 static struct timeval lastlog_time; 137 138 void 139 lastlog(void) 140 { 141 if (lastlog_time.tv_sec != now.tv_sec || 142 lastlog_time.tv_usec != now.tv_usec) { 143 (void) fprintf(ftrace, "-- %s --\n", ts_full(&now)); 144 lastlog_time = now; 145 } 146 } 147 148 149 static void 150 tmsg(const char *p, ...) 151 { 152 va_list args; 153 154 if (ftrace != NULL) { 155 lastlog(); 156 va_start(args, p); 157 (void) vfprintf(ftrace, p, args); 158 (void) fputc('\n', ftrace); 159 (void) fflush(ftrace); 160 (void) va_end(args); 161 } 162 } 163 164 165 void 166 trace_close(int zap_stdio) 167 { 168 int fd; 169 170 171 (void) fflush(stdout); 172 (void) fflush(stderr); 173 174 if (ftrace != NULL && zap_stdio) { 175 if (ftrace != stdout) 176 (void) fclose(ftrace); 177 ftrace = NULL; 178 fd = open("/dev/null", O_RDWR); 179 if (isatty(STDIN_FILENO)) 180 (void) dup2(fd, STDIN_FILENO); 181 if (isatty(STDOUT_FILENO)) 182 (void) dup2(fd, STDOUT_FILENO); 183 if (isatty(STDERR_FILENO)) 184 (void) dup2(fd, STDERR_FILENO); 185 (void) close(fd); 186 } 187 lastlog_time.tv_sec = 0; 188 } 189 190 191 void 192 trace_flush(void) 193 { 194 if (ftrace != NULL) { 195 (void) fflush(ftrace); 196 if (ferror(ftrace)) 197 trace_off("tracing off: %s", 198 rip_strerror(ferror(ftrace))); 199 } 200 } 201 202 203 void 204 trace_off(const char *p, ...) 205 { 206 va_list args; 207 208 209 if (ftrace != NULL) { 210 lastlog(); 211 va_start(args, p); 212 (void) vfprintf(ftrace, p, args); 213 (void) fputc('\n', ftrace); 214 (void) va_end(args); 215 } 216 trace_close(file_trace); 217 218 new_tracelevel = tracelevel = 0; 219 } 220 221 222 /* log a change in tracing */ 223 void 224 tracelevel_msg(const char *pat, 225 int dump) /* -1=no dump, 0=default, 1=force */ 226 { 227 static const char *off_msgs[MAX_TRACELEVEL] = { 228 "Tracing actions stopped", 229 "Tracing packets stopped", 230 "Tracing packet contents stopped", 231 "Tracing kernel changes stopped", 232 "Tracing routing socket messages stopped", 233 }; 234 static const char *on_msgs[MAX_TRACELEVEL] = { 235 "Tracing actions started", 236 "Tracing packets started", 237 "Tracing packet contents started", 238 "Tracing kernel changes started", 239 "Tracing routing socket messages started", 240 }; 241 uint_t old_tracelevel = tracelevel; 242 243 244 if (new_tracelevel < 0) 245 new_tracelevel = 0; 246 else if (new_tracelevel > MAX_TRACELEVEL) 247 new_tracelevel = MAX_TRACELEVEL; 248 249 if (new_tracelevel < tracelevel) { 250 if (new_tracelevel <= 0) { 251 trace_off(pat, off_msgs[0]); 252 } else { 253 do { 254 tmsg(pat, off_msgs[tracelevel]); 255 } while (--tracelevel != new_tracelevel); 256 } 257 258 } else if (new_tracelevel > tracelevel) { 259 do { 260 tmsg(pat, on_msgs[tracelevel++]); 261 } while (tracelevel != new_tracelevel); 262 } 263 264 if (dump > 0 || 265 (dump == 0 && old_tracelevel == 0 && tracelevel != 0)) 266 trace_dump(); 267 } 268 269 void 270 set_tracefile(const char *filename, 271 const char *pat, 272 int dump) /* -1=no dump, 0=default, 1=force */ 273 { 274 struct stat stbuf; 275 struct stat stbuf2; 276 FILE *n_ftrace; 277 const char *fn; 278 int nfd; 279 boolean_t allow_create; 280 281 /* 282 * main() calls this routine with "dump == -1". All others 283 * call it with 0, so we take dump == -1 to mean "can create 284 * the file." 285 */ 286 allow_create = (dump == -1); 287 288 /* 289 * Allow a null filename to increase the level if the trace file 290 * is already open or if coming from a trusted source, such as 291 * a signal or the command line. 292 */ 293 if (filename == NULL || filename[0] == '\0') { 294 filename = NULL; 295 if (ftrace == NULL) { 296 if (inittracename[0] == '\0') { 297 msglog("missing trace file name"); 298 return; 299 } 300 fn = inittracename; 301 } else { 302 goto set_tracelevel; 303 } 304 305 } else if (strcmp(filename, "dump/../table") == 0) { 306 trace_dump(); 307 return; 308 309 } else { 310 /* 311 * Allow the file specified with "-T file" to be reopened, 312 * but require all other names specified over the net to 313 * match the official path. The path can specify a directory 314 * in which the file is to be created. 315 */ 316 317 if (strcmp(filename, inittracename) != 0) { 318 if (strncmp(filename, PATH_TRACE, 319 sizeof (PATH_TRACE)-1) != 0 || 320 (strstr(filename, "../") != NULL)) { 321 msglog("wrong trace file \"%s\"", filename); 322 return; 323 } 324 if (stat(PATH_TRACE, &stbuf) == -1) { 325 fn = PATH_TRACE; 326 goto missing_file; 327 } 328 if (filename[sizeof (PATH_TRACE) - 1] != '\0' && 329 (filename[sizeof (PATH_TRACE) - 1] != '/' || 330 !S_ISDIR(stbuf.st_mode))) { 331 goto bad_file_type; 332 } 333 if (S_ISDIR(stbuf.st_mode)) 334 allow_create = _B_TRUE; 335 } 336 337 fn = filename; 338 } 339 /* fn cannot be null here */ 340 341 /* If the new tracefile exists, it must be a regular file. */ 342 if (lstat(fn, &stbuf) == -1) { 343 if (!allow_create) 344 goto missing_file; 345 nfd = open(fn, O_CREAT|O_EXCL|O_WRONLY, 0644); 346 if (nfd != -1 && fstat(nfd, &stbuf) == -1) { 347 (void) close(nfd); 348 goto missing_file; 349 } 350 } else if (S_ISREG(stbuf.st_mode)) { 351 nfd = open(fn, O_APPEND|O_WRONLY, 0644); 352 } else { 353 goto bad_file_type; 354 } 355 356 if (nfd == -1 || (n_ftrace = fdopen(nfd, "a")) == NULL) { 357 msglog("failed to open trace file \"%s\" %s", fn, 358 rip_strerror(errno)); 359 if (fn == inittracename) 360 inittracename[0] = '\0'; 361 if (nfd != -1) 362 (void) close(nfd); 363 return; 364 } 365 366 if (fstat(nfd, &stbuf2) == -1 || !S_ISREG(stbuf2.st_mode) || 367 stbuf2.st_dev != stbuf.st_dev || stbuf2.st_ino != stbuf.st_ino) { 368 msglog("trace file \"%s\" moved", fn); 369 (void) fclose(n_ftrace); 370 return; 371 } 372 373 tmsg("switch to trace file %s", fn); 374 trace_close(file_trace = _B_TRUE); 375 (void) dup2(nfd, STDOUT_FILENO); 376 (void) dup2(nfd, STDERR_FILENO); 377 378 if (fn != savetracename) 379 (void) strlcpy(savetracename, fn, sizeof (savetracename) - 1); 380 ftrace = n_ftrace; 381 382 set_tracelevel: 383 if (new_tracelevel == 0 || filename == NULL) 384 new_tracelevel++; 385 tracelevel_msg(pat, dump != 0 ? dump : (filename != NULL)); 386 return; 387 388 missing_file: 389 msglog("trace \"%s\" missing", fn); 390 return; 391 392 bad_file_type: 393 msglog("wrong type (%#x) of trace file \"%s\"", stbuf.st_mode, fn); 394 } 395 396 397 /* ARGSUSED */ 398 void 399 sigtrace_more(int s) 400 { 401 new_tracelevel++; 402 sigtrace_pat = "SIGUSR1: %s"; 403 if (signal(s, sigtrace_more) == SIG_ERR) 404 msglog("signal: %s", rip_strerror(errno)); 405 } 406 407 408 /* ARGSUSED */ 409 void 410 sigtrace_less(int s) 411 { 412 new_tracelevel--; 413 sigtrace_pat = "SIGUSR2: %s"; 414 if (signal(s, sigtrace_less) == SIG_ERR) 415 msglog("signal: %s", rip_strerror(errno)); 416 } 417 418 /* ARGSUSED */ 419 void 420 sigtrace_dump(int s) 421 { 422 trace_dump(); 423 if (signal(s, sigtrace_dump) == SIG_ERR) 424 msglog("signal: %s", rip_strerror(errno)); 425 } 426 427 /* Set tracing after a signal. */ 428 void 429 set_tracelevel(void) 430 { 431 if (new_tracelevel == tracelevel) 432 return; 433 434 /* 435 * If tracing entirely off, and there was no tracefile specified 436 * on the command line, then leave it off. 437 */ 438 if (new_tracelevel > tracelevel && ftrace == NULL) { 439 if (savetracename[0] != '\0') { 440 set_tracefile(savetracename, sigtrace_pat, 0); 441 } else if (inittracename[0] != '\0') { 442 set_tracefile(inittracename, sigtrace_pat, 0); 443 } else { 444 new_tracelevel = 0; 445 return; 446 } 447 } else { 448 tracelevel_msg(sigtrace_pat, 0); 449 } 450 } 451 452 453 /* display an address */ 454 char * 455 addrname(in_addr_t addr, /* in network byte order */ 456 in_addr_t mask, 457 int force) /* 0=show mask if nonstandard, */ 458 { /* 1=always show mask, 2=never */ 459 #define NUM_BUFS 4 460 static int bufno; 461 static struct { 462 /* 463 * this array can hold either of the following strings terminated 464 * by a null character: 465 * "xxx.xxx.xxx.xxx/xx" 466 * "xxx.xxx.xxx.xxx (mask xxx.xxx.xxx.xxx)" 467 * 468 */ 469 char str[2*INET_ADDRSTRLEN + sizeof (" (mask )")]; 470 } bufs[NUM_BUFS]; 471 char *s, *sp; 472 in_addr_t dmask; 473 int i, len; 474 struct in_addr tmp_addr; 475 476 tmp_addr.s_addr = addr; 477 len = strlcpy(bufs[bufno].str, inet_ntoa(tmp_addr), 478 sizeof (bufs[bufno].str)); 479 s = bufs[bufno].str; 480 bufno = (bufno+1) % NUM_BUFS; 481 482 if (force == 1 || (force == 0 && mask != std_mask(addr))) { 483 sp = &s[strlen(s)]; 484 485 dmask = mask & -mask; 486 if (mask + dmask == 0) { 487 i = ffs(mask); 488 (void) snprintf(sp, 489 (sizeof (bufs[bufno].str) - len), "/%d", 490 (NBBY * sizeof (in_addr_t) + 1) - i); 491 492 } else { 493 (void) snprintf(sp, 494 (sizeof (bufs[bufno].str) - len), " (mask %s)", 495 naddr_ntoa(htonl(mask))); 496 } 497 } 498 499 return (s); 500 #undef NUM_BUFS 501 } 502 503 504 /* display a bit-field */ 505 struct or_bits { 506 uint8_t origin; 507 const char *origin_name; 508 }; 509 510 static struct or_bits origin_bits[] = { 511 { RO_RIP, "RIP" }, 512 { RO_RDISC, "RDISC" }, 513 { RO_STATIC, "STATIC" }, 514 { RO_LOOPBCK, "LOOPBCK" }, 515 { RO_PTOPT, "PTOPT" }, 516 { RO_NET_SYN, "NET_SYN" }, 517 { RO_IF, "IF" }, 518 { RO_FILE, "FILE" }, 519 { RO_NONE, " " }, 520 { 0, NULL} 521 }; 522 523 /* display a bit-field */ 524 struct bits { 525 uint64_t bits_mask; 526 uint64_t bits_clear; 527 const char *bits_name; 528 }; 529 530 static struct bits if_bits[] = { 531 { IFF_BROADCAST, 0, "BROADCAST" }, 532 { IFF_DEBUG, 0, "DEBUG" }, 533 { IFF_LOOPBACK, 0, "LOOPBACK" }, 534 { IFF_POINTOPOINT, 0, "POINTOPOINT" }, 535 { IFF_NOTRAILERS, 0, "NOTRAILERS" }, 536 { IFF_RUNNING, 0, "RUNNING" }, 537 { IFF_NOARP, 0, "NOARP" }, 538 { IFF_PROMISC, 0, "PROMISC" }, 539 { IFF_ALLMULTI, 0, "ALLMULTI" }, 540 { IFF_INTELLIGENT, 0, "INTELLIGENT" }, 541 { IFF_MULTICAST, 0, "MULTICAST" }, 542 { IFF_MULTI_BCAST, 0, "MULTI_BCAST" }, 543 { IFF_UNNUMBERED, 0, "UNNUMBERED" }, 544 { IFF_DHCPRUNNING, 0, "DHCP" }, 545 { IFF_PRIVATE, 0, "PRIVATE" }, 546 { IFF_NOXMIT, 0, "NOXMIT" }, 547 { IFF_NOLOCAL, 0, "NOLOCAL" }, 548 { IFF_DEPRECATED, 0, "DEPRECATED" }, 549 { IFF_ADDRCONF, 0, "ADDRCONF" }, 550 { IFF_ROUTER, 0, "ROUTER" }, 551 { IFF_NONUD, 0, "NONUD" }, 552 { IFF_ANYCAST, 0, "ANYCAST" }, 553 { IFF_NORTEXCH, 0, "NORTEXCH" }, 554 { IFF_IPV4, 0, "IPv4" }, 555 { IFF_IPV6, 0, "IPv6" }, 556 { IFF_NOFAILOVER, 0, "NOFAILOVER" }, 557 { IFF_FAILED, 0, "FAILED" }, 558 { IFF_STANDBY, 0, "STANDBY" }, 559 { IFF_INACTIVE, 0, "INACTIVE" }, 560 { IFF_OFFLINE, 0, "OFFLINE" }, 561 { IFF_XRESOLV, 0, "XRESOLV" }, 562 { IFF_COS_ENABLED, 0, "CoS" }, 563 { IFF_PREFERRED, 0, "PREFERRED" }, 564 { IFF_TEMPORARY, 0, "TEMPORARY" }, 565 { IFF_FIXEDMTU, 0, "FIXEDMTU" }, 566 { IFF_VIRTUAL, 0, "VIRTUAL"}, 567 { IFF_IPMP, 0, "IPMP"}, 568 { 0, 0, NULL} 569 }; 570 571 static struct bits is_bits[] = { 572 { IS_ALIAS, 0, "ALIAS" }, 573 { IS_SUBNET, 0, "" }, 574 { IS_REMOTE, (IS_NO_RDISC | 575 IS_BCAST_RDISC), "REMOTE" }, 576 { IS_PASSIVE, (IS_NO_RDISC | 577 IS_NO_RIP | 578 IS_NO_SUPER_AG | 579 IS_PM_RDISC | 580 IS_NO_AG), "PASSIVE" }, 581 { IS_EXTERNAL, 0, "EXTERNAL" }, 582 { IS_CHECKED, 0, "" }, 583 { IS_ALL_HOSTS, 0, "" }, 584 { IS_ALL_ROUTERS, 0, "" }, 585 { IS_DISTRUST, 0, "DISTRUST" }, 586 { IS_BROKE, IS_SICK, "BROKEN" }, 587 { IS_SICK, 0, "SICK" }, 588 { IS_DUP, 0, "DUPLICATE" }, 589 { IS_REDIRECT_OK, 0, "REDIRECT_OK" }, 590 { IS_NEED_NET_SYN, 0, "" }, 591 { IS_NO_AG, IS_NO_SUPER_AG, "NO_AG" }, 592 { IS_NO_SUPER_AG, 0, "NO_SUPER_AG" }, 593 { (IS_NO_RIPV1_IN | 594 IS_NO_RIPV2_IN | 595 IS_NO_RIPV1_OUT | 596 IS_NO_RIPV2_OUT), 0, "NO_RIP" }, 597 { (IS_NO_RIPV1_IN | 598 IS_NO_RIPV1_OUT), 0, "RIPV2" }, 599 { IS_NO_RIPV1_IN, 0, "NO_RIPV1_IN" }, 600 { IS_NO_RIPV2_IN, 0, "NO_RIPV2_IN" }, 601 { IS_NO_RIPV1_OUT, 0, "NO_RIPV1_OUT" }, 602 { IS_NO_RIPV2_OUT, 0, "NO_RIPV2_OUT" }, 603 { IS_NO_RIP_MCAST, 0, "NO_RIP_MCAST" }, 604 { (IS_NO_ADV_IN | 605 IS_NO_SOL_OUT | 606 IS_NO_ADV_OUT), IS_BCAST_RDISC, "NO_RDISC" }, 607 { IS_NO_SOL_OUT, 0, "NO_SOLICIT" }, 608 { IS_SOL_OUT, 0, "SEND_SOLICIT" }, 609 { IS_NO_ADV_OUT, IS_BCAST_RDISC, "NO_RDISC_ADV" }, 610 { IS_ADV_OUT, 0, "RDISC_ADV" }, 611 { IS_BCAST_RDISC, 0, "BCAST_RDISC" }, 612 { IS_PM_RDISC, 0, "" }, 613 { IS_NO_HOST, 0, "NO_HOST" }, 614 { IS_SUPPRESS_RDISC, 0, "SUPPRESS_RDISC" }, 615 { IS_FLUSH_RDISC, 0, "FLUSH_RDISC" }, 616 { 0, 0, NULL} 617 }; 618 619 static struct bits rs_bits[] = { 620 { RS_IF, 0, "IF" }, 621 { RS_NET_INT, RS_NET_SYN, "NET_INT" }, 622 { RS_NET_SYN, 0, "NET_SYN" }, 623 { RS_SUBNET, 0, "" }, 624 { RS_LOCAL, 0, "LOCAL" }, 625 { RS_MHOME, 0, "MHOME" }, 626 { RS_STATIC, 0, "STATIC" }, 627 { RS_NOPROPAGATE, 0, "NOPROP" }, 628 { RS_BADIF, 0, "BADIF" }, 629 { 0, 0, NULL} 630 }; 631 632 static struct bits ks_bits[] = { 633 { KS_NEW, 0, "NEW" }, 634 { KS_DELETE, 0, "DELETE" }, 635 { KS_ADD, 0, "ADD" }, 636 { KS_CHANGE, 0, "CHANGE" }, 637 { KS_DEL_ADD, 0, "DEL_ADD" }, 638 { KS_STATIC, 0, "STATIC" }, 639 { KS_GATEWAY, 0, "GATEWAY" }, 640 { KS_DYNAMIC, 0, "DYNAMIC" }, 641 { KS_DELETED, 0, "DELETED" }, 642 { KS_PRIVATE, 0, "PRIVATE" }, 643 { KS_CHECK, 0, "CHECK" }, 644 { KS_IF, 0, "IF" }, 645 { KS_PASSIVE, 0, "PASSIVE" }, 646 { KS_DEPRE_IF, 0, "DEPRE_IF" }, 647 { KS_FILE, 0, "FILE" }, 648 { 0, 0, NULL} 649 }; 650 651 static void 652 trace_bits(const struct bits *tbl, 653 uint64_t field, 654 boolean_t force) 655 { 656 uint64_t b; 657 char c; 658 659 if (force) { 660 (void) putc('<', ftrace); 661 c = '\0'; 662 } else { 663 c = '<'; 664 } 665 666 while (field != 0 && 667 (b = tbl->bits_mask) != 0) { 668 if ((b & field) == b) { 669 if (tbl->bits_name[0] != '\0') { 670 if (c != '\0') 671 (void) putc(c, ftrace); 672 (void) fprintf(ftrace, "%s", tbl->bits_name); 673 c = '|'; 674 } 675 field &= ~(b | tbl->bits_clear); 676 } 677 tbl++; 678 } 679 if (field != 0) { 680 if (c != '\0') 681 (void) putc(c, ftrace); 682 (void) fprintf(ftrace, "%#llx", field); 683 c = '|'; 684 } 685 686 if (c != '<' || force) 687 (void) fputs("> ", ftrace); 688 } 689 690 static char * 691 trace_string(const struct bits *tbl, uint_t field, boolean_t force) 692 { 693 const struct bits *tbp; 694 char *sbuf, *cp, chr; 695 size_t slen; 696 697 /* minimum default string */ 698 slen = sizeof ("<0x12345678>"); 699 for (tbp = tbl; tbp->bits_mask != 0; tbp++) 700 if (tbp->bits_name[0] != '\0') 701 slen += strlen(tbp->bits_name) + 1; 702 if ((sbuf = malloc(slen)) == NULL) 703 return (NULL); 704 cp = sbuf; 705 706 if (force) { 707 *cp++ = '<'; 708 chr = '\0'; 709 } else { 710 chr = '<'; 711 } 712 713 while (field != 0 && tbl->bits_mask != 0) { 714 if ((tbl->bits_mask & field) == tbl->bits_mask) { 715 if (tbl->bits_name[0] != '\0') { 716 if (chr != '\0') 717 *cp++ = chr; 718 (void) strcpy(cp, tbl->bits_name); 719 cp += strlen(tbl->bits_name); 720 chr = '|'; 721 } 722 field &= ~(tbl->bits_mask | tbl->bits_clear); 723 } 724 tbl++; 725 } 726 if (field != 0) { 727 if (chr != '\0') 728 *cp++ = chr; 729 cp += sprintf(cp, "%#x", field); 730 chr = '|'; 731 } 732 733 if (chr != '<' || force) 734 *cp++ = '>'; 735 *cp = '\0'; 736 return (sbuf); 737 } 738 739 char * 740 if_bit_string(uint_t field, boolean_t force) 741 { 742 return (trace_string(if_bits, field, force)); 743 } 744 745 char * 746 rtname(in_addr_t dst, 747 in_addr_t mask, 748 in_addr_t gate) 749 { 750 static char buf[sizeof ("xxx.xxx.xxx.xxx/xx-->xxx.xxx.xxx.xxx")]; 751 int i; 752 753 (void) snprintf(buf, sizeof (buf), "%-16s-->", addrname(dst, mask, 0)); 754 i = strlen(buf); 755 (void) snprintf(&buf[i], (sizeof (buf) -i), "%-*s", 15+24-MAX(24, i), 756 naddr_ntoa(gate)); 757 return (buf); 758 } 759 760 761 static void 762 print_rts(struct rt_spare *rts, 763 int force_metric, /* -1=suppress, 0=default */ 764 int force_ifp, /* -1=suppress, 0=default */ 765 int force_router, /* -1=suppress, 0=default, 1=display */ 766 int force_tag, /* -1=suppress, 0=default, 1=display */ 767 int force_time) /* 0=suppress, 1=display */ 768 { 769 int i; 770 771 if (force_metric >= 0) 772 (void) fprintf(ftrace, "metric=%-2d ", rts->rts_metric); 773 if (force_ifp >= 0) 774 (void) fprintf(ftrace, "%s ", (rts->rts_ifp == 0 ? 775 "if?" : rts->rts_ifp->int_name)); 776 if (force_router > 0 || 777 (force_router == 0 && rts->rts_router != rts->rts_gate)) 778 (void) fprintf(ftrace, "router=%s ", 779 naddr_ntoa(rts->rts_router)); 780 if (force_time > 0) 781 (void) fprintf(ftrace, "%s ", ts(rts->rts_time)); 782 if (force_tag > 0 || 783 (force_tag == 0 && rts->rts_tag != 0)) 784 (void) fprintf(ftrace, "tag=%#x ", ntohs(rts->rts_tag)); 785 if (rts->rts_de_ag != 0) { 786 for (i = 1; (uint_t)(1 << i) <= rts->rts_de_ag; i++) 787 continue; 788 (void) fprintf(ftrace, "de_ag=%d ", i); 789 } 790 (void) fprintf(ftrace, "flags 0x%x ", rts->rts_flags); 791 792 } 793 794 795 static void 796 print_rtsorigin(const struct or_bits *tbl, uint8_t route_origin) 797 { 798 799 uint8_t tblentry; 800 while ((tblentry = tbl->origin) != 0) { 801 if (tblentry == route_origin) { 802 (void) fprintf(ftrace, "origin=%s ", tbl->origin_name); 803 } 804 tbl++; 805 } 806 } 807 808 809 void 810 trace_if(const char *act, struct interface *ifp) 811 { 812 if (!TRACEACTIONS || ftrace == NULL) 813 return; 814 815 lastlog(); 816 (void) fprintf(ftrace, "%-3s interface %-4s #%-3d ", act, 817 ifp->int_name, 818 ifp->int_phys != NULL ? ifp->int_phys->phyi_index : 0); 819 (void) fprintf(ftrace, "%-15s-->%-15s", 820 naddr_ntoa(ifp->int_addr), 821 addrname(((ifp->int_if_flags & IFF_POINTOPOINT) ? 822 ifp->int_dstaddr : htonl(ifp->int_net)), 823 ifp->int_mask, 1)); 824 if (ifp->int_metric != 0) 825 (void) fprintf(ftrace, " metric=%d", ifp->int_metric); 826 if (!IS_RIP_OUT_OFF(ifp->int_state) && 827 ifp->int_d_metric != 0) 828 (void) fprintf(ftrace, " fake_default=%d", ifp->int_d_metric); 829 (void) fputs("\n ", ftrace); 830 trace_bits(if_bits, ifp->int_if_flags, _B_FALSE); 831 trace_bits(is_bits, ifp->int_state, _B_FALSE); 832 (void) fputc('\n', ftrace); 833 } 834 835 void 836 trace_khash(const struct khash *krt) 837 { 838 if (ftrace == NULL) 839 return; 840 841 lastlog(); 842 (void) fprintf(ftrace, " %-15s-->%-15s metric=%d ", 843 addrname(krt->k_dst, krt->k_mask, 0), 844 naddr_ntoa(krt->k_gate), krt->k_metric); 845 if (krt->k_ifp != NULL) 846 (void) fprintf(ftrace, "ifp %s ", krt->k_ifp->int_name); 847 else 848 (void) fprintf(ftrace, "ifp NULL "); 849 (void) fprintf(ftrace, "%s ", ts(krt->k_keep)); 850 (void) fprintf(ftrace, "%s ", ts(krt->k_redirect_time)); 851 trace_bits(ks_bits, krt->k_state, _B_TRUE); 852 (void) fputc('\n', ftrace); 853 } 854 855 void 856 trace_dr(const struct dr *drp) 857 { 858 if (ftrace == NULL) 859 return; 860 861 lastlog(); 862 (void) fprintf(ftrace, " %-4s %-15s %s ", 863 drp->dr_ifp != NULL ? drp->dr_ifp->int_name : "?", 864 naddr_ntoa(drp->dr_gate), ts(drp->dr_ts)); 865 (void) fprintf(ftrace, "%s %d %u\n", ts(drp->dr_life), 866 SIGN_PREF(drp->dr_recv_pref), drp->dr_pref); 867 } 868 869 void 870 trace_upslot(struct rt_entry *rt, 871 struct rt_spare *rts, 872 struct rt_spare *new) 873 { 874 if (!TRACEACTIONS || ftrace == NULL) 875 return; 876 877 if (rts->rts_gate == new->rts_gate && 878 rts->rts_router == new->rts_router && 879 rts->rts_metric == new->rts_metric && 880 rts->rts_tag == new->rts_tag && 881 rts->rts_de_ag == new->rts_de_ag) 882 return; 883 884 lastlog(); 885 if (new->rts_gate == 0) { 886 (void) fprintf(ftrace, "Del #%d %-35s ", 887 (int)(rts - rt->rt_spares), 888 rtname(rt->rt_dst, rt->rt_mask, rts->rts_gate)); 889 print_rts(rts, 0, 0, 0, 0, 890 (rts != rt->rt_spares || 891 AGE_RT(rt->rt_state, rts->rts_origin, new->rts_ifp))); 892 893 } else if (rts->rts_gate != RIP_DEFAULT) { 894 (void) fprintf(ftrace, "Chg #%d %-35s ", 895 (int)(rts - rt->rt_spares), 896 rtname(rt->rt_dst, rt->rt_mask, rts->rts_gate)); 897 print_rts(rts, 0, 0, 898 rts->rts_gate != new->rts_gate, 899 rts->rts_tag != new->rts_tag, 900 rts != rt->rt_spares || 901 AGE_RT(rt->rt_state, rts->rts_origin, rt->rt_ifp)); 902 903 (void) fprintf(ftrace, "\n %19s%-16s ", "", 904 (new->rts_gate != rts->rts_gate ? 905 naddr_ntoa(new->rts_gate) : "")); 906 print_rts(new, 907 ((new->rts_metric == rts->rts_metric) ? -1 : 0), 908 ((new->rts_ifp == rts->rts_ifp) ? -1 : 0), 909 0, 910 rts->rts_tag != new->rts_tag, 911 (new->rts_time != rts->rts_time && 912 (rts != rt->rt_spares || 913 AGE_RT(rt->rt_state, new->rts_origin, new->rts_ifp)))); 914 915 } else { 916 (void) fprintf(ftrace, "Add #%d %-35s ", 917 (int)(rts - rt->rt_spares), 918 rtname(rt->rt_dst, rt->rt_mask, new->rts_gate)); 919 print_rts(new, 0, 0, 0, 0, 920 (rts != rt->rt_spares || 921 AGE_RT(rt->rt_state, new->rts_origin, new->rts_ifp))); 922 } 923 (void) fputc('\n', ftrace); 924 } 925 926 927 /* miscellaneous message checked by the caller */ 928 void 929 trace_misc(const char *p, ...) 930 { 931 va_list args; 932 933 if (ftrace == NULL) 934 return; 935 936 lastlog(); 937 va_start(args, p); 938 (void) vfprintf(ftrace, p, args); 939 (void) fputc('\n', ftrace); 940 (void) va_end(args); 941 } 942 943 944 /* display a message if tracing actions */ 945 void 946 trace_act(const char *p, ...) 947 { 948 va_list args; 949 950 if (!TRACEACTIONS || ftrace == NULL) 951 return; 952 953 lastlog(); 954 va_start(args, p); 955 (void) vfprintf(ftrace, p, args); 956 (void) fputc('\n', ftrace); 957 (void) va_end(args); 958 } 959 960 961 /* display a message if tracing packets */ 962 void 963 trace_pkt(const char *p, ...) 964 { 965 va_list args; 966 967 if (!TRACEPACKETS || ftrace == NULL) 968 return; 969 970 lastlog(); 971 va_start(args, p); 972 (void) vfprintf(ftrace, p, args); 973 (void) fputc('\n', ftrace); 974 (void) va_end(args); 975 } 976 977 978 void 979 trace_change(struct rt_entry *rt, 980 uint16_t state, 981 struct rt_spare *new, 982 const char *label) 983 { 984 if (ftrace == NULL) 985 return; 986 987 if (rt->rt_metric == new->rts_metric && 988 rt->rt_gate == new->rts_gate && 989 rt->rt_router == new->rts_router && 990 rt->rt_state == state && 991 rt->rt_tag == new->rts_tag && 992 rt->rt_de_ag == new->rts_de_ag) 993 return; 994 995 lastlog(); 996 (void) fprintf(ftrace, "%s %-35s ", 997 label, 998 rtname(rt->rt_dst, rt->rt_mask, rt->rt_gate)); 999 print_rts(rt->rt_spares, 1000 0, 0, 0, 0, AGE_RT(rt->rt_state, rt->rt_spares->rts_origin, 1001 rt->rt_ifp)); 1002 print_rtsorigin(origin_bits, rt->rt_spares->rts_origin); 1003 trace_bits(rs_bits, rt->rt_state, rt->rt_state != state); 1004 1005 (void) fprintf(ftrace, "\n%*s %19s%-16s ", 1006 strlen(label), "", "", 1007 (rt->rt_gate != new->rts_gate ? 1008 naddr_ntoa(new->rts_gate) : "")); 1009 print_rts(new, 1010 ((new->rts_metric == rt->rt_metric) ? -1 : 0), 1011 ((new->rts_ifp == rt->rt_ifp) ? -1 : 0), 1012 0, 1013 rt->rt_tag != new->rts_tag, 1014 (rt->rt_time != new->rts_time && 1015 AGE_RT(rt->rt_state, new->rts_origin, new->rts_ifp))); 1016 if (rt->rt_state != state) { 1017 print_rtsorigin(origin_bits, new->rts_origin); 1018 trace_bits(rs_bits, state, _B_TRUE); 1019 } 1020 (void) fputc('\n', ftrace); 1021 } 1022 1023 1024 void 1025 trace_add_del(const char *action, struct rt_entry *rt) 1026 { 1027 if (ftrace == NULL) 1028 return; 1029 1030 lastlog(); 1031 (void) fprintf(ftrace, "%s %-35s ", 1032 action, 1033 rtname(rt->rt_dst, rt->rt_mask, rt->rt_gate)); 1034 print_rts(rt->rt_spares, 0, 0, 0, 0, AGE_RT(rt->rt_state, 1035 rt->rt_spares->rts_origin, rt->rt_ifp)); 1036 print_rtsorigin(origin_bits, rt->rt_spares->rts_origin); 1037 trace_bits(rs_bits, rt->rt_state, _B_FALSE); 1038 (void) fputc('\n', ftrace); 1039 } 1040 1041 1042 /* ARGSUSED */ 1043 static int 1044 walk_trace(struct radix_node *rn, 1045 void *w) 1046 { 1047 #define RT ((struct rt_entry *)rn) 1048 struct rt_spare *rts; 1049 int i; 1050 1051 (void) fprintf(ftrace, " %-35s ", 1052 rtname(RT->rt_dst, RT->rt_mask, RT->rt_gate)); 1053 print_rts(&RT->rt_spares[0], 0, 0, 0, 0, 1054 AGE_RT(RT->rt_state, RT->rt_spares[0].rts_origin, RT->rt_ifp)); 1055 print_rtsorigin(origin_bits, RT->rt_spares[0].rts_origin); 1056 trace_bits(rs_bits, RT->rt_state, _B_FALSE); 1057 if (RT->rt_poison_time >= now_garbage && 1058 RT->rt_poison_metric < RT->rt_metric) 1059 (void) fprintf(ftrace, "pm=%d@%s", 1060 RT->rt_poison_metric, ts(RT->rt_poison_time)); 1061 (void) fprintf(ftrace, "%d spare slots", RT->rt_num_spares); 1062 1063 rts = &RT->rt_spares[1]; 1064 for (i = 1; i < RT->rt_num_spares; i++, rts++) { 1065 if (rts->rts_gate != RIP_DEFAULT) { 1066 (void) fprintf(ftrace, "\n #%d%15s%-16s ", 1067 i, "", naddr_ntoa(rts->rts_gate)); 1068 print_rts(rts, 0, 0, 0, 0, 1); 1069 print_rtsorigin(origin_bits, rts->rts_origin); 1070 } 1071 } 1072 (void) fputc('\n', ftrace); 1073 1074 return (0); 1075 } 1076 1077 1078 void 1079 trace_dump(void) 1080 { 1081 struct interface *ifp; 1082 1083 if (ftrace == NULL) 1084 return; 1085 lastlog(); 1086 1087 /* 1088 * Warning: the rtquery.trace.* family of STC tests depend on 1089 * the log file format here. If you need to change this next 1090 * message, make sure that you change the TRACE_DUMP variable 1091 * as well. 1092 */ 1093 (void) fputs("current daemon state:\n", ftrace); 1094 for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) 1095 trace_if("", ifp); 1096 (void) fputs("Routes:\n", ftrace); 1097 (void) rn_walktree(rhead, walk_trace, NULL); 1098 (void) fputs("Kernel routes:\n", ftrace); 1099 kern_dump(); 1100 (void) fputs("Discovered routers:\n", ftrace); 1101 rdisc_dump(); 1102 } 1103 1104 1105 void 1106 trace_rip(const char *dir1, const char *dir2, 1107 struct sockaddr_in *who, 1108 struct interface *ifp, 1109 struct rip *msg, 1110 int size) /* total size of message */ 1111 { 1112 struct netinfo *n, *lim; 1113 #define NA ((struct netauth *)n) 1114 int i, seen_route; 1115 struct in_addr tmp_mask; 1116 1117 if (!TRACEPACKETS || ftrace == NULL) 1118 return; 1119 1120 lastlog(); 1121 if (msg->rip_cmd >= RIPCMD_MAX || msg->rip_vers == 0) { 1122 (void) fprintf(ftrace, "%s bad RIPv%d cmd=%d %s" 1123 " %s.%d size=%d\n", 1124 dir1, msg->rip_vers, msg->rip_cmd, dir2, 1125 naddr_ntoa(who->sin_addr.s_addr), 1126 ntohs(who->sin_port), 1127 size); 1128 return; 1129 } 1130 1131 (void) fprintf(ftrace, "%s RIPv%d %s %s %s.%d%s%s\n", 1132 dir1, msg->rip_vers, ripcmds[msg->rip_cmd], dir2, 1133 naddr_ntoa(who->sin_addr.s_addr), ntohs(who->sin_port), 1134 ifp ? " via " : "", ifp ? ifp->int_name : ""); 1135 if (!TRACECONTENTS) 1136 return; 1137 1138 seen_route = 0; 1139 switch (msg->rip_cmd) { 1140 case RIPCMD_REQUEST: 1141 case RIPCMD_RESPONSE: 1142 1143 n = msg->rip_nets; 1144 tmp_mask.s_addr = n->n_mask; 1145 lim = n + (size - 4) / sizeof (struct netinfo); 1146 for (; n < lim; n++) { 1147 if (!seen_route && 1148 n->n_family == RIP_AF_UNSPEC && 1149 ntohl(n->n_metric) == HOPCNT_INFINITY && 1150 msg->rip_cmd == RIPCMD_REQUEST && 1151 (n+1 == lim || 1152 (n+2 == lim && 1153 (n+1)->n_family == RIP_AF_AUTH))) { 1154 (void) fputs("\tQUERY ", ftrace); 1155 if (n->n_dst != 0) 1156 (void) fprintf(ftrace, "%s ", 1157 naddr_ntoa(n->n_dst)); 1158 if (n->n_mask != 0) 1159 (void) fprintf(ftrace, "mask=%s ", 1160 inet_ntoa(tmp_mask)); 1161 if (n->n_nhop != 0) 1162 (void) fprintf(ftrace, "nhop=%s ", 1163 naddr_ntoa(n->n_nhop)); 1164 if (n->n_tag != 0) 1165 (void) fprintf(ftrace, "tag=%#x ", 1166 ntohs(n->n_tag)); 1167 (void) fputc('\n', ftrace); 1168 continue; 1169 } 1170 1171 if (n->n_family == RIP_AF_AUTH) { 1172 if (NA->a_type == RIP_AUTH_PW && 1173 n == msg->rip_nets) { 1174 (void) fprintf(ftrace, "\tPassword" 1175 " Authentication: \"%s\"\n", 1176 qstring(NA->au.au_pw, 1177 RIP_AUTH_PW_LEN)); 1178 continue; 1179 } 1180 1181 if (NA->a_type == RIP_AUTH_MD5 && 1182 n == msg->rip_nets) { 1183 (void) fprintf(ftrace, 1184 "\tMD5 Auth" 1185 " pkt_len=%d KeyID=%u" 1186 " auth_len=%d" 1187 " seqno=%#x" 1188 " rsvd=%#hx,%#hx\n", 1189 ntohs(NA->au.a_md5.md5_pkt_len), 1190 NA->au.a_md5.md5_keyid, 1191 NA->au.a_md5.md5_auth_len, 1192 ntohl(NA->au.a_md5.md5_seqno), 1193 ntohs(NA->au.a_md5.rsvd[0]), 1194 ntohs(NA->au.a_md5.rsvd[1])); 1195 continue; 1196 } 1197 (void) fprintf(ftrace, 1198 "\tAuthentication type %d: ", 1199 ntohs(NA->a_type)); 1200 for (i = 0; i < (int)sizeof (NA->au.au_pw); 1201 i++) 1202 (void) fprintf(ftrace, "%02x ", 1203 NA->au.au_pw[i]); 1204 (void) fputc('\n', ftrace); 1205 continue; 1206 } 1207 1208 seen_route = 1; 1209 if (n->n_family != RIP_AF_INET) { 1210 (void) fprintf(ftrace, 1211 "\t(af %d) %-18s mask=%s ", 1212 ntohs(n->n_family), 1213 naddr_ntoa(n->n_dst), 1214 inet_ntoa(tmp_mask)); 1215 } else if (msg->rip_vers == RIPv1) { 1216 (void) fprintf(ftrace, "\t%-18s ", 1217 addrname(n->n_dst, ntohl(n->n_mask), 1218 n->n_mask == 0 ? 2 : 1)); 1219 } else { 1220 (void) fprintf(ftrace, "\t%-18s ", 1221 addrname(n->n_dst, ntohl(n->n_mask), 1222 n->n_mask == 0 ? 2 : 0)); 1223 } 1224 (void) fprintf(ftrace, "metric=%-2lu ", 1225 (unsigned long)ntohl(n->n_metric)); 1226 if (n->n_nhop != 0) 1227 (void) fprintf(ftrace, " nhop=%s ", 1228 naddr_ntoa(n->n_nhop)); 1229 if (n->n_tag != 0) 1230 (void) fprintf(ftrace, "tag=%#x", 1231 ntohs(n->n_tag)); 1232 (void) fputc('\n', ftrace); 1233 } 1234 if (size != (char *)n - (char *)msg) 1235 (void) fprintf(ftrace, "truncated record, len %d\n", 1236 size); 1237 break; 1238 1239 case RIPCMD_TRACEON: 1240 (void) fprintf(ftrace, "\tfile=\"%.*s\"\n", size - 4, 1241 msg->rip_tracefile); 1242 break; 1243 1244 case RIPCMD_TRACEOFF: 1245 break; 1246 } 1247 } 1248