1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * Portions of this source code were derived from Berkeley 4.3 BSD
32  * under license from the Regents of the University of California.
33  */
34 
35 #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.1	*/
36 
37 /*
38  * Routing Table Management Daemon
39  */
40 #include "defs.h"
41 
42 #define	NRECORDS	50		/* size of circular trace buffer */
43 
44 boolean_t	tracepackets;		/* watch packets as they go by */
45 int		tracing;		/* bitmask: */
46 FILE		*ftrace;		/* output trace file */
47 
48 static int	iftraceinit(struct interface *ifp, struct ifdebug *ifd);
49 static void	dumpif(FILE *fp, struct interface *ifp);
50 static void	dumptrace(FILE *fp, char *dir, struct ifdebug *ifd);
51 
52 void
traceinit(struct interface * ifp)53 traceinit(struct interface *ifp)
54 {
55 	if (iftraceinit(ifp, &ifp->int_input) &&
56 	    iftraceinit(ifp, &ifp->int_output))
57 		return;
58 	tracing = 0;
59 	(void) fprintf(stderr, "traceinit: can't init %s\n",
60 	    (ifp->int_name != NULL) ? ifp->int_name : "(noname)");
61 }
62 
63 static int
iftraceinit(struct interface * ifp,struct ifdebug * ifd)64 iftraceinit(struct interface *ifp, struct ifdebug *ifd)
65 {
66 	struct iftrace *t;
67 
68 	ifd->ifd_records = (struct iftrace *)
69 	    malloc((size_t)NRECORDS * sizeof (struct iftrace));
70 	if (ifd->ifd_records == NULL)
71 		return (0);
72 	ifd->ifd_front = ifd->ifd_records;
73 	ifd->ifd_count = 0;
74 	for (t = ifd->ifd_records; t < ifd->ifd_records + NRECORDS; t++) {
75 		t->ift_size = 0;
76 		t->ift_packet = NULL;
77 	}
78 	ifd->ifd_if = ifp;
79 	return (1);
80 }
81 
82 void
traceon(char * file)83 traceon(char *file)
84 {
85 	struct stat stbuf;
86 
87 	if (ftrace != NULL)
88 		return;
89 	if (stat(file, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) != S_IFREG)
90 		return;
91 	ftrace = fopen(file, "a");
92 	if (ftrace == NULL)
93 		return;
94 	(void) dup2(fileno(ftrace), 1);
95 	(void) dup2(fileno(ftrace), 2);
96 }
97 
98 void
traceonfp(FILE * fp)99 traceonfp(FILE *fp)
100 {
101 	if (ftrace != NULL)
102 		return;
103 	ftrace = fp;
104 	if (ftrace == NULL)
105 		return;
106 	(void) dup2(fileno(ftrace), 1);
107 	(void) dup2(fileno(ftrace), 2);
108 }
109 
110 void
trace(struct ifdebug * ifd,struct sockaddr_in6 * who,char * p,int len,int m)111 trace(struct ifdebug *ifd, struct sockaddr_in6 *who, char *p, int len, int m)
112 {
113 	struct iftrace *t;
114 
115 	if (ifd->ifd_records == 0)
116 		return;
117 	t = ifd->ifd_front++;
118 	if (ifd->ifd_front >= ifd->ifd_records + NRECORDS)
119 		ifd->ifd_front = ifd->ifd_records;
120 	if (ifd->ifd_count < NRECORDS)
121 		ifd->ifd_count++;
122 	if (t->ift_size > 0 && t->ift_size < len && t->ift_packet != NULL) {
123 		free(t->ift_packet);
124 		t->ift_packet = NULL;
125 	}
126 	(void) time(&t->ift_stamp);
127 	t->ift_who = *who;
128 	if (len > 0 && t->ift_packet == NULL) {
129 		t->ift_packet = (char *)malloc((size_t)len);
130 		if (t->ift_packet == NULL)
131 			len = 0;
132 	}
133 	if (len > 0)
134 		bcopy(p, t->ift_packet, len);
135 	t->ift_size = len;
136 	t->ift_metric = m;
137 }
138 
139 void
traceaction(FILE * fp,char * action,struct rt_entry * rt)140 traceaction(FILE *fp, char *action, struct rt_entry *rt)
141 {
142 	static struct bits {
143 		ulong_t	t_bits;
144 		char	*t_name;
145 	} flagbits[] = {
146 		/* BEGIN CSTYLED */
147 		{ RTF_UP,		"UP" },
148 		{ RTF_GATEWAY,		"GATEWAY" },
149 		{ RTF_HOST,		"HOST" },
150 		{ 0,			NULL }
151 		/* END CSTYLED */
152 	}, statebits[] = {
153 		/* BEGIN CSTYLED */
154 		{ RTS_INTERFACE,	"INTERFACE" },
155 		{ RTS_CHANGED,		"CHANGED" },
156 		{ RTS_PRIVATE,		"PRIVATE" },
157 		{ 0,			NULL }
158 		/* END CSTYLED */
159 	};
160 	struct bits *p;
161 	boolean_t first;
162 	char c;
163 	time_t t;
164 
165 	if (fp == NULL)
166 		return;
167 	(void) time(&t);
168 	(void) fprintf(fp, "%.15s %s ", ctime(&t) + 4, action);
169 	if (rt != NULL) {
170 		char buf1[INET6_ADDRSTRLEN];
171 
172 		(void) fprintf(fp, "prefix %s/%d ",
173 		    inet_ntop(AF_INET6, (void *)&rt->rt_dst, buf1,
174 			sizeof (buf1)),
175 		    rt->rt_prefix_length);
176 		(void) fprintf(fp, "via %s metric %d",
177 		    inet_ntop(AF_INET6, (void *)&rt->rt_router, buf1,
178 			sizeof (buf1)),
179 		    rt->rt_metric);
180 		if (rt->rt_ifp != NULL) {
181 			(void) fprintf(fp, " if %s",
182 			    (rt->rt_ifp->int_name != NULL) ?
183 				rt->rt_ifp->int_name : "(noname)");
184 		}
185 		(void) fprintf(fp, " state");
186 		c = ' ';
187 		for (first = _B_TRUE, p = statebits; p->t_bits > 0; p++) {
188 			if ((rt->rt_state & p->t_bits) == 0)
189 				continue;
190 			(void) fprintf(fp, "%c%s", c, p->t_name);
191 			if (first) {
192 				c = '|';
193 				first = _B_FALSE;
194 			}
195 		}
196 		if (first)
197 			(void) fprintf(fp, " 0");
198 		if (rt->rt_flags & (RTF_UP | RTF_GATEWAY)) {
199 			c = ' ';
200 			for (first = _B_TRUE, p = flagbits; p->t_bits > 0;
201 			    p++) {
202 				if ((rt->rt_flags & p->t_bits) == 0)
203 					continue;
204 				(void) fprintf(fp, "%c%s", c, p->t_name);
205 				if (first) {
206 					c = '|';
207 					first = _B_FALSE;
208 				}
209 			}
210 		}
211 	}
212 	(void) putc('\n', fp);
213 	if (!tracepackets && rt != NULL && rt->rt_ifp != NULL)
214 		dumpif(fp, rt->rt_ifp);
215 	(void) fflush(fp);
216 }
217 
218 static void
dumpif(FILE * fp,struct interface * ifp)219 dumpif(FILE *fp, struct interface *ifp)
220 {
221 	if (ifp->int_input.ifd_count != 0 || ifp->int_output.ifd_count != 0) {
222 		(void) fprintf(fp, "*** Packet history for interface %s ***\n",
223 		    (ifp->int_name != NULL) ? ifp->int_name : "(noname)");
224 		dumptrace(fp, "to", &ifp->int_output);
225 		dumptrace(fp, "from", &ifp->int_input);
226 		(void) fprintf(fp, "*** end packet history ***\n");
227 	}
228 	(void) fflush(fp);
229 }
230 
231 static void
dumptrace(FILE * fp,char * dir,struct ifdebug * ifd)232 dumptrace(FILE *fp, char *dir, struct ifdebug *ifd)
233 {
234 	struct iftrace *t;
235 	char *cp = (strcmp(dir, "to") != 0) ? "Output" : "Input";
236 
237 	if (ifd->ifd_front == ifd->ifd_records &&
238 	    ifd->ifd_front->ift_size == 0) {
239 		(void) fprintf(fp, "%s: no packets.\n", cp);
240 		(void) fflush(fp);
241 		return;
242 	}
243 	(void) fprintf(fp, "%s trace:\n", cp);
244 	t = ifd->ifd_front - ifd->ifd_count;
245 	if (t < ifd->ifd_records)
246 		t += NRECORDS;
247 	for (; ifd->ifd_count; ifd->ifd_count--, t++) {
248 		if (t >= ifd->ifd_records + NRECORDS)
249 			t = ifd->ifd_records;
250 		if (t->ift_size == 0)
251 			continue;
252 		(void) fprintf(fp, "%.24s: metric=%d\n", ctime(&t->ift_stamp),
253 		    t->ift_metric);
254 		dumppacket(fp, dir, (struct sockaddr_in6 *)&t->ift_who,
255 		    t->ift_packet, t->ift_size);
256 	}
257 }
258 
259 /*ARGSUSED*/
260 void
dumppacket(FILE * fp,char * dir,struct sockaddr_in6 * who,char * cp,int size)261 dumppacket(FILE *fp, char *dir, struct sockaddr_in6 *who, char *cp, int size)
262 {
263 	/* XXX Output contents of the RIP packet */
264 }
265