xref: /netbsd-src/sbin/routed/trace.c (revision 811e6386f8c5e4a3521c7003da29ec8673e344fa)
1 /*
2  * Copyright (c) 1983, 1988 Regents of the University of California.
3  * 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[] = "@(#)trace.c	5.11 (Berkeley) 2/28/91";
36 static char rcsid[] = "$Header: /cvsroot/src/sbin/routed/trace.c,v 1.3 1993/03/23 00:30:48 cgd 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