xref: /csrg-svn/sbin/routed/trace.c (revision 36831)
122001Sdist /*
234564Skarels  * Copyright (c) 1983, 1988 Regents of the University of California.
333489Sbostic  * All rights reserved.
433489Sbostic  *
533489Sbostic  * Redistribution and use in source and binary forms are permitted
634771Sbostic  * provided that the above copyright notice and this paragraph are
734771Sbostic  * duplicated in all such forms and that any documentation,
834771Sbostic  * advertising materials, and other materials related to such
934771Sbostic  * distribution and use acknowledge that the software was developed
1034771Sbostic  * by the University of California, Berkeley.  The name of the
1134771Sbostic  * University may not be used to endorse or promote products derived
1234771Sbostic  * from this software without specific prior written permission.
1334771Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434771Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534771Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1622001Sdist  */
1722001Sdist 
189022Ssam #ifndef lint
19*36831Skarels static char sccsid[] = "@(#)trace.c	5.8 (Berkeley) 02/18/89";
2033489Sbostic #endif /* not lint */
219022Ssam 
229022Ssam /*
239022Ssam  * Routing Table Management Daemon
249022Ssam  */
259022Ssam #define	RIPCMDS
2610245Ssam #include "defs.h"
2734571Skarels #include <sys/file.h>
2828906Skarels #include <sys/stat.h>
2934564Skarels #include <sys/signal.h>
309022Ssam 
319022Ssam #define	NRECORDS	50		/* size of circular trace buffer */
329022Ssam #ifdef DEBUG
339022Ssam FILE	*ftrace = stdout;
34*36831Skarels int	traceactions = 0;
359022Ssam #endif
36*36831Skarels static	struct timeval lastlog;
37*36831Skarels static	char *savetracename;
389022Ssam 
399022Ssam traceinit(ifp)
409022Ssam 	register struct interface *ifp;
419022Ssam {
429022Ssam 
439022Ssam 	if (iftraceinit(ifp, &ifp->int_input) &&
449022Ssam 	    iftraceinit(ifp, &ifp->int_output))
459022Ssam 		return;
4634564Skarels 	tracehistory = 0;
479022Ssam 	fprintf(stderr, "traceinit: can't init %s\n", ifp->int_name);
489022Ssam }
499022Ssam 
509022Ssam static
519022Ssam iftraceinit(ifp, ifd)
529022Ssam 	struct interface *ifp;
539022Ssam 	register struct ifdebug *ifd;
549022Ssam {
559022Ssam 	register struct iftrace *t;
569022Ssam 
579022Ssam 	ifd->ifd_records =
589022Ssam 	  (struct iftrace *)malloc(NRECORDS * sizeof (struct iftrace));
599022Ssam 	if (ifd->ifd_records == 0)
609022Ssam 		return (0);
619022Ssam 	ifd->ifd_front = ifd->ifd_records;
6216314Skarels 	ifd->ifd_count = 0;
639022Ssam 	for (t = ifd->ifd_records; t < ifd->ifd_records + NRECORDS; t++) {
649022Ssam 		t->ift_size = 0;
659022Ssam 		t->ift_packet = 0;
669022Ssam 	}
679022Ssam 	ifd->ifd_if = ifp;
689022Ssam 	return (1);
699022Ssam }
709022Ssam 
719022Ssam traceon(file)
729022Ssam 	char *file;
739022Ssam {
7428906Skarels 	struct stat stbuf;
759022Ssam 
769022Ssam 	if (ftrace != NULL)
779022Ssam 		return;
7828906Skarels 	if (stat(file, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) != S_IFREG)
7928906Skarels 		return;
80*36831Skarels 	savetracename = file;
81*36831Skarels 	(void) gettimeofday(&now, (struct timezone *)NULL);
829022Ssam 	ftrace = fopen(file, "a");
839022Ssam 	if (ftrace == NULL)
849022Ssam 		return;
859022Ssam 	dup2(fileno(ftrace), 1);
869022Ssam 	dup2(fileno(ftrace), 2);
8734564Skarels 	traceactions = 1;
88*36831Skarels 	fprintf(ftrace, "Tracing enabled %s\n", ctime((time_t *)&now.tv_sec));
899022Ssam }
909022Ssam 
919022Ssam traceoff()
929022Ssam {
9334564Skarels 	if (!traceactions)
949022Ssam 		return;
9534571Skarels 	if (ftrace != NULL) {
9634571Skarels 		int fd = open("/dev/null", O_RDWR);
9734571Skarels 
98*36831Skarels 		fprintf(ftrace, "Tracing disabled %s\n",
99*36831Skarels 		    ctime((time_t *)&now.tv_sec));
100*36831Skarels 		fflush(ftrace);
10134571Skarels 		(void) dup2(fd, 1);
10234571Skarels 		(void) dup2(fd, 2);
10334571Skarels 		(void) close(fd);
1049022Ssam 		fclose(ftrace);
10534571Skarels 		ftrace = NULL;
10634571Skarels 	}
10734564Skarels 	traceactions = 0;
10834564Skarels 	tracehistory = 0;
109*36831Skarels 	tracepackets = 0;
110*36831Skarels 	tracecontents = 0;
1119022Ssam }
1129022Ssam 
11334564Skarels sigtrace(s)
11434564Skarels 	int s;
11534564Skarels {
116*36831Skarels 
117*36831Skarels 	if (s == SIGUSR2)
11834564Skarels 		traceoff();
119*36831Skarels 	else if (ftrace == NULL && savetracename)
120*36831Skarels 		traceon(savetracename);
121*36831Skarels 	else
122*36831Skarels 		bumploglevel();
123*36831Skarels }
124*36831Skarels 
125*36831Skarels /*
126*36831Skarels  * Move to next higher level of tracing when -t option processed or
127*36831Skarels  * SIGUSR1 is received.  Successive levels are:
128*36831Skarels  *	traceactions
129*36831Skarels  *	traceactions + tracepackets
130*36831Skarels  *	traceactions + tracehistory (packets and contents after change)
131*36831Skarels  *	traceactions + tracepackets + tracecontents
132*36831Skarels  */
133*36831Skarels bumploglevel()
134*36831Skarels {
135*36831Skarels 
136*36831Skarels 	(void) gettimeofday(&now, (struct timezone *)NULL);
137*36831Skarels 	if (traceactions == 0) {
13834564Skarels 		traceactions++;
139*36831Skarels 		if (ftrace)
140*36831Skarels 			fprintf(ftrace, "Tracing actions started %s\n",
141*36831Skarels 			    ctime((time_t *)&now.tv_sec));
142*36831Skarels 	} else if (tracepackets == 0) {
143*36831Skarels 		tracepackets++;
144*36831Skarels 		tracehistory = 0;
145*36831Skarels 		tracecontents = 0;
146*36831Skarels 		if (ftrace)
147*36831Skarels 			fprintf(ftrace, "Tracing packets started %s\n",
148*36831Skarels 			    ctime((time_t *)&now.tv_sec));
149*36831Skarels 	} else if (tracehistory == 0) {
15034564Skarels 		tracehistory++;
151*36831Skarels 		if (ftrace)
152*36831Skarels 			fprintf(ftrace, "Tracing history started %s\n",
153*36831Skarels 			    ctime((time_t *)&now.tv_sec));
154*36831Skarels 	} else {
15534564Skarels 		tracepackets++;
156*36831Skarels 		tracecontents++;
15734564Skarels 		tracehistory = 0;
158*36831Skarels 		if (ftrace)
159*36831Skarels 			fprintf(ftrace, "Tracing packet contents started %s\n",
160*36831Skarels 			    ctime((time_t *)&now.tv_sec));
16134564Skarels 	}
162*36831Skarels 	if (ftrace)
163*36831Skarels 		fflush(ftrace);
16434564Skarels }
16534564Skarels 
1669022Ssam trace(ifd, who, p, len, m)
1679022Ssam 	register struct ifdebug *ifd;
1689022Ssam 	struct sockaddr *who;
1699022Ssam 	char *p;
1709022Ssam 	int len, m;
1719022Ssam {
1729022Ssam 	register struct iftrace *t;
1739022Ssam 
1749022Ssam 	if (ifd->ifd_records == 0)
1759022Ssam 		return;
1769022Ssam 	t = ifd->ifd_front++;
1779022Ssam 	if (ifd->ifd_front >= ifd->ifd_records + NRECORDS)
1789022Ssam 		ifd->ifd_front = ifd->ifd_records;
17916314Skarels 	if (ifd->ifd_count < NRECORDS)
18016314Skarels 		ifd->ifd_count++;
18126960Skarels 	if (t->ift_size > 0 && t->ift_size < len && t->ift_packet) {
1829022Ssam 		free(t->ift_packet);
18326960Skarels 		t->ift_packet = 0;
18426960Skarels 	}
185*36831Skarels 	t->ift_stamp = now;
1869022Ssam 	t->ift_who = *who;
18726960Skarels 	if (len > 0 && t->ift_packet == 0) {
1889022Ssam 		t->ift_packet = malloc(len);
18926960Skarels 		if (t->ift_packet == 0)
1909022Ssam 			len = 0;
1919022Ssam 	}
19226960Skarels 	if (len > 0)
19326960Skarels 		bcopy(p, t->ift_packet, len);
1949022Ssam 	t->ift_size = len;
1959022Ssam 	t->ift_metric = m;
1969022Ssam }
1979022Ssam 
1989022Ssam traceaction(fd, action, rt)
1999022Ssam 	FILE *fd;
2009022Ssam 	char *action;
2019022Ssam 	struct rt_entry *rt;
2029022Ssam {
2039022Ssam 	struct sockaddr_in *dst, *gate;
2049022Ssam 	static struct bits {
2059022Ssam 		int	t_bits;
2069022Ssam 		char	*t_name;
2079022Ssam 	} flagbits[] = {
2089022Ssam 		{ RTF_UP,	"UP" },
2099022Ssam 		{ RTF_GATEWAY,	"GATEWAY" },
2109022Ssam 		{ RTF_HOST,	"HOST" },
2119022Ssam 		{ 0 }
2129022Ssam 	}, statebits[] = {
2139022Ssam 		{ RTS_PASSIVE,	"PASSIVE" },
2149022Ssam 		{ RTS_REMOTE,	"REMOTE" },
2159022Ssam 		{ RTS_INTERFACE,"INTERFACE" },
2169022Ssam 		{ RTS_CHANGED,	"CHANGED" },
21728906Skarels 		{ RTS_INTERNAL,	"INTERNAL" },
21828906Skarels 		{ RTS_EXTERNAL,	"EXTERNAL" },
21928906Skarels 		{ RTS_SUBNET,	"SUBNET" },
2209022Ssam 		{ 0 }
2219022Ssam 	};
2229022Ssam 	register struct bits *p;
2239022Ssam 	register int first;
2249022Ssam 	char *cp;
2259022Ssam 	struct interface *ifp;
2269022Ssam 
2279022Ssam 	if (fd == NULL)
2289022Ssam 		return;
229*36831Skarels 	if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
230*36831Skarels 		fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
231*36831Skarels 		lastlog = now;
23234564Skarels 	}
2339022Ssam 	fprintf(fd, "%s ", action);
2349022Ssam 	dst = (struct sockaddr_in *)&rt->rt_dst;
2359022Ssam 	gate = (struct sockaddr_in *)&rt->rt_router;
23615099Ssam 	fprintf(fd, "dst %s, ", inet_ntoa(dst->sin_addr));
23715099Ssam 	fprintf(fd, "router %s, metric %d, flags",
23815099Ssam 	     inet_ntoa(gate->sin_addr), rt->rt_metric);
2399022Ssam 	cp = " %s";
2409022Ssam 	for (first = 1, p = flagbits; p->t_bits > 0; p++) {
2419022Ssam 		if ((rt->rt_flags & p->t_bits) == 0)
2429022Ssam 			continue;
2439022Ssam 		fprintf(fd, cp, p->t_name);
2449022Ssam 		if (first) {
2459022Ssam 			cp = "|%s";
2469022Ssam 			first = 0;
2479022Ssam 		}
2489022Ssam 	}
2499022Ssam 	fprintf(fd, " state");
2509022Ssam 	cp = " %s";
2519022Ssam 	for (first = 1, p = statebits; p->t_bits > 0; p++) {
2529022Ssam 		if ((rt->rt_state & p->t_bits) == 0)
2539022Ssam 			continue;
2549022Ssam 		fprintf(fd, cp, p->t_name);
2559022Ssam 		if (first) {
2569022Ssam 			cp = "|%s";
2579022Ssam 			first = 0;
2589022Ssam 		}
2599022Ssam 	}
26034564Skarels 	fprintf(fd, " timer %d\n", rt->rt_timer);
261*36831Skarels 	if (tracehistory && !tracepackets &&
262*36831Skarels 	    (rt->rt_state & RTS_PASSIVE) == 0 && rt->rt_ifp)
2639022Ssam 		dumpif(fd, rt->rt_ifp);
2649022Ssam 	fflush(fd);
265*36831Skarels 	if (ferror(fd))
266*36831Skarels 		traceoff();
2679022Ssam }
2689022Ssam 
26934564Skarels tracenewmetric(fd, rt, newmetric)
27034564Skarels 	FILE *fd;
27134564Skarels 	struct rt_entry *rt;
27234564Skarels 	int newmetric;
27334564Skarels {
27434564Skarels 	struct sockaddr_in *dst, *gate;
27534564Skarels 
27634564Skarels 	if (fd == NULL)
27734564Skarels 		return;
278*36831Skarels 	if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
279*36831Skarels 		fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
280*36831Skarels 		lastlog = now;
281*36831Skarels 	}
28234564Skarels 	dst = (struct sockaddr_in *)&rt->rt_dst;
28334564Skarels 	gate = (struct sockaddr_in *)&rt->rt_router;
28434564Skarels 	fprintf(fd, "CHANGE metric dst %s, ", inet_ntoa(dst->sin_addr));
28534564Skarels 	fprintf(fd, "router %s, from %d to %d\n",
28634564Skarels 	     inet_ntoa(gate->sin_addr), rt->rt_metric, newmetric);
28734564Skarels 	fflush(fd);
288*36831Skarels 	if (ferror(fd))
289*36831Skarels 		traceoff();
29034564Skarels }
29134564Skarels 
2929022Ssam dumpif(fd, ifp)
293*36831Skarels 	FILE *fd;
2949022Ssam 	register struct interface *ifp;
2959022Ssam {
29616314Skarels 	if (ifp->int_input.ifd_count || ifp->int_output.ifd_count) {
29716314Skarels 		fprintf(fd, "*** Packet history for interface %s ***\n",
29816314Skarels 			ifp->int_name);
29934564Skarels #ifdef notneeded
30016314Skarels 		dumptrace(fd, "to", &ifp->int_output);
30134564Skarels #endif
30216314Skarels 		dumptrace(fd, "from", &ifp->int_input);
30316314Skarels 		fprintf(fd, "*** end packet history ***\n");
30416314Skarels 	}
3059022Ssam }
3069022Ssam 
3079022Ssam dumptrace(fd, dir, ifd)
3089022Ssam 	FILE *fd;
3099022Ssam 	char *dir;
3109022Ssam 	register struct ifdebug *ifd;
3119022Ssam {
3129022Ssam 	register struct iftrace *t;
3139022Ssam 	char *cp = !strcmp(dir, "to") ? "Output" : "Input";
3149022Ssam 
3159022Ssam 	if (ifd->ifd_front == ifd->ifd_records &&
3169022Ssam 	    ifd->ifd_front->ift_size == 0) {
3179022Ssam 		fprintf(fd, "%s: no packets.\n", cp);
31826960Skarels 		fflush(fd);
3199022Ssam 		return;
3209022Ssam 	}
3219022Ssam 	fprintf(fd, "%s trace:\n", cp);
32216314Skarels 	t = ifd->ifd_front - ifd->ifd_count;
32316314Skarels 	if (t < ifd->ifd_records)
32416314Skarels 		t += NRECORDS;
32516314Skarels 	for ( ; ifd->ifd_count; ifd->ifd_count--, t++) {
32616314Skarels 		if (t >= ifd->ifd_records + NRECORDS)
32716314Skarels 			t = ifd->ifd_records;
3289022Ssam 		if (t->ift_size == 0)
3299022Ssam 			continue;
33034564Skarels 		dumppacket(fd, dir, &t->ift_who, t->ift_packet, t->ift_size,
33134564Skarels 		    &t->ift_stamp);
3329022Ssam 	}
3339022Ssam }
3349022Ssam 
335*36831Skarels dumppacket(fd, dir, who, cp, size, stamp)
3369022Ssam 	FILE *fd;
3379022Ssam 	struct sockaddr_in *who;		/* should be sockaddr */
3389022Ssam 	char *dir, *cp;
3399022Ssam 	register int size;
340*36831Skarels 	struct timeval *stamp;
3419022Ssam {
3429022Ssam 	register struct rip *msg = (struct rip *)cp;
3439022Ssam 	register struct netinfo *n;
3449022Ssam 
345*36831Skarels 	if (fd == NULL)
346*36831Skarels 		return;
3479022Ssam 	if (msg->rip_cmd && msg->rip_cmd < RIPCMD_MAX)
348*36831Skarels 		fprintf(fd, "%s %s %s.%d %.19s:\n", ripcmds[msg->rip_cmd],
349*36831Skarels 		    dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port),
350*36831Skarels 		    ctime((time_t *)&stamp->tv_sec));
351*36831Skarels 	else {
352*36831Skarels 		fprintf(fd, "Bad cmd 0x%x %s %x.%d %.19s\n", msg->rip_cmd,
35315099Ssam 		    dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port));
354*36831Skarels 		fprintf(fd, "size=%d cp=%x packet=%x\n", size, cp, packet,
355*36831Skarels 		    ctime((time_t *)&stamp->tv_sec));
35626960Skarels 		fflush(fd);
3579022Ssam 		return;
3589022Ssam 	}
359*36831Skarels 	if (tracepackets && tracecontents == 0) {
360*36831Skarels 		fflush(fd);
361*36831Skarels 		return;
362*36831Skarels 	}
3639022Ssam 	switch (msg->rip_cmd) {
3649022Ssam 
3659022Ssam 	case RIPCMD_REQUEST:
3669022Ssam 	case RIPCMD_RESPONSE:
3679022Ssam 		size -= 4 * sizeof (char);
3689022Ssam 		n = msg->rip_nets;
3699022Ssam 		for (; size > 0; n++, size -= sizeof (struct netinfo)) {
370*36831Skarels 			if (size < sizeof (struct netinfo)) {
371*36831Skarels 				fprintf(fd, "(truncated record, len %d)\n",
372*36831Skarels 				    size);
3739022Ssam 				break;
374*36831Skarels 			}
375*36831Skarels 			if (sizeof(n->rip_dst.sa_family) > 1)
376*36831Skarels 			    n->rip_dst.sa_family = ntohs(n->rip_dst.sa_family);
377*36831Skarels 
378*36831Skarels 			switch ((int)n->rip_dst.sa_family) {
379*36831Skarels 
380*36831Skarels 			case AF_INET:
381*36831Skarels 				fprintf(fd, "\tdst %s metric %d\n",
38215099Ssam #define	satosin(sa)	((struct sockaddr_in *)&sa)
383*36831Skarels 				     inet_ntoa(satosin(n->rip_dst)->sin_addr),
384*36831Skarels 				     ntohl(n->rip_metric));
385*36831Skarels 				break;
386*36831Skarels 
387*36831Skarels 			default:
388*36831Skarels 				fprintf(fd, "\taf %d? metric %d\n",
389*36831Skarels 				     n->rip_dst.sa_family,
390*36831Skarels 				     ntohl(n->rip_metric));
391*36831Skarels 				break;
392*36831Skarels 			}
3939022Ssam 		}
3949022Ssam 		break;
3959022Ssam 
3969022Ssam 	case RIPCMD_TRACEON:
39734564Skarels 		fprintf(fd, "\tfile=%*s\n", size, msg->rip_tracefile);
3989022Ssam 		break;
3999022Ssam 
4009022Ssam 	case RIPCMD_TRACEOFF:
4019022Ssam 		break;
4029022Ssam 	}
40326960Skarels 	fflush(fd);
404*36831Skarels 	if (ferror(fd))
405*36831Skarels 		traceoff();
4069022Ssam }
407