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