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