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