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 /*
36  * Routing Table Management Daemon
37  */
38 #include "defs.h"
39 
40 #define	NRECORDS	50		/* size of circular trace buffer */
41 
42 boolean_t	tracepackets;		/* watch packets as they go by */
43 int		tracing;		/* bitmask: */
44 FILE		*ftrace;		/* output trace file */
45 
46 static int	iftraceinit(struct interface *ifp, struct ifdebug *ifd);
47 static void	dumpif(FILE *fp, struct interface *ifp);
48 static void	dumptrace(FILE *fp, char *dir, struct ifdebug *ifd);
49 
50 void
traceinit(struct interface * ifp)51 traceinit(struct interface *ifp)
52 {
53 	if (iftraceinit(ifp, &ifp->int_input) &&
54 	    iftraceinit(ifp, &ifp->int_output))
55 		return;
56 	tracing = 0;
57 	(void) fprintf(stderr, "traceinit: can't init %s\n",
58 	    (ifp->int_name != NULL) ? ifp->int_name : "(noname)");
59 }
60 
61 static int
iftraceinit(struct interface * ifp,struct ifdebug * ifd)62 iftraceinit(struct interface *ifp, struct ifdebug *ifd)
63 {
64 	struct iftrace *t;
65 
66 	ifd->ifd_records = (struct iftrace *)
67 	    malloc((size_t)NRECORDS * sizeof (struct iftrace));
68 	if (ifd->ifd_records == NULL)
69 		return (0);
70 	ifd->ifd_front = ifd->ifd_records;
71 	ifd->ifd_count = 0;
72 	for (t = ifd->ifd_records; t < ifd->ifd_records + NRECORDS; t++) {
73 		t->ift_size = 0;
74 		t->ift_packet = NULL;
75 	}
76 	ifd->ifd_if = ifp;
77 	return (1);
78 }
79 
80 void
traceon(char * file)81 traceon(char *file)
82 {
83 	struct stat stbuf;
84 
85 	if (ftrace != NULL)
86 		return;
87 	if (stat(file, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) != S_IFREG)
88 		return;
89 	ftrace = fopen(file, "a");
90 	if (ftrace == NULL)
91 		return;
92 	(void) dup2(fileno(ftrace), 1);
93 	(void) dup2(fileno(ftrace), 2);
94 }
95 
96 void
traceonfp(FILE * fp)97 traceonfp(FILE *fp)
98 {
99 	if (ftrace != NULL)
100 		return;
101 	ftrace = fp;
102 	if (ftrace == NULL)
103 		return;
104 	(void) dup2(fileno(ftrace), 1);
105 	(void) dup2(fileno(ftrace), 2);
106 }
107 
108 void
trace(struct ifdebug * ifd,struct sockaddr_in6 * who,char * p,int len,int m)109 trace(struct ifdebug *ifd, struct sockaddr_in6 *who, char *p, int len, int m)
110 {
111 	struct iftrace *t;
112 
113 	if (ifd->ifd_records == 0)
114 		return;
115 	t = ifd->ifd_front++;
116 	if (ifd->ifd_front >= ifd->ifd_records + NRECORDS)
117 		ifd->ifd_front = ifd->ifd_records;
118 	if (ifd->ifd_count < NRECORDS)
119 		ifd->ifd_count++;
120 	if (t->ift_size > 0 && t->ift_size < len && t->ift_packet != NULL) {
121 		free(t->ift_packet);
122 		t->ift_packet = NULL;
123 	}
124 	(void) time(&t->ift_stamp);
125 	t->ift_who = *who;
126 	if (len > 0 && t->ift_packet == NULL) {
127 		t->ift_packet = (char *)malloc((size_t)len);
128 		if (t->ift_packet == NULL)
129 			len = 0;
130 	}
131 	if (len > 0)
132 		bcopy(p, t->ift_packet, len);
133 	t->ift_size = len;
134 	t->ift_metric = m;
135 }
136 
137 void
traceaction(FILE * fp,char * action,struct rt_entry * rt)138 traceaction(FILE *fp, char *action, struct rt_entry *rt)
139 {
140 	static struct bits {
141 		ulong_t	t_bits;
142 		char	*t_name;
143 	} flagbits[] = {
144 		/* BEGIN CSTYLED */
145 		{ RTF_UP,		"UP" },
146 		{ RTF_GATEWAY,		"GATEWAY" },
147 		{ RTF_HOST,		"HOST" },
148 		{ 0,			NULL }
149 		/* END CSTYLED */
150 	}, statebits[] = {
151 		/* BEGIN CSTYLED */
152 		{ RTS_INTERFACE,	"INTERFACE" },
153 		{ RTS_CHANGED,		"CHANGED" },
154 		{ RTS_PRIVATE,		"PRIVATE" },
155 		{ 0,			NULL }
156 		/* END CSTYLED */
157 	};
158 	struct bits *p;
159 	boolean_t first;
160 	char c;
161 	time_t t;
162 
163 	if (fp == NULL)
164 		return;
165 	(void) time(&t);
166 	(void) fprintf(fp, "%.15s %s ", ctime(&t) + 4, action);
167 	if (rt != NULL) {
168 		char buf1[INET6_ADDRSTRLEN];
169 
170 		(void) fprintf(fp, "prefix %s/%d ",
171 		    inet_ntop(AF_INET6, (void *)&rt->rt_dst, buf1,
172 			sizeof (buf1)),
173 		    rt->rt_prefix_length);
174 		(void) fprintf(fp, "via %s metric %d",
175 		    inet_ntop(AF_INET6, (void *)&rt->rt_router, buf1,
176 			sizeof (buf1)),
177 		    rt->rt_metric);
178 		if (rt->rt_ifp != NULL) {
179 			(void) fprintf(fp, " if %s",
180 			    (rt->rt_ifp->int_name != NULL) ?
181 				rt->rt_ifp->int_name : "(noname)");
182 		}
183 		(void) fprintf(fp, " state");
184 		c = ' ';
185 		for (first = _B_TRUE, p = statebits; p->t_bits > 0; p++) {
186 			if ((rt->rt_state & p->t_bits) == 0)
187 				continue;
188 			(void) fprintf(fp, "%c%s", c, p->t_name);
189 			if (first) {
190 				c = '|';
191 				first = _B_FALSE;
192 			}
193 		}
194 		if (first)
195 			(void) fprintf(fp, " 0");
196 		if (rt->rt_flags & (RTF_UP | RTF_GATEWAY)) {
197 			c = ' ';
198 			for (first = _B_TRUE, p = flagbits; p->t_bits > 0;
199 			    p++) {
200 				if ((rt->rt_flags & p->t_bits) == 0)
201 					continue;
202 				(void) fprintf(fp, "%c%s", c, p->t_name);
203 				if (first) {
204 					c = '|';
205 					first = _B_FALSE;
206 				}
207 			}
208 		}
209 	}
210 	(void) putc('\n', fp);
211 	if (!tracepackets && rt != NULL && rt->rt_ifp != NULL)
212 		dumpif(fp, rt->rt_ifp);
213 	(void) fflush(fp);
214 }
215 
216 static void
dumpif(FILE * fp,struct interface * ifp)217 dumpif(FILE *fp, struct interface *ifp)
218 {
219 	if (ifp->int_input.ifd_count != 0 || ifp->int_output.ifd_count != 0) {
220 		(void) fprintf(fp, "*** Packet history for interface %s ***\n",
221 		    (ifp->int_name != NULL) ? ifp->int_name : "(noname)");
222 		dumptrace(fp, "to", &ifp->int_output);
223 		dumptrace(fp, "from", &ifp->int_input);
224 		(void) fprintf(fp, "*** end packet history ***\n");
225 	}
226 	(void) fflush(fp);
227 }
228 
229 static void
dumptrace(FILE * fp,char * dir,struct ifdebug * ifd)230 dumptrace(FILE *fp, char *dir, struct ifdebug *ifd)
231 {
232 	struct iftrace *t;
233 	char *cp = (strcmp(dir, "to") != 0) ? "Output" : "Input";
234 
235 	if (ifd->ifd_front == ifd->ifd_records &&
236 	    ifd->ifd_front->ift_size == 0) {
237 		(void) fprintf(fp, "%s: no packets.\n", cp);
238 		(void) fflush(fp);
239 		return;
240 	}
241 	(void) fprintf(fp, "%s trace:\n", cp);
242 	t = ifd->ifd_front - ifd->ifd_count;
243 	if (t < ifd->ifd_records)
244 		t += NRECORDS;
245 	for (; ifd->ifd_count; ifd->ifd_count--, t++) {
246 		if (t >= ifd->ifd_records + NRECORDS)
247 			t = ifd->ifd_records;
248 		if (t->ift_size == 0)
249 			continue;
250 		(void) fprintf(fp, "%.24s: metric=%d\n", ctime(&t->ift_stamp),
251 		    t->ift_metric);
252 		dumppacket(fp, dir, (struct sockaddr_in6 *)&t->ift_who,
253 		    t->ift_packet, t->ift_size);
254 	}
255 }
256 
257 /*ARGSUSED*/
258 void
dumppacket(FILE * fp,char * dir,struct sockaddr_in6 * who,char * cp,int size)259 dumppacket(FILE *fp, char *dir, struct sockaddr_in6 *who, char *cp, int size)
260 {
261 	/* XXX Output contents of the RIP packet */
262 }
263