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