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