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