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