1 /* 2 * Copyright (c) 1983, 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * @(#)trace.c 8.1 (Berkeley) 6/5/93 30 * $FreeBSD: src/sbin/routed/trace.c,v 1.5.2.1 2002/11/07 17:19:13 imp Exp $ 31 */ 32 33 #define RIPCMDS 34 #include "defs.h" 35 #include "pathnames.h" 36 #include <sys/stat.h> 37 #include <sys/signal.h> 38 #include <fcntl.h> 39 40 #define NRECORDS 50 /* size of circular trace buffer */ 41 42 int tracelevel, new_tracelevel; 43 FILE *ftrace; /* output trace file */ 44 static const char *sigtrace_pat = "%s"; 45 static char savetracename[MAXPATHLEN+1]; 46 char inittracename[MAXPATHLEN+1]; 47 int file_trace; /* 1=tracing to file, not stdout */ 48 49 static void trace_dump(void); 50 static void tmsg(const char *, ...) __printflike(1, 2); 51 52 53 /* convert string to printable characters 54 */ 55 static char * 56 qstring(u_char *s, int len) 57 { 58 static char buf[8*20+1]; 59 char *p; 60 u_char *s2, c; 61 62 63 for (p = buf; len != 0 && p < &buf[sizeof(buf)-1]; len--) { 64 c = *s++; 65 if (c == '\0') { 66 for (s2 = s+1; s2 < &s[len]; s2++) { 67 if (*s2 != '\0') 68 break; 69 } 70 if (s2 >= &s[len]) 71 goto exit; 72 } 73 74 if (c >= ' ' && c < 0x7f && c != '\\') { 75 *p++ = c; 76 continue; 77 } 78 *p++ = '\\'; 79 switch (c) { 80 case '\\': 81 *p++ = '\\'; 82 break; 83 case '\n': 84 *p++= 'n'; 85 break; 86 case '\r': 87 *p++= 'r'; 88 break; 89 case '\t': 90 *p++ = 't'; 91 break; 92 case '\b': 93 *p++ = 'b'; 94 break; 95 default: 96 p += sprintf(p,"%o",c); 97 break; 98 } 99 } 100 exit: 101 *p = '\0'; 102 return buf; 103 } 104 105 106 /* convert IP address to a string, but not into a single buffer 107 */ 108 char * 109 naddr_ntoa(naddr a) 110 { 111 #define NUM_BUFS 4 112 static int bufno; 113 static struct { 114 char str[16]; /* xxx.xxx.xxx.xxx\0 */ 115 } bufs[NUM_BUFS]; 116 char *s; 117 struct in_addr addr; 118 119 addr.s_addr = a; 120 s = strcpy(bufs[bufno].str, inet_ntoa(addr)); 121 bufno = (bufno+1) % NUM_BUFS; 122 return s; 123 #undef NUM_BUFS 124 } 125 126 127 const char * 128 saddr_ntoa(struct sockaddr *sa) 129 { 130 return (sa == NULL) ? "?" : naddr_ntoa(S_ADDR(sa)); 131 } 132 133 134 static char * 135 ts(time_t secs) { 136 static char s[20]; 137 138 secs += epoch.tv_sec; 139 memcpy(s, ctime(&secs)+11, 8); 140 s[8] = '\0'; 141 return s; 142 } 143 144 145 /* On each event, display a time stamp. 146 * This assumes that 'now' is update once for each event, and 147 * that at least now.tv_usec changes. 148 */ 149 static struct timeval lastlog_time; 150 151 void 152 lastlog(void) 153 { 154 if (lastlog_time.tv_sec != now.tv_sec 155 || lastlog_time.tv_usec != now.tv_usec) { 156 fprintf(ftrace, "-- %s --\n", ts(now.tv_sec)); 157 lastlog_time = now; 158 } 159 } 160 161 162 static void 163 tmsg(const char *p, ...) 164 { 165 va_list args; 166 167 if (ftrace != NULL) { 168 lastlog(); 169 va_start(args, p); 170 vfprintf(ftrace, p, args); 171 fputc('\n',ftrace); 172 fflush(ftrace); 173 } 174 } 175 176 177 void 178 trace_close(int zap_stdio) 179 { 180 int fd; 181 182 183 fflush(stdout); 184 fflush(stderr); 185 186 if (ftrace != NULL && zap_stdio) { 187 if (ftrace != stdout) 188 fclose(ftrace); 189 ftrace = NULL; 190 fd = open(_PATH_DEVNULL, O_RDWR); 191 if (isatty(STDIN_FILENO)) 192 dup2(fd, STDIN_FILENO); 193 if (isatty(STDOUT_FILENO)) 194 dup2(fd, STDOUT_FILENO); 195 if (isatty(STDERR_FILENO)) 196 dup2(fd, STDERR_FILENO); 197 close(fd); 198 } 199 lastlog_time.tv_sec = 0; 200 } 201 202 203 void 204 trace_flush(void) 205 { 206 if (ftrace != NULL) { 207 fflush(ftrace); 208 if (ferror(ftrace)) 209 trace_off("tracing off: %s", strerror(ferror(ftrace))); 210 } 211 } 212 213 214 void 215 trace_off(const char *p, ...) 216 { 217 va_list args; 218 219 220 if (ftrace != NULL) { 221 lastlog(); 222 va_start(args, p); 223 vfprintf(ftrace, p, args); 224 fputc('\n',ftrace); 225 } 226 trace_close(file_trace); 227 228 new_tracelevel = tracelevel = 0; 229 } 230 231 232 /* log a change in tracing 233 */ 234 void 235 tracelevel_msg(const char *pat, 236 int dump) /* -1=no dump, 0=default, 1=force */ 237 { 238 static const char *off_msgs[MAX_TRACELEVEL] = { 239 "Tracing actions stopped", 240 "Tracing packets stopped", 241 "Tracing packet contents stopped", 242 "Tracing kernel changes stopped", 243 }; 244 static const char *on_msgs[MAX_TRACELEVEL] = { 245 "Tracing actions started", 246 "Tracing packets started", 247 "Tracing packet contents started", 248 "Tracing kernel changes started", 249 }; 250 u_int old_tracelevel = tracelevel; 251 252 253 if (new_tracelevel < 0) 254 new_tracelevel = 0; 255 else if (new_tracelevel > MAX_TRACELEVEL) 256 new_tracelevel = MAX_TRACELEVEL; 257 258 if (new_tracelevel < tracelevel) { 259 if (new_tracelevel <= 0) { 260 trace_off(pat, off_msgs[0]); 261 } else do { 262 tmsg(pat, off_msgs[tracelevel]); 263 } 264 while (--tracelevel != new_tracelevel); 265 266 } else if (new_tracelevel > tracelevel) { 267 do { 268 tmsg(pat, on_msgs[tracelevel++]); 269 } while (tracelevel != new_tracelevel); 270 } 271 272 if (dump > 0 273 || (dump == 0 && old_tracelevel == 0 && tracelevel != 0)) 274 trace_dump(); 275 } 276 277 278 void 279 set_tracefile(const char *filename, 280 const char *pat, 281 int dump) /* -1=no dump, 0=default, 1=force */ 282 { 283 struct stat stbuf; 284 FILE *n_ftrace; 285 const char *fn; 286 287 288 /* Allow a null filename to increase the level if the trace file 289 * is already open or if coming from a trusted source, such as 290 * a signal or the command line. 291 */ 292 if (filename == NULL || filename[0] == '\0') { 293 filename = NULL; 294 if (ftrace == NULL) { 295 if (inittracename[0] == '\0') { 296 msglog("missing trace file name"); 297 return; 298 } 299 fn = inittracename; 300 } else { 301 fn = NULL; 302 } 303 304 } else if (!strcmp(filename,"dump/../table")) { 305 trace_dump(); 306 return; 307 308 } else { 309 /* Allow the file specified with "-T file" to be reopened, 310 * but require all other names specified over the net to 311 * match the official path. The path can specify a directory 312 * in which the file is to be created. 313 */ 314 if (strcmp(filename, inittracename) 315 #ifdef _PATH_TRACE 316 && (strncmp(filename, _PATH_TRACE, sizeof(_PATH_TRACE)-1) 317 || strstr(filename,"../") 318 || 0 > stat(_PATH_TRACE, &stbuf)) 319 #endif 320 ) { 321 msglog("wrong trace file \"%s\"", filename); 322 return; 323 } 324 325 /* If the new tracefile exists, it must be a regular file. 326 */ 327 if (stat(filename, &stbuf) >= 0 && !S_ISREG(stbuf.st_mode)) { 328 msglog("wrong type (%#x) of trace file \"%s\"", 329 stbuf.st_mode, filename); 330 return; 331 } 332 333 fn = filename; 334 } 335 336 if (fn != NULL) { 337 n_ftrace = fopen(fn, "a"); 338 if (n_ftrace == NULL) { 339 msglog("failed to open trace file \"%s\" %s", 340 fn, strerror(errno)); 341 if (fn == inittracename) 342 inittracename[0] = '\0'; 343 return; 344 } 345 346 tmsg("switch to trace file %s", fn); 347 348 trace_close(file_trace = 1); 349 350 if (fn != savetracename) 351 strncpy(savetracename, fn, sizeof(savetracename)-1); 352 ftrace = n_ftrace; 353 354 fflush(stdout); 355 fflush(stderr); 356 dup2(fileno(ftrace), STDOUT_FILENO); 357 dup2(fileno(ftrace), STDERR_FILENO); 358 } 359 360 if (new_tracelevel == 0 || filename == NULL) 361 new_tracelevel++; 362 tracelevel_msg(pat, dump != 0 ? dump : (filename != NULL)); 363 } 364 365 366 /* ARGSUSED */ 367 void 368 sigtrace_on(__unused int s) 369 { 370 new_tracelevel++; 371 sigtrace_pat = "SIGUSR1: %s"; 372 } 373 374 375 /* ARGSUSED */ 376 void 377 sigtrace_off(__unused int s) 378 { 379 new_tracelevel--; 380 sigtrace_pat = "SIGUSR2: %s"; 381 } 382 383 384 /* Set tracing after a signal. 385 */ 386 void 387 set_tracelevel(void) 388 { 389 if (new_tracelevel == tracelevel) 390 return; 391 392 /* If tracing entirely off, and there was no tracefile specified 393 * on the command line, then leave it off. 394 */ 395 if (new_tracelevel > tracelevel && ftrace == NULL) { 396 if (savetracename[0] != '\0') { 397 set_tracefile(savetracename,sigtrace_pat,0); 398 } else if (inittracename[0] != '\0') { 399 set_tracefile(inittracename,sigtrace_pat,0); 400 } else { 401 new_tracelevel = 0; 402 return; 403 } 404 } else { 405 tracelevel_msg(sigtrace_pat, 0); 406 } 407 } 408 409 410 /* display an address 411 */ 412 char * 413 addrname(naddr addr, /* in network byte order */ 414 naddr mask, 415 int force) /* 0=show mask if nonstandard, */ 416 { /* 1=always show mask, 2=never */ 417 #define NUM_BUFS 4 418 static int bufno; 419 static struct { 420 char str[15+20]; 421 } bufs[NUM_BUFS]; 422 char *s, *sp; 423 naddr dmask; 424 int i; 425 426 s = strcpy(bufs[bufno].str, naddr_ntoa(addr)); 427 bufno = (bufno+1) % NUM_BUFS; 428 429 if (force == 1 || (force == 0 && mask != std_mask(addr))) { 430 sp = &s[strlen(s)]; 431 432 dmask = mask & -mask; 433 if (mask + dmask == 0) { 434 for (i = 0; i != 32 && ((1<<i) & mask) == 0; i++) 435 continue; 436 sprintf(sp, "/%d", 32-i); 437 438 } else { 439 sprintf(sp, " (mask %#x)", (u_int)mask); 440 } 441 } 442 443 return s; 444 #undef NUM_BUFS 445 } 446 447 448 /* display a bit-field 449 */ 450 struct bits { 451 u_int bits_mask; 452 u_int bits_clear; 453 const char *bits_name; 454 }; 455 456 static struct bits if_bits[] = { 457 { IFF_LOOPBACK, 0, "LOOPBACK" }, 458 { IFF_POINTOPOINT, 0, "PT-TO-PT" }, 459 { 0, 0, 0} 460 }; 461 462 static struct bits is_bits[] = { 463 { IS_ALIAS, 0, "ALIAS" }, 464 { IS_SUBNET, 0, "" }, 465 { IS_REMOTE, (IS_NO_RDISC 466 | IS_BCAST_RDISC), "REMOTE" }, 467 { IS_PASSIVE, (IS_NO_RDISC 468 | IS_NO_RIP 469 | IS_NO_SUPER_AG 470 | IS_PM_RDISC 471 | IS_NO_AG), "PASSIVE" }, 472 { IS_EXTERNAL, 0, "EXTERNAL" }, 473 { IS_CHECKED, 0, "" }, 474 { IS_ALL_HOSTS, 0, "" }, 475 { IS_ALL_ROUTERS, 0, "" }, 476 { IS_DISTRUST, 0, "DISTRUST" }, 477 { IS_BROKE, IS_SICK, "BROKEN" }, 478 { IS_SICK, 0, "SICK" }, 479 { IS_DUP, 0, "DUPLICATE" }, 480 { IS_REDIRECT_OK, 0, "REDIRECT_OK" }, 481 { IS_NEED_NET_SYN, 0, "" }, 482 { IS_NO_AG, IS_NO_SUPER_AG, "NO_AG" }, 483 { IS_NO_SUPER_AG, 0, "NO_SUPER_AG" }, 484 { (IS_NO_RIPV1_IN 485 | IS_NO_RIPV2_IN 486 | IS_NO_RIPV1_OUT 487 | IS_NO_RIPV2_OUT), 0, "NO_RIP" }, 488 { (IS_NO_RIPV1_IN 489 | IS_NO_RIPV1_OUT), 0, "RIPV2" }, 490 { IS_NO_RIPV1_IN, 0, "NO_RIPV1_IN" }, 491 { IS_NO_RIPV2_IN, 0, "NO_RIPV2_IN" }, 492 { IS_NO_RIPV1_OUT, 0, "NO_RIPV1_OUT" }, 493 { IS_NO_RIPV2_OUT, 0, "NO_RIPV2_OUT" }, 494 { (IS_NO_ADV_IN 495 | IS_NO_SOL_OUT 496 | IS_NO_ADV_OUT), IS_BCAST_RDISC, "NO_RDISC" }, 497 { IS_NO_SOL_OUT, 0, "NO_SOLICIT" }, 498 { IS_SOL_OUT, 0, "SEND_SOLICIT" }, 499 { IS_NO_ADV_OUT, IS_BCAST_RDISC, "NO_RDISC_ADV" }, 500 { IS_ADV_OUT, 0, "RDISC_ADV" }, 501 { IS_BCAST_RDISC, 0, "BCAST_RDISC" }, 502 { IS_PM_RDISC, 0, "" }, 503 { 0, 0, "%#x"} 504 }; 505 506 static struct bits rs_bits[] = { 507 { RS_IF, 0, "IF" }, 508 { RS_NET_INT, RS_NET_SYN, "NET_INT" }, 509 { RS_NET_SYN, 0, "NET_SYN" }, 510 { RS_SUBNET, 0, "" }, 511 { RS_LOCAL, 0, "LOCAL" }, 512 { RS_MHOME, 0, "MHOME" }, 513 { RS_STATIC, 0, "STATIC" }, 514 { RS_RDISC, 0, "RDISC" }, 515 { 0, 0, "%#x"} 516 }; 517 518 519 static void 520 trace_bits(const struct bits *tbl, 521 u_int field, 522 int force) 523 { 524 u_int b; 525 char c; 526 527 if (force) { 528 putc('<', ftrace); 529 c = 0; 530 } else { 531 c = '<'; 532 } 533 534 while (field != 0 535 && (b = tbl->bits_mask) != 0) { 536 if ((b & field) == b) { 537 if (tbl->bits_name[0] != '\0') { 538 if (c) 539 putc(c, ftrace); 540 fprintf(ftrace, "%s", tbl->bits_name); 541 c = '|'; 542 } 543 if (0 == (field &= ~(b | tbl->bits_clear))) 544 break; 545 } 546 tbl++; 547 } 548 if (field != 0 && tbl->bits_name != NULL) { 549 if (c) 550 putc(c, ftrace); 551 fprintf(ftrace, tbl->bits_name, field); 552 c = '|'; 553 } 554 555 if (c != '<' || force) 556 fputs("> ", ftrace); 557 } 558 559 560 char * 561 rtname(naddr dst, 562 naddr mask, 563 naddr gate) 564 { 565 static char buf[3*4+3+1+2+3 /* "xxx.xxx.xxx.xxx/xx-->" */ 566 +3*4+3+1]; /* "xxx.xxx.xxx.xxx" */ 567 int i; 568 569 i = sprintf(buf, "%-16s-->", addrname(dst, mask, 0)); 570 sprintf(&buf[i], "%-*s", 15+20-MAX(20,i), naddr_ntoa(gate)); 571 return buf; 572 } 573 574 575 static void 576 print_rts(struct rt_spare *rts, 577 int force_metric, /* -1=suppress, 0=default */ 578 int force_ifp, /* -1=suppress, 0=default */ 579 int force_router, /* -1=suppress, 0=default, 1=display */ 580 int force_tag, /* -1=suppress, 0=default, 1=display */ 581 int force_time) /* 0=suppress, 1=display */ 582 { 583 int i; 584 585 586 if (force_metric >= 0) 587 fprintf(ftrace, "metric=%-2d ", rts->rts_metric); 588 if (force_ifp >= 0) 589 fprintf(ftrace, "%s ", (rts->rts_ifp == 0 ? 590 "if?" : rts->rts_ifp->int_name)); 591 if (force_router > 0 592 || (force_router == 0 && rts->rts_router != rts->rts_gate)) 593 fprintf(ftrace, "router=%s ", naddr_ntoa(rts->rts_router)); 594 if (force_time > 0) 595 fprintf(ftrace, "%s ", ts(rts->rts_time)); 596 if (force_tag > 0 597 || (force_tag == 0 && rts->rts_tag != 0)) 598 fprintf(ftrace, "tag=%#x ", ntohs(rts->rts_tag)); 599 if (rts->rts_de_ag != 0) { 600 for (i = 1; (u_int)(1 << i) <= rts->rts_de_ag; i++) 601 continue; 602 fprintf(ftrace, "de_ag=%d ", i); 603 } 604 605 } 606 607 608 void 609 trace_if(const char *act, 610 struct interface *ifp) 611 { 612 if (!TRACEACTIONS || ftrace == NULL) 613 return; 614 615 lastlog(); 616 fprintf(ftrace, "%-3s interface %-4s ", act, ifp->int_name); 617 fprintf(ftrace, "%-15s-->%-15s ", 618 naddr_ntoa(ifp->int_addr), 619 addrname(((ifp->int_if_flags & IFF_POINTOPOINT) 620 ? ifp->int_dstaddr : htonl(ifp->int_net)), 621 ifp->int_mask, 1)); 622 if (ifp->int_metric != 0) 623 fprintf(ftrace, "metric=%d ", ifp->int_metric); 624 if (!IS_RIP_OUT_OFF(ifp->int_state) 625 && ifp->int_d_metric != 0) 626 fprintf(ftrace, "fake_default=%d ", ifp->int_d_metric); 627 trace_bits(if_bits, ifp->int_if_flags, 0); 628 trace_bits(is_bits, ifp->int_state, 0); 629 fputc('\n',ftrace); 630 } 631 632 633 void 634 trace_upslot(struct rt_entry *rt, 635 struct rt_spare *rts, 636 struct rt_spare *new) 637 { 638 if (!TRACEACTIONS || ftrace == NULL) 639 return; 640 641 if (rts->rts_gate == new->rts_gate 642 && rts->rts_router == new->rts_router 643 && rts->rts_metric == new->rts_metric 644 && rts->rts_tag == new->rts_tag 645 && rts->rts_de_ag == new->rts_de_ag) 646 return; 647 648 lastlog(); 649 if (new->rts_gate == 0) { 650 fprintf(ftrace, "Del #%d %-35s ", 651 (int)(rts - rt->rt_spares), 652 rtname(rt->rt_dst, rt->rt_mask, rts->rts_gate)); 653 print_rts(rts, 0,0,0,0, 654 (rts != rt->rt_spares 655 || AGE_RT(rt->rt_state,new->rts_ifp))); 656 657 } else if (rts->rts_gate != RIP_DEFAULT) { 658 fprintf(ftrace, "Chg #%d %-35s ", 659 (int)(rts - rt->rt_spares), 660 rtname(rt->rt_dst, rt->rt_mask, rts->rts_gate)); 661 print_rts(rts, 0,0, 662 rts->rts_gate != new->rts_gate, 663 rts->rts_tag != new->rts_tag, 664 rts != rt->rt_spares || AGE_RT(rt->rt_state, 665 rt->rt_ifp)); 666 667 fprintf(ftrace, "\n %19s%-16s ", "", 668 (new->rts_gate != rts->rts_gate 669 ? naddr_ntoa(new->rts_gate) : "")); 670 print_rts(new, 671 -(new->rts_metric == rts->rts_metric), 672 -(new->rts_ifp == rts->rts_ifp), 673 0, 674 rts->rts_tag != new->rts_tag, 675 (new->rts_time != rts->rts_time 676 && (rts != rt->rt_spares 677 || AGE_RT(rt->rt_state, new->rts_ifp)))); 678 679 } else { 680 fprintf(ftrace, "Add #%d %-35s ", 681 (int)(rts - rt->rt_spares), 682 rtname(rt->rt_dst, rt->rt_mask, new->rts_gate)); 683 print_rts(new, 0,0,0,0, 684 (rts != rt->rt_spares 685 || AGE_RT(rt->rt_state,new->rts_ifp))); 686 } 687 fputc('\n',ftrace); 688 } 689 690 691 /* miscellaneous message checked by the caller 692 */ 693 void 694 trace_misc(const char *p, ...) 695 { 696 va_list args; 697 698 if (ftrace == NULL) 699 return; 700 701 lastlog(); 702 va_start(args, p); 703 vfprintf(ftrace, p, args); 704 fputc('\n',ftrace); 705 } 706 707 708 /* display a message if tracing actions 709 */ 710 void 711 trace_act(const char *p, ...) 712 { 713 va_list args; 714 715 if (!TRACEACTIONS || ftrace == NULL) 716 return; 717 718 lastlog(); 719 va_start(args, p); 720 vfprintf(ftrace, p, args); 721 fputc('\n',ftrace); 722 } 723 724 725 /* display a message if tracing packets 726 */ 727 void 728 trace_pkt(const char *p, ...) 729 { 730 va_list args; 731 732 if (!TRACEPACKETS || ftrace == NULL) 733 return; 734 735 lastlog(); 736 va_start(args, p); 737 vfprintf(ftrace, p, args); 738 fputc('\n',ftrace); 739 } 740 741 742 void 743 trace_change(struct rt_entry *rt, 744 u_int state, 745 struct rt_spare *new, 746 const char *label) 747 { 748 if (ftrace == NULL) 749 return; 750 751 if (rt->rt_metric == new->rts_metric 752 && rt->rt_gate == new->rts_gate 753 && rt->rt_router == new->rts_router 754 && rt->rt_state == state 755 && rt->rt_tag == new->rts_tag 756 && rt->rt_de_ag == new->rts_de_ag) 757 return; 758 759 lastlog(); 760 fprintf(ftrace, "%s %-35s ", 761 label, rtname(rt->rt_dst, rt->rt_mask, rt->rt_gate)); 762 print_rts(rt->rt_spares, 763 0,0,0,0, AGE_RT(rt->rt_state, rt->rt_ifp)); 764 trace_bits(rs_bits, rt->rt_state, rt->rt_state != state); 765 766 fprintf(ftrace, "\n%*s %19s%-16s ", 767 (int)strlen(label), "", "", 768 (rt->rt_gate != new->rts_gate 769 ? naddr_ntoa(new->rts_gate) : "")); 770 print_rts(new, 771 -(new->rts_metric == rt->rt_metric), 772 -(new->rts_ifp == rt->rt_ifp), 773 0, 774 rt->rt_tag != new->rts_tag, 775 (rt->rt_time != new->rts_time 776 && AGE_RT(rt->rt_state,new->rts_ifp))); 777 if (rt->rt_state != state) 778 trace_bits(rs_bits, state, 1); 779 fputc('\n',ftrace); 780 } 781 782 783 void 784 trace_add_del(const char * action, struct rt_entry *rt) 785 { 786 if (ftrace == NULL) 787 return; 788 789 lastlog(); 790 fprintf(ftrace, "%s %-35s ", 791 action, rtname(rt->rt_dst, rt->rt_mask, rt->rt_gate)); 792 print_rts(rt->rt_spares, 0,0,0,0,AGE_RT(rt->rt_state,rt->rt_ifp)); 793 trace_bits(rs_bits, rt->rt_state, 0); 794 fputc('\n',ftrace); 795 } 796 797 798 /* ARGSUSED */ 799 static int 800 walk_trace(struct radix_node *rn, __unused struct walkarg *w) 801 { 802 #define RT ((struct rt_entry *)rn) 803 struct rt_spare *rts; 804 int i; 805 806 fprintf(ftrace, " %-35s ", 807 rtname(RT->rt_dst, RT->rt_mask, RT->rt_gate)); 808 print_rts(&RT->rt_spares[0], 0,0,0,0, AGE_RT(RT->rt_state, RT->rt_ifp)); 809 trace_bits(rs_bits, RT->rt_state, 0); 810 if (RT->rt_poison_time >= now_garbage 811 && RT->rt_poison_metric < RT->rt_metric) 812 fprintf(ftrace, "pm=%d@%s", 813 RT->rt_poison_metric, ts(RT->rt_poison_time)); 814 815 rts = &RT->rt_spares[1]; 816 for (i = 1; i < NUM_SPARES; i++, rts++) { 817 if (rts->rts_gate != RIP_DEFAULT) { 818 fprintf(ftrace,"\n #%d%15s%-16s ", 819 i, "", naddr_ntoa(rts->rts_gate)); 820 print_rts(rts, 0,0,0,0,1); 821 } 822 } 823 fputc('\n',ftrace); 824 825 return 0; 826 } 827 828 829 static void 830 trace_dump(void) 831 { 832 struct interface *ifp; 833 834 if (ftrace == NULL) 835 return; 836 lastlog(); 837 838 fputs("current daemon state:\n", ftrace); 839 for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) 840 trace_if("", ifp); 841 rn_walktree(rhead, walk_trace, 0); 842 } 843 844 845 void 846 trace_rip(const char *dir1, const char *dir2, 847 struct sockaddr_in *who, 848 struct interface *ifp, 849 struct rip *msg, 850 int size) /* total size of message */ 851 { 852 struct netinfo *n, *lim; 853 # define NA ((struct netauth*)n) 854 int i, seen_route; 855 856 if (!TRACEPACKETS || ftrace == NULL) 857 return; 858 859 lastlog(); 860 if (msg->rip_cmd >= RIPCMD_MAX 861 || msg->rip_vers == 0) { 862 fprintf(ftrace, "%s bad RIPv%d cmd=%d %s" 863 " %s.%d size=%d\n", 864 dir1, msg->rip_vers, msg->rip_cmd, dir2, 865 naddr_ntoa(who->sin_addr.s_addr), 866 ntohs(who->sin_port), 867 size); 868 return; 869 } 870 871 fprintf(ftrace, "%s RIPv%d %s %s %s.%d%s%s\n", 872 dir1, msg->rip_vers, ripcmds[msg->rip_cmd], dir2, 873 naddr_ntoa(who->sin_addr.s_addr), ntohs(who->sin_port), 874 ifp ? " via " : "", ifp ? ifp->int_name : ""); 875 if (!TRACECONTENTS) 876 return; 877 878 seen_route = 0; 879 switch (msg->rip_cmd) { 880 case RIPCMD_REQUEST: 881 case RIPCMD_RESPONSE: 882 n = msg->rip_nets; 883 lim = (struct netinfo *)((char*)msg + size); 884 for (; n < lim; n++) { 885 if (!seen_route 886 && n->n_family == RIP_AF_UNSPEC 887 && ntohl(n->n_metric) == HOPCNT_INFINITY 888 && msg->rip_cmd == RIPCMD_REQUEST 889 && (n+1 == lim 890 || (n+2 == lim 891 && (n+1)->n_family == RIP_AF_AUTH))) { 892 fputs("\tQUERY ", ftrace); 893 if (n->n_dst != 0) 894 fprintf(ftrace, "%s ", 895 naddr_ntoa(n->n_dst)); 896 if (n->n_mask != 0) 897 fprintf(ftrace, "mask=%#x ", 898 (u_int)ntohl(n->n_mask)); 899 if (n->n_nhop != 0) 900 fprintf(ftrace, "nhop=%s ", 901 naddr_ntoa(n->n_nhop)); 902 if (n->n_tag != 0) 903 fprintf(ftrace, "tag=%#x ", 904 ntohs(n->n_tag)); 905 fputc('\n',ftrace); 906 continue; 907 } 908 909 if (n->n_family == RIP_AF_AUTH) { 910 if (NA->a_type == RIP_AUTH_PW 911 && n == msg->rip_nets) { 912 fprintf(ftrace, "\tPassword" 913 " Authentication:" 914 " \"%s\"\n", 915 qstring(NA->au.au_pw, 916 RIP_AUTH_PW_LEN)); 917 continue; 918 } 919 920 if (NA->a_type == RIP_AUTH_MD5 921 && n == msg->rip_nets) { 922 fprintf(ftrace, 923 "\tMD5 Auth" 924 " pkt_len=%d KeyID=%u" 925 " auth_len=%d" 926 " seqno=%#x" 927 " rsvd=%#x,%#x\n", 928 ntohs(NA->au.a_md5.md5_pkt_len), 929 NA->au.a_md5.md5_keyid, 930 NA->au.a_md5.md5_auth_len, 931 (int)ntohl(NA->au.a_md5.md5_seqno), 932 (int)ntohs(NA->au.a_md5.rsvd[0]), 933 (int)ntohs(NA->au.a_md5.rsvd[1])); 934 continue; 935 } 936 fprintf(ftrace, 937 "\tAuthentication type %d: ", 938 ntohs(NA->a_type)); 939 for (i = 0; 940 i < (int)sizeof(NA->au.au_pw); 941 i++) 942 fprintf(ftrace, "%02x ", 943 NA->au.au_pw[i]); 944 fputc('\n',ftrace); 945 continue; 946 } 947 948 seen_route = 1; 949 if (n->n_family != RIP_AF_INET) { 950 fprintf(ftrace, 951 "\t(af %d) %-18s mask=%#x ", 952 ntohs(n->n_family), 953 naddr_ntoa(n->n_dst), 954 (u_int)ntohl(n->n_mask)); 955 } else if (msg->rip_vers == RIPv1) { 956 fprintf(ftrace, "\t%-18s ", 957 addrname(n->n_dst, ntohl(n->n_mask), 958 n->n_mask==0 ? 2 : 1)); 959 } else { 960 fprintf(ftrace, "\t%-18s ", 961 addrname(n->n_dst, ntohl(n->n_mask), 962 n->n_mask==0 ? 2 : 0)); 963 } 964 fprintf(ftrace, "metric=%-2d ", 965 (u_int)ntohl(n->n_metric)); 966 if (n->n_nhop != 0) 967 fprintf(ftrace, " nhop=%s ", 968 naddr_ntoa(n->n_nhop)); 969 if (n->n_tag != 0) 970 fprintf(ftrace, "tag=%#x", ntohs(n->n_tag)); 971 fputc('\n',ftrace); 972 } 973 if (size != (char *)n - (char *)msg) 974 fprintf(ftrace, "truncated record, len %d\n", size); 975 break; 976 977 case RIPCMD_TRACEON: 978 fprintf(ftrace, "\tfile=\"%.*s\"\n", size-4, 979 msg->rip_tracefile); 980 break; 981 982 case RIPCMD_TRACEOFF: 983 break; 984 } 985 } 986