trace.c revision 1.13 1 /* $NetBSD: trace.c,v 1.13 1995/06/20 22:28:03 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 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)trace.c 8.1 (Berkeley) 6/5/93";
39 #else
40 static char rcsid[] = "$NetBSD: trace.c,v 1.13 1995/06/20 22:28:03 christos Exp $";
41 #endif
42 #endif /* not lint */
43
44 /*
45 * Routing Table Management Daemon
46 */
47 #define RIPCMDS
48 #include "defs.h"
49 #include <sys/stat.h>
50 #include <signal.h>
51 #include <fcntl.h>
52 #include "pathnames.h"
53
54 #define NRECORDS 50 /* size of circular trace buffer */
55 #ifdef DEBUG
56 FILE *ftrace = stdout;
57 int traceactions = 0;
58 #endif
59 static struct timeval lastlog;
60 static char *savetracename;
61
62 static int iftraceinit __P((struct interface *, struct ifdebug *));
63 void dumpif __P((FILE *, struct interface *));
64 void dumptrace __P((FILE *, char *, struct ifdebug *));
65
66 void
67 traceinit(ifp)
68 register struct interface *ifp;
69 {
70 if (iftraceinit(ifp, &ifp->int_input) &&
71 iftraceinit(ifp, &ifp->int_output))
72 return;
73 tracehistory = 0;
74 fprintf(stderr, "traceinit: can't init %s\n", ifp->int_name);
75 }
76
77 static int
78 iftraceinit(ifp, ifd)
79 struct interface *ifp;
80 register struct ifdebug *ifd;
81 {
82 register struct iftrace *t;
83
84 ifd->ifd_records =
85 (struct iftrace *)malloc(NRECORDS * sizeof (struct iftrace));
86 if (ifd->ifd_records == 0)
87 return (0);
88 ifd->ifd_front = ifd->ifd_records;
89 ifd->ifd_count = 0;
90 for (t = ifd->ifd_records; t < ifd->ifd_records + NRECORDS; t++) {
91 t->ift_size = 0;
92 t->ift_packet = 0;
93 }
94 ifd->ifd_if = ifp;
95 return (1);
96 }
97
98 void
99 traceon(file)
100 char *file;
101 {
102 struct stat stbuf;
103
104 if (ftrace != NULL)
105 return;
106 if (stat(file, &stbuf) >= 0 && !S_ISREG(stbuf.st_mode))
107 return;
108 savetracename = file;
109 (void) gettimeofday(&now, NULL);
110 ftrace = fopen(file, "a");
111 if (ftrace == NULL)
112 return;
113 dup2(fileno(ftrace), 1);
114 dup2(fileno(ftrace), 2);
115 traceactions = 1;
116 fprintf(ftrace, "Tracing enabled %s\n", ctime((time_t *)&now.tv_sec));
117 }
118
119 void
120 traceoff()
121 {
122 if (!traceactions)
123 return;
124 if (ftrace != NULL) {
125 int fd = open(_PATH_DEVNULL, O_RDWR);
126
127 fprintf(ftrace, "Tracing disabled %s\n",
128 ctime((time_t *)&now.tv_sec));
129 fflush(ftrace);
130 (void) dup2(fd, 1);
131 (void) dup2(fd, 2);
132 (void) close(fd);
133 fclose(ftrace);
134 ftrace = NULL;
135 }
136 traceactions = 0;
137 tracehistory = 0;
138 tracepackets = 0;
139 tracecontents = 0;
140 }
141
142 void
143 sigtrace(s)
144 int s;
145 {
146
147 if (s == SIGUSR2)
148 traceoff();
149 else if (ftrace == NULL && savetracename)
150 traceon(savetracename);
151 else
152 bumploglevel();
153 }
154
155 /*
156 * Move to next higher level of tracing when -t option processed or
157 * SIGUSR1 is received. Successive levels are:
158 * traceactions
159 * traceactions + tracepackets
160 * traceactions + tracehistory (packets and contents after change)
161 * traceactions + tracepackets + tracecontents
162 */
163 void
164 bumploglevel()
165 {
166
167 (void) gettimeofday(&now, NULL);
168 if (traceactions == 0) {
169 traceactions++;
170 if (ftrace)
171 fprintf(ftrace, "Tracing actions started %s\n",
172 ctime((time_t *)&now.tv_sec));
173 } else if (tracepackets == 0) {
174 tracepackets++;
175 tracehistory = 0;
176 tracecontents = 0;
177 if (ftrace)
178 fprintf(ftrace, "Tracing packets started %s\n",
179 ctime((time_t *)&now.tv_sec));
180 } else if (tracehistory == 0) {
181 tracehistory++;
182 if (ftrace)
183 fprintf(ftrace, "Tracing history started %s\n",
184 ctime((time_t *)&now.tv_sec));
185 } else {
186 tracepackets++;
187 tracecontents++;
188 tracehistory = 0;
189 if (ftrace)
190 fprintf(ftrace, "Tracing packet contents started %s\n",
191 ctime((time_t *)&now.tv_sec));
192 }
193 if (ftrace)
194 fflush(ftrace);
195 }
196
197 void
198 trace(ifd, who, p, len, m)
199 register struct ifdebug *ifd;
200 struct sockaddr *who;
201 char *p;
202 int len, m;
203 {
204 register struct iftrace *t;
205
206 if (ifd->ifd_records == 0)
207 return;
208 t = ifd->ifd_front++;
209 if (ifd->ifd_front >= ifd->ifd_records + NRECORDS)
210 ifd->ifd_front = ifd->ifd_records;
211 if (ifd->ifd_count < NRECORDS)
212 ifd->ifd_count++;
213 if (t->ift_size > 0 && t->ift_size < len && t->ift_packet) {
214 free(t->ift_packet);
215 t->ift_packet = 0;
216 }
217 t->ift_stamp = now;
218 t->ift_who = *who;
219 if (len > 0 && t->ift_packet == 0) {
220 t->ift_packet = malloc(len);
221 if (t->ift_packet == 0)
222 len = 0;
223 }
224 if (len > 0)
225 memcpy(t->ift_packet, p, len);
226 t->ift_size = len;
227 t->ift_metric = m;
228 }
229
230 void
231 traceaction(fd, action, rt)
232 FILE *fd;
233 char *action;
234 struct rt_entry *rt;
235 {
236 struct sockaddr_in *dst, *gate, *netmask;
237 static struct bits {
238 int t_bits;
239 char *t_name;
240 } flagbits[] = {
241 { RTF_UP, "UP" },
242 { RTF_GATEWAY, "GATEWAY" },
243 { RTF_HOST, "HOST" },
244 { 0 }
245 }, statebits[] = {
246 { RTS_PASSIVE, "PASSIVE" },
247 { RTS_REMOTE, "REMOTE" },
248 { RTS_INTERFACE,"INTERFACE" },
249 { RTS_CHANGED, "CHANGED" },
250 { RTS_INTERNAL, "INTERNAL" },
251 { RTS_EXTERNAL, "EXTERNAL" },
252 { RTS_SUBNET, "SUBNET" },
253 { 0 }
254 };
255 register struct bits *p;
256 register int first;
257 char *cp;
258
259 if (fd == NULL)
260 return;
261 if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
262 fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
263 lastlog = now;
264 }
265 fprintf(fd, "%s ", action);
266 dst = (struct sockaddr_in *)&rt->rt_dst;
267 gate = (struct sockaddr_in *)&rt->rt_router;
268 netmask = (struct sockaddr_in *)&rt->rt_netmask;
269 fprintf(fd, "dst %s, ", inet_ntoa(dst->sin_addr));
270 fprintf(fd, "router %s, ", inet_ntoa(gate->sin_addr));
271 fprintf(fd, " netmask %s, metric %d, flags",
272 inet_ntoa(netmask->sin_addr), rt->rt_metric);
273 cp = " %s";
274 for (first = 1, p = flagbits; p->t_bits > 0; p++) {
275 if ((rt->rt_flags & p->t_bits) == 0)
276 continue;
277 fprintf(fd, cp, p->t_name);
278 if (first) {
279 cp = "|%s";
280 first = 0;
281 }
282 }
283 fprintf(fd, " state");
284 cp = " %s";
285 for (first = 1, p = statebits; p->t_bits > 0; p++) {
286 if ((rt->rt_state & p->t_bits) == 0)
287 continue;
288 fprintf(fd, cp, p->t_name);
289 if (first) {
290 cp = "|%s";
291 first = 0;
292 }
293 }
294 fprintf(fd, " timer %d\n", rt->rt_timer);
295 if (tracehistory && !tracepackets &&
296 (rt->rt_state & RTS_PASSIVE) == 0 && rt->rt_ifp)
297 dumpif(fd, rt->rt_ifp);
298 fflush(fd);
299 if (ferror(fd))
300 traceoff();
301 }
302
303 void
304 tracenewmetric(fd, rt, newmetric)
305 FILE *fd;
306 struct rt_entry *rt;
307 int newmetric;
308 {
309 struct sockaddr_in *dst, *gate;
310
311 if (fd == NULL)
312 return;
313 if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
314 fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
315 lastlog = now;
316 }
317 dst = (struct sockaddr_in *)&rt->rt_dst;
318 gate = (struct sockaddr_in *)&rt->rt_router;
319 fprintf(fd, "CHANGE metric dst %s, ", inet_ntoa(dst->sin_addr));
320 fprintf(fd, "router %s, from %d to %d\n",
321 inet_ntoa(gate->sin_addr), rt->rt_metric, newmetric);
322 fflush(fd);
323 if (ferror(fd))
324 traceoff();
325 }
326
327 void
328 dumpif(fd, ifp)
329 FILE *fd;
330 register struct interface *ifp;
331 {
332 if (ifp->int_input.ifd_count || ifp->int_output.ifd_count) {
333 fprintf(fd, "*** Packet history for interface %s ***\n",
334 ifp->int_name);
335 #ifdef notneeded
336 dumptrace(fd, "to", &ifp->int_output);
337 #endif
338 dumptrace(fd, "from", &ifp->int_input);
339 fprintf(fd, "*** end packet history ***\n");
340 }
341 }
342
343 void
344 dumptrace(fd, dir, ifd)
345 FILE *fd;
346 char *dir;
347 register struct ifdebug *ifd;
348 {
349 register struct iftrace *t;
350 char *cp = !strcmp(dir, "to") ? "Output" : "Input";
351
352 if (ifd->ifd_front == ifd->ifd_records &&
353 ifd->ifd_front->ift_size == 0) {
354 fprintf(fd, "%s: no packets.\n", cp);
355 fflush(fd);
356 return;
357 }
358 fprintf(fd, "%s trace:\n", cp);
359 t = ifd->ifd_front - ifd->ifd_count;
360 if (t < ifd->ifd_records)
361 t += NRECORDS;
362 for ( ; ifd->ifd_count; ifd->ifd_count--, t++) {
363 if (t >= ifd->ifd_records + NRECORDS)
364 t = ifd->ifd_records;
365 if (t->ift_size == 0)
366 continue;
367 dumppacket(fd, dir, (struct sockaddr_in *)&t->ift_who,
368 t->ift_packet, t->ift_size, &t->ift_stamp);
369 }
370 }
371
372 void
373 dumppacket(fd, dir, who, cp, size, stamp)
374 FILE *fd;
375 struct sockaddr_in *who; /* should be sockaddr */
376 char *dir, *cp;
377 register int size;
378 struct timeval *stamp;
379 {
380 register struct rip *msg = (struct rip *)cp;
381 register struct netinfo *n;
382
383 if (fd == NULL)
384 return;
385 if (msg->rip_cmd && msg->rip_cmd < RIPCMD_MAX)
386 fprintf(fd, "%s %s %s.%d %.19s:\n", ripcmds[msg->rip_cmd],
387 dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port),
388 ctime((time_t *)&stamp->tv_sec));
389 else {
390 fprintf(fd, "Bad cmd 0x%x %s %s.%d %.19s\n", msg->rip_cmd,
391 dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port),
392 ctime((time_t *)&stamp->tv_sec));
393 fprintf(fd, "size=%d cp=%lx packet=%lx\n", size,
394 (u_long) cp, (u_long) packet);
395 fflush(fd);
396 return;
397 }
398 if (tracepackets && tracecontents == 0) {
399 fflush(fd);
400 return;
401 }
402 switch (msg->rip_cmd) {
403
404 case RIPCMD_REQUEST:
405 case RIPCMD_RESPONSE:
406 size -= 4 * sizeof (char);
407 n = msg->rip_nets;
408 for (; size > 0; n++, size -= sizeof (struct netinfo)) {
409 if (size < sizeof (struct netinfo)) {
410 fprintf(fd, "(truncated record, len %d)\n",
411 size);
412 break;
413 }
414 switch (n->rip_family) {
415
416 case AF_INET:
417 {
418 struct sockaddr_in sa;
419 sa.sin_addr.s_addr = n->rip_dst;
420 fprintf(fd, "\tdst %s",
421 inet_ntoa(sa.sin_addr));
422 if (msg->rip_vers > RIP_VERSION_1) {
423 fprintf(fd, ", mask 0x%.8x",
424 n->rip_netmask);
425 sa.sin_addr.s_addr =
426 n->rip_router;
427 fprintf(fd, ", router %s",
428 inet_ntoa(sa.sin_addr));
429 }
430 }
431 break;
432
433 default:
434 fprintf(fd, "\taf %d?", n->rip_family);
435 break;
436 }
437 fprintf(fd, ", metric %d\n", ntohl(n->rip_metric));
438 }
439 break;
440
441 case RIPCMD_TRACEON:
442 fprintf(fd, "\tfile=%*s\n", size, msg->rip_tracefile);
443 break;
444
445 case RIPCMD_TRACEOFF:
446 break;
447 }
448 fflush(fd);
449 if (ferror(fd))
450 traceoff();
451 }
452