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