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