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