1 /* 2 * Copyright 2005 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_MIPRUNNING, 0, "MIP" }, 559 { IFF_NOFAILOVER, 0, "NOFAILOVER" }, 560 { IFF_FAILED, 0, "FAILED" }, 561 { IFF_STANDBY, 0, "STANDBY" }, 562 { IFF_INACTIVE, 0, "INACTIVE" }, 563 { IFF_OFFLINE, 0, "OFFLINE" }, 564 { IFF_XRESOLV, 0, "XRESOLV" }, 565 { IFF_COS_ENABLED, 0, "CoS" }, 566 { IFF_PREFERRED, 0, "PREFERRED" }, 567 { IFF_TEMPORARY, 0, "TEMPORARY" }, 568 { IFF_FIXEDMTU, 0, "FIXEDMTU" }, 569 { IFF_VIRTUAL, 0, "VIRTUAL"}, 570 { 0, 0, NULL} 571 }; 572 573 static struct bits is_bits[] = { 574 { IS_ALIAS, 0, "ALIAS" }, 575 { IS_SUBNET, 0, "" }, 576 { IS_REMOTE, (IS_NO_RDISC | 577 IS_BCAST_RDISC), "REMOTE" }, 578 { IS_PASSIVE, (IS_NO_RDISC | 579 IS_NO_RIP | 580 IS_NO_SUPER_AG | 581 IS_PM_RDISC | 582 IS_NO_AG), "PASSIVE" }, 583 { IS_EXTERNAL, 0, "EXTERNAL" }, 584 { IS_CHECKED, 0, "" }, 585 { IS_ALL_HOSTS, 0, "" }, 586 { IS_ALL_ROUTERS, 0, "" }, 587 { IS_DISTRUST, 0, "DISTRUST" }, 588 { IS_BROKE, IS_SICK, "BROKEN" }, 589 { IS_SICK, 0, "SICK" }, 590 { IS_DUP, 0, "DUPLICATE" }, 591 { IS_REDIRECT_OK, 0, "REDIRECT_OK" }, 592 { IS_NEED_NET_SYN, 0, "" }, 593 { IS_NO_AG, IS_NO_SUPER_AG, "NO_AG" }, 594 { IS_NO_SUPER_AG, 0, "NO_SUPER_AG" }, 595 { (IS_NO_RIPV1_IN | 596 IS_NO_RIPV2_IN | 597 IS_NO_RIPV1_OUT | 598 IS_NO_RIPV2_OUT), 0, "NO_RIP" }, 599 { (IS_NO_RIPV1_IN | 600 IS_NO_RIPV1_OUT), 0, "RIPV2" }, 601 { IS_NO_RIPV1_IN, 0, "NO_RIPV1_IN" }, 602 { IS_NO_RIPV2_IN, 0, "NO_RIPV2_IN" }, 603 { IS_NO_RIPV1_OUT, 0, "NO_RIPV1_OUT" }, 604 { IS_NO_RIPV2_OUT, 0, "NO_RIPV2_OUT" }, 605 { IS_NO_RIP_MCAST, 0, "NO_RIP_MCAST" }, 606 { (IS_NO_ADV_IN | 607 IS_NO_SOL_OUT | 608 IS_NO_ADV_OUT), IS_BCAST_RDISC, "NO_RDISC" }, 609 { IS_NO_SOL_OUT, 0, "NO_SOLICIT" }, 610 { IS_SOL_OUT, 0, "SEND_SOLICIT" }, 611 { IS_NO_ADV_OUT, IS_BCAST_RDISC, "NO_RDISC_ADV" }, 612 { IS_ADV_OUT, 0, "RDISC_ADV" }, 613 { IS_BCAST_RDISC, 0, "BCAST_RDISC" }, 614 { IS_PM_RDISC, 0, "" }, 615 { IS_NO_HOST, 0, "NO_HOST" }, 616 { IS_SUPPRESS_RDISC, 0, "SUPPRESS_RDISC" }, 617 { IS_FLUSH_RDISC, 0, "FLUSH_RDISC" }, 618 { 0, 0, NULL} 619 }; 620 621 static struct bits rs_bits[] = { 622 { RS_IF, 0, "IF" }, 623 { RS_NET_INT, RS_NET_SYN, "NET_INT" }, 624 { RS_NET_SYN, 0, "NET_SYN" }, 625 { RS_SUBNET, 0, "" }, 626 { RS_LOCAL, 0, "LOCAL" }, 627 { RS_MHOME, 0, "MHOME" }, 628 { RS_STATIC, 0, "STATIC" }, 629 { RS_NOPROPAGATE, 0, "NOPROP" }, 630 { RS_BADIF, 0, "BADIF" }, 631 { 0, 0, NULL} 632 }; 633 634 static struct bits ks_bits[] = { 635 { KS_NEW, 0, "NEW" }, 636 { KS_DELETE, 0, "DELETE" }, 637 { KS_ADD, 0, "ADD" }, 638 { KS_CHANGE, 0, "CHANGE" }, 639 { KS_DEL_ADD, 0, "DEL_ADD" }, 640 { KS_STATIC, 0, "STATIC" }, 641 { KS_GATEWAY, 0, "GATEWAY" }, 642 { KS_DYNAMIC, 0, "DYNAMIC" }, 643 { KS_DELETED, 0, "DELETED" }, 644 { KS_PRIVATE, 0, "PRIVATE" }, 645 { KS_CHECK, 0, "CHECK" }, 646 { KS_IF, 0, "IF" }, 647 { KS_PASSIVE, 0, "PASSIVE" }, 648 { KS_DEPRE_IF, 0, "DEPRE_IF" }, 649 { KS_FILE, 0, "FILE" }, 650 { 0, 0, NULL} 651 }; 652 653 static void 654 trace_bits(const struct bits *tbl, 655 uint64_t field, 656 boolean_t force) 657 { 658 uint64_t b; 659 char c; 660 661 if (force) { 662 (void) putc('<', ftrace); 663 c = '\0'; 664 } else { 665 c = '<'; 666 } 667 668 while (field != 0 && 669 (b = tbl->bits_mask) != 0) { 670 if ((b & field) == b) { 671 if (tbl->bits_name[0] != '\0') { 672 if (c != '\0') 673 (void) putc(c, ftrace); 674 (void) fprintf(ftrace, "%s", tbl->bits_name); 675 c = '|'; 676 } 677 field &= ~(b | tbl->bits_clear); 678 } 679 tbl++; 680 } 681 if (field != 0) { 682 if (c != '\0') 683 (void) putc(c, ftrace); 684 (void) fprintf(ftrace, "%#llx", field); 685 c = '|'; 686 } 687 688 if (c != '<' || force) 689 (void) fputs("> ", ftrace); 690 } 691 692 static char * 693 trace_string(const struct bits *tbl, uint_t field, boolean_t force) 694 { 695 const struct bits *tbp; 696 char *sbuf, *cp, chr; 697 size_t slen; 698 699 /* minimum default string */ 700 slen = sizeof ("<0x12345678>"); 701 for (tbp = tbl; tbp->bits_mask != 0; tbp++) 702 if (tbp->bits_name[0] != '\0') 703 slen += strlen(tbp->bits_name) + 1; 704 if ((sbuf = malloc(slen)) == NULL) 705 return (NULL); 706 cp = sbuf; 707 708 if (force) { 709 *cp++ = '<'; 710 chr = '\0'; 711 } else { 712 chr = '<'; 713 } 714 715 while (field != 0 && tbl->bits_mask != 0) { 716 if ((tbl->bits_mask & field) == tbl->bits_mask) { 717 if (tbl->bits_name[0] != '\0') { 718 if (chr != '\0') 719 *cp++ = chr; 720 (void) strcpy(cp, tbl->bits_name); 721 cp += strlen(tbl->bits_name); 722 chr = '|'; 723 } 724 field &= ~(tbl->bits_mask | tbl->bits_clear); 725 } 726 tbl++; 727 } 728 if (field != 0) { 729 if (chr != '\0') 730 *cp++ = chr; 731 cp += sprintf(cp, "%#x", field); 732 chr = '|'; 733 } 734 735 if (chr != '<' || force) 736 *cp++ = '>'; 737 *cp = '\0'; 738 return (sbuf); 739 } 740 741 char * 742 if_bit_string(uint_t field, boolean_t force) 743 { 744 return (trace_string(if_bits, field, force)); 745 } 746 747 char * 748 rtname(in_addr_t dst, 749 in_addr_t mask, 750 in_addr_t gate) 751 { 752 static char buf[sizeof ("xxx.xxx.xxx.xxx/xx-->xxx.xxx.xxx.xxx")]; 753 int i; 754 755 (void) snprintf(buf, sizeof (buf), "%-16s-->", addrname(dst, mask, 0)); 756 i = strlen(buf); 757 (void) snprintf(&buf[i], (sizeof (buf) -i), "%-*s", 15+24-MAX(24, i), 758 naddr_ntoa(gate)); 759 return (buf); 760 } 761 762 763 static void 764 print_rts(struct rt_spare *rts, 765 int force_metric, /* -1=suppress, 0=default */ 766 int force_ifp, /* -1=suppress, 0=default */ 767 int force_router, /* -1=suppress, 0=default, 1=display */ 768 int force_tag, /* -1=suppress, 0=default, 1=display */ 769 int force_time) /* 0=suppress, 1=display */ 770 { 771 int i; 772 773 if (force_metric >= 0) 774 (void) fprintf(ftrace, "metric=%-2d ", rts->rts_metric); 775 if (force_ifp >= 0) 776 (void) fprintf(ftrace, "%s ", (rts->rts_ifp == 0 ? 777 "if?" : rts->rts_ifp->int_name)); 778 if (force_router > 0 || 779 (force_router == 0 && rts->rts_router != rts->rts_gate)) 780 (void) fprintf(ftrace, "router=%s ", 781 naddr_ntoa(rts->rts_router)); 782 if (force_time > 0) 783 (void) fprintf(ftrace, "%s ", ts(rts->rts_time)); 784 if (force_tag > 0 || 785 (force_tag == 0 && rts->rts_tag != 0)) 786 (void) fprintf(ftrace, "tag=%#x ", ntohs(rts->rts_tag)); 787 if (rts->rts_de_ag != 0) { 788 for (i = 1; (uint_t)(1 << i) <= rts->rts_de_ag; i++) 789 continue; 790 (void) fprintf(ftrace, "de_ag=%d ", i); 791 } 792 (void) fprintf(ftrace, "flags 0x%x ", rts->rts_flags); 793 794 } 795 796 797 static void 798 print_rtsorigin(const struct or_bits *tbl, uint8_t route_origin) 799 { 800 801 uint8_t tblentry; 802 while ((tblentry = tbl->origin) != 0) { 803 if (tblentry == route_origin) { 804 (void) fprintf(ftrace, "origin=%s ", tbl->origin_name); 805 } 806 tbl++; 807 } 808 } 809 810 811 void 812 trace_if(const char *act, struct interface *ifp) 813 { 814 if (!TRACEACTIONS || ftrace == NULL) 815 return; 816 817 lastlog(); 818 (void) fprintf(ftrace, "%-3s interface %-4s #%-3d ", act, 819 ifp->int_name, 820 ifp->int_phys != NULL ? ifp->int_phys->phyi_index : 0); 821 (void) fprintf(ftrace, "%-15s-->%-15s", 822 naddr_ntoa(ifp->int_addr), 823 addrname(((ifp->int_if_flags & IFF_POINTOPOINT) ? 824 ifp->int_dstaddr : htonl(ifp->int_net)), 825 ifp->int_mask, 1)); 826 if (ifp->int_metric != 0) 827 (void) fprintf(ftrace, " metric=%d", ifp->int_metric); 828 if (!IS_RIP_OUT_OFF(ifp->int_state) && 829 ifp->int_d_metric != 0) 830 (void) fprintf(ftrace, " fake_default=%d", ifp->int_d_metric); 831 (void) fputs("\n ", ftrace); 832 trace_bits(if_bits, ifp->int_if_flags, _B_FALSE); 833 trace_bits(is_bits, ifp->int_state, _B_FALSE); 834 (void) fputc('\n', ftrace); 835 } 836 837 void 838 trace_khash(const struct khash *krt) 839 { 840 if (ftrace == NULL) 841 return; 842 843 lastlog(); 844 (void) fprintf(ftrace, " %-15s-->%-15s metric=%d ", 845 addrname(krt->k_dst, krt->k_mask, 0), 846 naddr_ntoa(krt->k_gate), krt->k_metric); 847 if (krt->k_ifp != NULL) 848 (void) fprintf(ftrace, "ifp %s ", krt->k_ifp->int_name); 849 else 850 (void) fprintf(ftrace, "ifp NULL "); 851 (void) fprintf(ftrace, "%s ", ts(krt->k_keep)); 852 (void) fprintf(ftrace, "%s ", ts(krt->k_redirect_time)); 853 trace_bits(ks_bits, krt->k_state, _B_TRUE); 854 (void) fputc('\n', ftrace); 855 } 856 857 void 858 trace_dr(const struct dr *drp) 859 { 860 if (ftrace == NULL) 861 return; 862 863 lastlog(); 864 (void) fprintf(ftrace, " %-4s %-15s %s ", 865 drp->dr_ifp != NULL ? drp->dr_ifp->int_name : "?", 866 naddr_ntoa(drp->dr_gate), ts(drp->dr_ts)); 867 (void) fprintf(ftrace, "%s %d %u\n", ts(drp->dr_life), 868 SIGN_PREF(drp->dr_recv_pref), drp->dr_pref); 869 } 870 871 void 872 trace_upslot(struct rt_entry *rt, 873 struct rt_spare *rts, 874 struct rt_spare *new) 875 { 876 if (!TRACEACTIONS || ftrace == NULL) 877 return; 878 879 if (rts->rts_gate == new->rts_gate && 880 rts->rts_router == new->rts_router && 881 rts->rts_metric == new->rts_metric && 882 rts->rts_tag == new->rts_tag && 883 rts->rts_de_ag == new->rts_de_ag) 884 return; 885 886 lastlog(); 887 if (new->rts_gate == 0) { 888 (void) fprintf(ftrace, "Del #%d %-35s ", 889 (int)(rts - rt->rt_spares), 890 rtname(rt->rt_dst, rt->rt_mask, rts->rts_gate)); 891 print_rts(rts, 0, 0, 0, 0, 892 (rts != rt->rt_spares || 893 AGE_RT(rt->rt_state, rts->rts_origin, new->rts_ifp))); 894 895 } else if (rts->rts_gate != RIP_DEFAULT) { 896 (void) fprintf(ftrace, "Chg #%d %-35s ", 897 (int)(rts - rt->rt_spares), 898 rtname(rt->rt_dst, rt->rt_mask, rts->rts_gate)); 899 print_rts(rts, 0, 0, 900 rts->rts_gate != new->rts_gate, 901 rts->rts_tag != new->rts_tag, 902 rts != rt->rt_spares || AGE_RT(rt->rt_state, 903 rts->rts_origin, rt->rt_ifp)); 904 905 (void) fprintf(ftrace, "\n %19s%-16s ", "", 906 (new->rts_gate != rts->rts_gate ? 907 naddr_ntoa(new->rts_gate) : "")); 908 print_rts(new, 909 ((new->rts_metric == rts->rts_metric) ? -1 : 0), 910 ((new->rts_ifp == rts->rts_ifp) ? -1 : 0), 911 0, 912 rts->rts_tag != new->rts_tag, 913 (new->rts_time != rts->rts_time && 914 (rts != rt->rt_spares || 915 AGE_RT(rt->rt_state, new->rts_origin, new->rts_ifp)))); 916 917 } else { 918 (void) fprintf(ftrace, "Add #%d %-35s ", 919 (int)(rts - rt->rt_spares), 920 rtname(rt->rt_dst, rt->rt_mask, new->rts_gate)); 921 print_rts(new, 0, 0, 0, 0, 922 (rts != rt->rt_spares || 923 AGE_RT(rt->rt_state, new->rts_origin, new->rts_ifp))); 924 } 925 (void) fputc('\n', ftrace); 926 } 927 928 929 /* miscellaneous message checked by the caller */ 930 void 931 trace_misc(const char *p, ...) 932 { 933 va_list args; 934 935 if (ftrace == NULL) 936 return; 937 938 lastlog(); 939 va_start(args, p); 940 (void) vfprintf(ftrace, p, args); 941 (void) fputc('\n', ftrace); 942 (void) va_end(args); 943 } 944 945 946 /* display a message if tracing actions */ 947 void 948 trace_act(const char *p, ...) 949 { 950 va_list args; 951 952 if (!TRACEACTIONS || ftrace == NULL) 953 return; 954 955 lastlog(); 956 va_start(args, p); 957 (void) vfprintf(ftrace, p, args); 958 (void) fputc('\n', ftrace); 959 (void) va_end(args); 960 } 961 962 963 /* display a message if tracing packets */ 964 void 965 trace_pkt(const char *p, ...) 966 { 967 va_list args; 968 969 if (!TRACEPACKETS || ftrace == NULL) 970 return; 971 972 lastlog(); 973 va_start(args, p); 974 (void) vfprintf(ftrace, p, args); 975 (void) fputc('\n', ftrace); 976 (void) va_end(args); 977 } 978 979 980 void 981 trace_change(struct rt_entry *rt, 982 uint16_t state, 983 struct rt_spare *new, 984 const char *label) 985 { 986 if (ftrace == NULL) 987 return; 988 989 if (rt->rt_metric == new->rts_metric && 990 rt->rt_gate == new->rts_gate && 991 rt->rt_router == new->rts_router && 992 rt->rt_state == state && 993 rt->rt_tag == new->rts_tag && 994 rt->rt_de_ag == new->rts_de_ag) 995 return; 996 997 lastlog(); 998 (void) fprintf(ftrace, "%s %-35s ", 999 label, 1000 rtname(rt->rt_dst, rt->rt_mask, rt->rt_gate)); 1001 print_rts(rt->rt_spares, 1002 0, 0, 0, 0, AGE_RT(rt->rt_state, rt->rt_spares->rts_origin, 1003 rt->rt_ifp)); 1004 print_rtsorigin(origin_bits, rt->rt_spares->rts_origin); 1005 trace_bits(rs_bits, rt->rt_state, rt->rt_state != state); 1006 1007 (void) fprintf(ftrace, "\n%*s %19s%-16s ", 1008 strlen(label), "", "", 1009 (rt->rt_gate != new->rts_gate ? 1010 naddr_ntoa(new->rts_gate) : "")); 1011 print_rts(new, 1012 ((new->rts_metric == rt->rt_metric) ? -1 : 0), 1013 ((new->rts_ifp == rt->rt_ifp) ? -1 : 0), 1014 0, 1015 rt->rt_tag != new->rts_tag, 1016 (rt->rt_time != new->rts_time && 1017 AGE_RT(rt->rt_state, new->rts_origin, new->rts_ifp))); 1018 if (rt->rt_state != state) { 1019 print_rtsorigin(origin_bits, new->rts_origin); 1020 trace_bits(rs_bits, state, _B_TRUE); 1021 } 1022 (void) fputc('\n', ftrace); 1023 } 1024 1025 1026 void 1027 trace_add_del(const char *action, struct rt_entry *rt) 1028 { 1029 if (ftrace == NULL) 1030 return; 1031 1032 lastlog(); 1033 (void) fprintf(ftrace, "%s %-35s ", 1034 action, 1035 rtname(rt->rt_dst, rt->rt_mask, rt->rt_gate)); 1036 print_rts(rt->rt_spares, 0, 0, 0, 0, AGE_RT(rt->rt_state, 1037 rt->rt_spares->rts_origin, rt->rt_ifp)); 1038 print_rtsorigin(origin_bits, rt->rt_spares->rts_origin); 1039 trace_bits(rs_bits, rt->rt_state, _B_FALSE); 1040 (void) fputc('\n', ftrace); 1041 } 1042 1043 1044 /* ARGSUSED */ 1045 static int 1046 walk_trace(struct radix_node *rn, 1047 void *w) 1048 { 1049 #define RT ((struct rt_entry *)rn) 1050 struct rt_spare *rts; 1051 int i; 1052 1053 (void) fprintf(ftrace, " %-35s ", 1054 rtname(RT->rt_dst, RT->rt_mask, RT->rt_gate)); 1055 print_rts(&RT->rt_spares[0], 0, 0, 0, 0, 1056 AGE_RT(RT->rt_state, RT->rt_spares[0].rts_origin, RT->rt_ifp)); 1057 print_rtsorigin(origin_bits, RT->rt_spares[0].rts_origin); 1058 trace_bits(rs_bits, RT->rt_state, _B_FALSE); 1059 if (RT->rt_poison_time >= now_garbage && 1060 RT->rt_poison_metric < RT->rt_metric) 1061 (void) fprintf(ftrace, "pm=%d@%s", 1062 RT->rt_poison_metric, ts(RT->rt_poison_time)); 1063 (void) fprintf(ftrace, "%d spare slots", RT->rt_num_spares); 1064 1065 rts = &RT->rt_spares[1]; 1066 for (i = 1; i < RT->rt_num_spares; i++, rts++) { 1067 if (rts->rts_gate != RIP_DEFAULT) { 1068 (void) fprintf(ftrace, "\n #%d%15s%-16s ", 1069 i, "", naddr_ntoa(rts->rts_gate)); 1070 print_rts(rts, 0, 0, 0, 0, 1); 1071 print_rtsorigin(origin_bits, rts->rts_origin); 1072 } 1073 } 1074 (void) fputc('\n', ftrace); 1075 1076 return (0); 1077 } 1078 1079 1080 void 1081 trace_dump(void) 1082 { 1083 struct interface *ifp; 1084 1085 if (ftrace == NULL) 1086 return; 1087 lastlog(); 1088 1089 /* 1090 * Warning: the rtquery.trace.* family of STC tests depend on 1091 * the log file format here. If you need to change this next 1092 * message, make sure that you change the TRACE_DUMP variable 1093 * as well. 1094 */ 1095 (void) fputs("current daemon state:\n", ftrace); 1096 for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) 1097 trace_if("", ifp); 1098 (void) fputs("Routes:\n", ftrace); 1099 (void) rn_walktree(rhead, walk_trace, NULL); 1100 (void) fputs("Kernel routes:\n", ftrace); 1101 kern_dump(); 1102 (void) fputs("Discovered routers:\n", ftrace); 1103 rdisc_dump(); 1104 } 1105 1106 1107 void 1108 trace_rip(const char *dir1, const char *dir2, 1109 struct sockaddr_in *who, 1110 struct interface *ifp, 1111 struct rip *msg, 1112 int size) /* total size of message */ 1113 { 1114 struct netinfo *n, *lim; 1115 #define NA ((struct netauth *)n) 1116 int i, seen_route; 1117 struct in_addr tmp_mask; 1118 1119 if (!TRACEPACKETS || ftrace == NULL) 1120 return; 1121 1122 lastlog(); 1123 if (msg->rip_cmd >= RIPCMD_MAX || msg->rip_vers == 0) { 1124 (void) fprintf(ftrace, "%s bad RIPv%d cmd=%d %s" 1125 " %s.%d size=%d\n", 1126 dir1, msg->rip_vers, msg->rip_cmd, dir2, 1127 naddr_ntoa(who->sin_addr.s_addr), 1128 ntohs(who->sin_port), 1129 size); 1130 return; 1131 } 1132 1133 (void) fprintf(ftrace, "%s RIPv%d %s %s %s.%d%s%s\n", 1134 dir1, msg->rip_vers, ripcmds[msg->rip_cmd], dir2, 1135 naddr_ntoa(who->sin_addr.s_addr), ntohs(who->sin_port), 1136 ifp ? " via " : "", ifp ? ifp->int_name : ""); 1137 if (!TRACECONTENTS) 1138 return; 1139 1140 seen_route = 0; 1141 switch (msg->rip_cmd) { 1142 case RIPCMD_REQUEST: 1143 case RIPCMD_RESPONSE: 1144 1145 n = msg->rip_nets; 1146 tmp_mask.s_addr = n->n_mask; 1147 lim = n + (size - 4) / sizeof (struct netinfo); 1148 for (; n < lim; n++) { 1149 if (!seen_route && 1150 n->n_family == RIP_AF_UNSPEC && 1151 ntohl(n->n_metric) == HOPCNT_INFINITY && 1152 msg->rip_cmd == RIPCMD_REQUEST && 1153 (n+1 == lim || 1154 (n+2 == lim && 1155 (n+1)->n_family == RIP_AF_AUTH))) { 1156 (void) fputs("\tQUERY ", ftrace); 1157 if (n->n_dst != 0) 1158 (void) fprintf(ftrace, "%s ", 1159 naddr_ntoa(n->n_dst)); 1160 if (n->n_mask != 0) 1161 (void) fprintf(ftrace, "mask=%s ", 1162 inet_ntoa(tmp_mask)); 1163 if (n->n_nhop != 0) 1164 (void) fprintf(ftrace, "nhop=%s ", 1165 naddr_ntoa(n->n_nhop)); 1166 if (n->n_tag != 0) 1167 (void) fprintf(ftrace, "tag=%#x ", 1168 ntohs(n->n_tag)); 1169 (void) fputc('\n', ftrace); 1170 continue; 1171 } 1172 1173 if (n->n_family == RIP_AF_AUTH) { 1174 if (NA->a_type == RIP_AUTH_PW && 1175 n == msg->rip_nets) { 1176 (void) fprintf(ftrace, "\tPassword" 1177 " Authentication:" 1178 " \"%s\"\n", 1179 qstring(NA->au.au_pw, 1180 RIP_AUTH_PW_LEN)); 1181 continue; 1182 } 1183 1184 if (NA->a_type == RIP_AUTH_MD5 && 1185 n == msg->rip_nets) { 1186 (void) fprintf(ftrace, 1187 "\tMD5 Auth" 1188 " pkt_len=%d KeyID=%u" 1189 " auth_len=%d" 1190 " seqno=%#lx" 1191 " rsvd=%#x,%#x\n", 1192 ntohs(NA->au.a_md5.md5_pkt_len), 1193 NA->au.a_md5.md5_keyid, 1194 NA->au.a_md5.md5_auth_len, 1195 (unsigned long)ntohl(NA->au.a_md5. 1196 md5_seqno), 1197 ntohs(NA->au.a_md5.rsvd[0]), 1198 ntohs(NA->au.a_md5.rsvd[1])); 1199 continue; 1200 } 1201 (void) fprintf(ftrace, 1202 "\tAuthentication type %d: ", 1203 ntohs(NA->a_type)); 1204 for (i = 0; i < (int)sizeof (NA->au.au_pw); 1205 i++) 1206 (void) fprintf(ftrace, "%02x ", 1207 NA->au.au_pw[i]); 1208 (void) fputc('\n', ftrace); 1209 continue; 1210 } 1211 1212 seen_route = 1; 1213 if (n->n_family != RIP_AF_INET) { 1214 (void) fprintf(ftrace, 1215 "\t(af %d) %-18s mask=%s ", 1216 ntohs(n->n_family), 1217 naddr_ntoa(n->n_dst), 1218 inet_ntoa(tmp_mask)); 1219 } else if (msg->rip_vers == RIPv1) { 1220 (void) fprintf(ftrace, "\t%-18s ", 1221 addrname(n->n_dst, 1222 ntohl(n->n_mask), 1223 n->n_mask == 0 ? 2 : 1)); 1224 } else { 1225 (void) fprintf(ftrace, "\t%-18s ", 1226 addrname(n->n_dst, 1227 ntohl(n->n_mask), 1228 n->n_mask == 0 ? 2 : 0)); 1229 } 1230 (void) fprintf(ftrace, "metric=%-2lu ", 1231 (unsigned long)ntohl(n->n_metric)); 1232 if (n->n_nhop != 0) 1233 (void) fprintf(ftrace, " nhop=%s ", 1234 naddr_ntoa(n->n_nhop)); 1235 if (n->n_tag != 0) 1236 (void) fprintf(ftrace, "tag=%#x", 1237 ntohs(n->n_tag)); 1238 (void) fputc('\n', ftrace); 1239 } 1240 if (size != (char *)n - (char *)msg) 1241 (void) fprintf(ftrace, "truncated record, len %d\n", 1242 size); 1243 break; 1244 1245 case RIPCMD_TRACEON: 1246 (void) fprintf(ftrace, "\tfile=\"%.*s\"\n", size-4, 1247 msg->rip_tracefile); 1248 break; 1249 1250 case RIPCMD_TRACEOFF: 1251 break; 1252 } 1253 } 1254