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