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