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