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