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