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