trace.c revision 1.5 1 /*
2 * Copyright (c) 1983, 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 /*static char sccsid[] = "from: @(#)trace.c 8.1 (Berkeley) 6/5/93";*/
36 static char *rcsid = "$Id: trace.c,v 1.5 1994/05/13 08:04:58 mycroft Exp $";
37 #endif /* not lint */
38
39 /*
40 * Routing Table Management Daemon
41 */
42 #define RIPCMDS
43 #include "defs.h"
44 #include <sys/stat.h>
45 #include <sys/signal.h>
46 #include <fcntl.h>
47 #include <stdlib.h>
48 #include "pathnames.h"
49
50 #define NRECORDS 50 /* size of circular trace buffer */
51 #ifdef DEBUG
52 FILE *ftrace = stdout;
53 int traceactions = 0;
54 #endif
55 static struct timeval lastlog;
56 static char *savetracename;
57
58 traceinit(ifp)
59 register struct interface *ifp;
60 {
61 static int iftraceinit();
62
63 if (iftraceinit(ifp, &ifp->int_input) &&
64 iftraceinit(ifp, &ifp->int_output))
65 return;
66 tracehistory = 0;
67 fprintf(stderr, "traceinit: can't init %s\n", ifp->int_name);
68 }
69
70 static
71 iftraceinit(ifp, ifd)
72 struct interface *ifp;
73 register struct ifdebug *ifd;
74 {
75 register struct iftrace *t;
76
77 ifd->ifd_records =
78 (struct iftrace *)malloc(NRECORDS * sizeof (struct iftrace));
79 if (ifd->ifd_records == 0)
80 return (0);
81 ifd->ifd_front = ifd->ifd_records;
82 ifd->ifd_count = 0;
83 for (t = ifd->ifd_records; t < ifd->ifd_records + NRECORDS; t++) {
84 t->ift_size = 0;
85 t->ift_packet = 0;
86 }
87 ifd->ifd_if = ifp;
88 return (1);
89 }
90
91 traceon(file)
92 char *file;
93 {
94 struct stat stbuf;
95
96 if (ftrace != NULL)
97 return;
98 if (stat(file, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) != S_IFREG)
99 return;
100 savetracename = file;
101 (void) gettimeofday(&now, (struct timezone *)NULL);
102 ftrace = fopen(file, "a");
103 if (ftrace == NULL)
104 return;
105 dup2(fileno(ftrace), 1);
106 dup2(fileno(ftrace), 2);
107 traceactions = 1;
108 fprintf(ftrace, "Tracing enabled %s\n", ctime((time_t *)&now.tv_sec));
109 }
110
111 traceoff()
112 {
113 if (!traceactions)
114 return;
115 if (ftrace != NULL) {
116 int fd = open(_PATH_DEVNULL, O_RDWR);
117
118 fprintf(ftrace, "Tracing disabled %s\n",
119 ctime((time_t *)&now.tv_sec));
120 fflush(ftrace);
121 (void) dup2(fd, 1);
122 (void) dup2(fd, 2);
123 (void) close(fd);
124 fclose(ftrace);
125 ftrace = NULL;
126 }
127 traceactions = 0;
128 tracehistory = 0;
129 tracepackets = 0;
130 tracecontents = 0;
131 }
132
133 void
134 sigtrace(s)
135 int s;
136 {
137
138 if (s == SIGUSR2)
139 traceoff();
140 else if (ftrace == NULL && savetracename)
141 traceon(savetracename);
142 else
143 bumploglevel();
144 }
145
146 /*
147 * Move to next higher level of tracing when -t option processed or
148 * SIGUSR1 is received. Successive levels are:
149 * traceactions
150 * traceactions + tracepackets
151 * traceactions + tracehistory (packets and contents after change)
152 * traceactions + tracepackets + tracecontents
153 */
154 bumploglevel()
155 {
156
157 (void) gettimeofday(&now, (struct timezone *)NULL);
158 if (traceactions == 0) {
159 traceactions++;
160 if (ftrace)
161 fprintf(ftrace, "Tracing actions started %s\n",
162 ctime((time_t *)&now.tv_sec));
163 } else if (tracepackets == 0) {
164 tracepackets++;
165 tracehistory = 0;
166 tracecontents = 0;
167 if (ftrace)
168 fprintf(ftrace, "Tracing packets started %s\n",
169 ctime((time_t *)&now.tv_sec));
170 } else if (tracehistory == 0) {
171 tracehistory++;
172 if (ftrace)
173 fprintf(ftrace, "Tracing history started %s\n",
174 ctime((time_t *)&now.tv_sec));
175 } else {
176 tracepackets++;
177 tracecontents++;
178 tracehistory = 0;
179 if (ftrace)
180 fprintf(ftrace, "Tracing packet contents started %s\n",
181 ctime((time_t *)&now.tv_sec));
182 }
183 if (ftrace)
184 fflush(ftrace);
185 }
186
187 trace(ifd, who, p, len, m)
188 register struct ifdebug *ifd;
189 struct sockaddr *who;
190 char *p;
191 int len, m;
192 {
193 register struct iftrace *t;
194
195 if (ifd->ifd_records == 0)
196 return;
197 t = ifd->ifd_front++;
198 if (ifd->ifd_front >= ifd->ifd_records + NRECORDS)
199 ifd->ifd_front = ifd->ifd_records;
200 if (ifd->ifd_count < NRECORDS)
201 ifd->ifd_count++;
202 if (t->ift_size > 0 && t->ift_size < len && t->ift_packet) {
203 free(t->ift_packet);
204 t->ift_packet = 0;
205 }
206 t->ift_stamp = now;
207 t->ift_who = *who;
208 if (len > 0 && t->ift_packet == 0) {
209 t->ift_packet = malloc(len);
210 if (t->ift_packet == 0)
211 len = 0;
212 }
213 if (len > 0)
214 bcopy(p, t->ift_packet, len);
215 t->ift_size = len;
216 t->ift_metric = m;
217 }
218
219 traceaction(fd, action, rt)
220 FILE *fd;
221 char *action;
222 struct rt_entry *rt;
223 {
224 struct sockaddr_in *dst, *gate;
225 static struct bits {
226 int t_bits;
227 char *t_name;
228 } flagbits[] = {
229 { RTF_UP, "UP" },
230 { RTF_GATEWAY, "GATEWAY" },
231 { RTF_HOST, "HOST" },
232 { 0 }
233 }, statebits[] = {
234 { RTS_PASSIVE, "PASSIVE" },
235 { RTS_REMOTE, "REMOTE" },
236 { RTS_INTERFACE,"INTERFACE" },
237 { RTS_CHANGED, "CHANGED" },
238 { RTS_INTERNAL, "INTERNAL" },
239 { RTS_EXTERNAL, "EXTERNAL" },
240 { RTS_SUBNET, "SUBNET" },
241 { 0 }
242 };
243 register struct bits *p;
244 register int first;
245 char *cp;
246 struct interface *ifp;
247
248 if (fd == NULL)
249 return;
250 if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
251 fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
252 lastlog = now;
253 }
254 fprintf(fd, "%s ", action);
255 dst = (struct sockaddr_in *)&rt->rt_dst;
256 gate = (struct sockaddr_in *)&rt->rt_router;
257 fprintf(fd, "dst %s, ", inet_ntoa(dst->sin_addr));
258 fprintf(fd, "router %s, metric %d, flags",
259 inet_ntoa(gate->sin_addr), rt->rt_metric);
260 cp = " %s";
261 for (first = 1, p = flagbits; p->t_bits > 0; p++) {
262 if ((rt->rt_flags & p->t_bits) == 0)
263 continue;
264 fprintf(fd, cp, p->t_name);
265 if (first) {
266 cp = "|%s";
267 first = 0;
268 }
269 }
270 fprintf(fd, " state");
271 cp = " %s";
272 for (first = 1, p = statebits; p->t_bits > 0; p++) {
273 if ((rt->rt_state & p->t_bits) == 0)
274 continue;
275 fprintf(fd, cp, p->t_name);
276 if (first) {
277 cp = "|%s";
278 first = 0;
279 }
280 }
281 fprintf(fd, " timer %d\n", rt->rt_timer);
282 if (tracehistory && !tracepackets &&
283 (rt->rt_state & RTS_PASSIVE) == 0 && rt->rt_ifp)
284 dumpif(fd, rt->rt_ifp);
285 fflush(fd);
286 if (ferror(fd))
287 traceoff();
288 }
289
290 tracenewmetric(fd, rt, newmetric)
291 FILE *fd;
292 struct rt_entry *rt;
293 int newmetric;
294 {
295 struct sockaddr_in *dst, *gate;
296
297 if (fd == NULL)
298 return;
299 if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
300 fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
301 lastlog = now;
302 }
303 dst = (struct sockaddr_in *)&rt->rt_dst;
304 gate = (struct sockaddr_in *)&rt->rt_router;
305 fprintf(fd, "CHANGE metric dst %s, ", inet_ntoa(dst->sin_addr));
306 fprintf(fd, "router %s, from %d to %d\n",
307 inet_ntoa(gate->sin_addr), rt->rt_metric, newmetric);
308 fflush(fd);
309 if (ferror(fd))
310 traceoff();
311 }
312
313 dumpif(fd, ifp)
314 FILE *fd;
315 register struct interface *ifp;
316 {
317 if (ifp->int_input.ifd_count || ifp->int_output.ifd_count) {
318 fprintf(fd, "*** Packet history for interface %s ***\n",
319 ifp->int_name);
320 #ifdef notneeded
321 dumptrace(fd, "to", &ifp->int_output);
322 #endif
323 dumptrace(fd, "from", &ifp->int_input);
324 fprintf(fd, "*** end packet history ***\n");
325 }
326 }
327
328 dumptrace(fd, dir, ifd)
329 FILE *fd;
330 char *dir;
331 register struct ifdebug *ifd;
332 {
333 register struct iftrace *t;
334 char *cp = !strcmp(dir, "to") ? "Output" : "Input";
335
336 if (ifd->ifd_front == ifd->ifd_records &&
337 ifd->ifd_front->ift_size == 0) {
338 fprintf(fd, "%s: no packets.\n", cp);
339 fflush(fd);
340 return;
341 }
342 fprintf(fd, "%s trace:\n", cp);
343 t = ifd->ifd_front - ifd->ifd_count;
344 if (t < ifd->ifd_records)
345 t += NRECORDS;
346 for ( ; ifd->ifd_count; ifd->ifd_count--, t++) {
347 if (t >= ifd->ifd_records + NRECORDS)
348 t = ifd->ifd_records;
349 if (t->ift_size == 0)
350 continue;
351 dumppacket(fd, dir, &t->ift_who, t->ift_packet, t->ift_size,
352 &t->ift_stamp);
353 }
354 }
355
356 dumppacket(fd, dir, who, cp, size, stamp)
357 FILE *fd;
358 struct sockaddr_in *who; /* should be sockaddr */
359 char *dir, *cp;
360 register int size;
361 struct timeval *stamp;
362 {
363 register struct rip *msg = (struct rip *)cp;
364 register struct netinfo *n;
365
366 if (fd == NULL)
367 return;
368 if (msg->rip_cmd && msg->rip_cmd < RIPCMD_MAX)
369 fprintf(fd, "%s %s %s.%d %.19s:\n", ripcmds[msg->rip_cmd],
370 dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port),
371 ctime((time_t *)&stamp->tv_sec));
372 else {
373 fprintf(fd, "Bad cmd 0x%x %s %x.%d %.19s\n", msg->rip_cmd,
374 dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port));
375 fprintf(fd, "size=%d cp=%x packet=%x\n", size, cp, packet,
376 ctime((time_t *)&stamp->tv_sec));
377 fflush(fd);
378 return;
379 }
380 if (tracepackets && tracecontents == 0) {
381 fflush(fd);
382 return;
383 }
384 switch (msg->rip_cmd) {
385
386 case RIPCMD_REQUEST:
387 case RIPCMD_RESPONSE:
388 size -= 4 * sizeof (char);
389 n = msg->rip_nets;
390 for (; size > 0; n++, size -= sizeof (struct netinfo)) {
391 if (size < sizeof (struct netinfo)) {
392 fprintf(fd, "(truncated record, len %d)\n",
393 size);
394 break;
395 }
396 if (sizeof(n->rip_dst.sa_family) > 1)
397 n->rip_dst.sa_family = ntohs(n->rip_dst.sa_family);
398
399 switch ((int)n->rip_dst.sa_family) {
400
401 case AF_INET:
402 fprintf(fd, "\tdst %s metric %d\n",
403 #define satosin(sa) ((struct sockaddr_in *)&sa)
404 inet_ntoa(satosin(n->rip_dst)->sin_addr),
405 ntohl(n->rip_metric));
406 break;
407
408 default:
409 fprintf(fd, "\taf %d? metric %d\n",
410 n->rip_dst.sa_family,
411 ntohl(n->rip_metric));
412 break;
413 }
414 }
415 break;
416
417 case RIPCMD_TRACEON:
418 fprintf(fd, "\tfile=%*s\n", size, msg->rip_tracefile);
419 break;
420
421 case RIPCMD_TRACEOFF:
422 break;
423 }
424 fflush(fd);
425 if (ferror(fd))
426 traceoff();
427 }
428