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