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