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