]> git.saurik.com Git - apple/network_cmds.git/blob - routed.tproj/trace.c
network_cmds-307.1.1.tar.gz
[apple/network_cmds.git] / routed.tproj / trace.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*
25 * Copyright (c) 1983, 1988, 1993
26 * The Regents of the University of California. All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgment:
38 * This product includes software developed by the University of
39 * California, Berkeley and its contributors.
40 * 4. Neither the name of the University nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 *
56 * @(#)defs.h 8.1 (Berkeley) 6/5/93
57 */
58
59
60 /*
61 * Routing Table Management Daemon
62 */
63 #define RIPCMDS
64 #include "defs.h"
65 #include <sys/stat.h>
66 #include <sys/signal.h>
67 #include <fcntl.h>
68 #include <stdlib.h>
69 #include "pathnames.h"
70
71 #define NRECORDS 50 /* size of circular trace buffer */
72 #ifdef DEBUG
73 FILE *ftrace = stdout;
74 int traceactions = 0;
75 #endif
76 static struct timeval lastlog;
77 static char *savetracename;
78
79 static int iftraceinit();
80
81 void
82 traceinit(ifp)
83 register struct interface *ifp;
84 {
85
86 if (iftraceinit(ifp, &ifp->int_input) &&
87 iftraceinit(ifp, &ifp->int_output))
88 return;
89 tracehistory = 0;
90 fprintf(stderr, "traceinit: can't init %s\n", ifp->int_name);
91 }
92
93
94 static int
95 iftraceinit(ifp, ifd)
96 struct interface *ifp;
97 register struct ifdebug *ifd;
98 {
99 register struct iftrace *t;
100
101 ifd->ifd_records =
102 (struct iftrace *)malloc(NRECORDS * sizeof (struct iftrace));
103 if (ifd->ifd_records == 0)
104 return (0);
105 ifd->ifd_front = ifd->ifd_records;
106 ifd->ifd_count = 0;
107 for (t = ifd->ifd_records; t < ifd->ifd_records + NRECORDS; t++) {
108 t->ift_size = 0;
109 t->ift_packet = 0;
110 }
111 ifd->ifd_if = ifp;
112 return (1);
113 }
114
115 void
116 traceon(file)
117 char *file;
118 {
119 struct stat stbuf;
120
121 if (ftrace != NULL)
122 return;
123 if (stat(file, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) != S_IFREG)
124 return;
125 savetracename = file;
126 (void) gettimeofday(&now, (struct timezone *)NULL);
127 ftrace = fopen(file, "a");
128 if (ftrace == NULL)
129 return;
130 dup2(fileno(ftrace), 1);
131 dup2(fileno(ftrace), 2);
132 traceactions = 1;
133 fprintf(ftrace, "Tracing enabled %s\n", ctime((time_t *)&now.tv_sec));
134 }
135
136 void
137 traceoff()
138 {
139 if (!traceactions)
140 return;
141 if (ftrace != NULL) {
142 int fd = open(_PATH_DEVNULL, O_RDWR);
143
144 fprintf(ftrace, "Tracing disabled %s\n",
145 ctime((time_t *)&now.tv_sec));
146 fflush(ftrace);
147 (void) dup2(fd, 1);
148 (void) dup2(fd, 2);
149 (void) close(fd);
150 fclose(ftrace);
151 ftrace = NULL;
152 }
153 traceactions = 0;
154 tracehistory = 0;
155 tracepackets = 0;
156 tracecontents = 0;
157 }
158
159 void
160 sigtrace(s)
161 int s;
162 {
163
164 if (s == SIGUSR2)
165 traceoff();
166 else if (ftrace == NULL && savetracename)
167 traceon(savetracename);
168 else
169 bumploglevel();
170 }
171
172 /*
173 * Move to next higher level of tracing when -t option processed or
174 * SIGUSR1 is received. Successive levels are:
175 * traceactions
176 * traceactions + tracepackets
177 * traceactions + tracehistory (packets and contents after change)
178 * traceactions + tracepackets + tracecontents
179 */
180 void
181 bumploglevel()
182 {
183
184 (void) gettimeofday(&now, (struct timezone *)NULL);
185 if (traceactions == 0) {
186 traceactions++;
187 if (ftrace)
188 fprintf(ftrace, "Tracing actions started %s\n",
189 ctime((time_t *)&now.tv_sec));
190 } else if (tracepackets == 0) {
191 tracepackets++;
192 tracehistory = 0;
193 tracecontents = 0;
194 if (ftrace)
195 fprintf(ftrace, "Tracing packets started %s\n",
196 ctime((time_t *)&now.tv_sec));
197 } else if (tracehistory == 0) {
198 tracehistory++;
199 if (ftrace)
200 fprintf(ftrace, "Tracing history started %s\n",
201 ctime((time_t *)&now.tv_sec));
202 } else {
203 tracepackets++;
204 tracecontents++;
205 tracehistory = 0;
206 if (ftrace)
207 fprintf(ftrace, "Tracing packet contents started %s\n",
208 ctime((time_t *)&now.tv_sec));
209 }
210 if (ftrace)
211 fflush(ftrace);
212 }
213
214 void
215 trace(ifd, who, p, len, m)
216 register struct ifdebug *ifd;
217 struct sockaddr *who;
218 char *p;
219 int len, m;
220 {
221 register struct iftrace *t;
222
223 if (ifd->ifd_records == 0)
224 return;
225 t = ifd->ifd_front++;
226 if (ifd->ifd_front >= ifd->ifd_records + NRECORDS)
227 ifd->ifd_front = ifd->ifd_records;
228 if (ifd->ifd_count < NRECORDS)
229 ifd->ifd_count++;
230 if (t->ift_size > 0 && t->ift_size < len && t->ift_packet) {
231 free(t->ift_packet);
232 t->ift_packet = 0;
233 }
234 t->ift_stamp = now;
235 t->ift_who = *who;
236 if (len > 0 && t->ift_packet == 0) {
237 t->ift_packet = malloc(len);
238 if (t->ift_packet == 0)
239 len = 0;
240 }
241 if (len > 0)
242 memmove(t->ift_packet, p, len);
243 t->ift_size = len;
244 t->ift_metric = m;
245 }
246
247 void
248 traceaction(fd, action, rt)
249 FILE *fd;
250 char *action;
251 struct rt_entry *rt;
252 {
253 struct sockaddr_in *dst, *gate;
254 static struct bits {
255 int t_bits;
256 char *t_name;
257 } flagbits[] = {
258 { RTF_UP, "UP" },
259 { RTF_GATEWAY, "GATEWAY" },
260 { RTF_HOST, "HOST" },
261 { 0 }
262 }, statebits[] = {
263 { RTS_PASSIVE, "PASSIVE" },
264 { RTS_REMOTE, "REMOTE" },
265 { RTS_INTERFACE,"INTERFACE" },
266 { RTS_CHANGED, "CHANGED" },
267 { RTS_INTERNAL, "INTERNAL" },
268 { RTS_EXTERNAL, "EXTERNAL" },
269 { RTS_SUBNET, "SUBNET" },
270 { 0 }
271 };
272 register struct bits *p;
273 register int first;
274 char *cp;
275
276 if (fd == NULL)
277 return;
278 if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
279 fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
280 lastlog = now;
281 }
282 fprintf(fd, "%s ", action);
283 dst = (struct sockaddr_in *)&rt->rt_dst;
284 gate = (struct sockaddr_in *)&rt->rt_router;
285 fprintf(fd, "dst %s, ", inet_ntoa(dst->sin_addr));
286 fprintf(fd, "router %s, metric %d, flags",
287 inet_ntoa(gate->sin_addr), rt->rt_metric);
288 cp = " %s";
289 for (first = 1, p = flagbits; p->t_bits > 0; p++) {
290 if ((rt->rt_flags & p->t_bits) == 0)
291 continue;
292 fprintf(fd, cp, p->t_name);
293 if (first) {
294 cp = "|%s";
295 first = 0;
296 }
297 }
298 fprintf(fd, " state");
299 cp = " %s";
300 for (first = 1, p = statebits; p->t_bits > 0; p++) {
301 if ((rt->rt_state & p->t_bits) == 0)
302 continue;
303 fprintf(fd, cp, p->t_name);
304 if (first) {
305 cp = "|%s";
306 first = 0;
307 }
308 }
309 fprintf(fd, " timer %d\n", rt->rt_timer);
310 if (tracehistory && !tracepackets &&
311 (rt->rt_state & RTS_PASSIVE) == 0 && rt->rt_ifp)
312 dumpif(fd, rt->rt_ifp);
313 fflush(fd);
314 if (ferror(fd))
315 traceoff();
316 }
317
318 void
319 tracenewmetric(fd, rt, newmetric)
320 FILE *fd;
321 struct rt_entry *rt;
322 int newmetric;
323 {
324 struct sockaddr_in *dst, *gate;
325
326 if (fd == NULL)
327 return;
328 if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
329 fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
330 lastlog = now;
331 }
332 dst = (struct sockaddr_in *)&rt->rt_dst;
333 gate = (struct sockaddr_in *)&rt->rt_router;
334 fprintf(fd, "CHANGE metric dst %s, ", inet_ntoa(dst->sin_addr));
335 fprintf(fd, "router %s, from %d to %d\n",
336 inet_ntoa(gate->sin_addr), rt->rt_metric, newmetric);
337 fflush(fd);
338 if (ferror(fd))
339 traceoff();
340 }
341
342 void
343 dumpif(fd, ifp)
344 FILE *fd;
345 register struct interface *ifp;
346 {
347 if (ifp->int_input.ifd_count || ifp->int_output.ifd_count) {
348 fprintf(fd, "*** Packet history for interface %s ***\n",
349 ifp->int_name);
350 #ifdef notneeded
351 dumptrace(fd, "to", &ifp->int_output);
352 #endif
353 dumptrace(fd, "from", &ifp->int_input);
354 fprintf(fd, "*** end packet history ***\n");
355 }
356 }
357
358 void
359 dumptrace(fd, dir, ifd)
360 FILE *fd;
361 char *dir;
362 register struct ifdebug *ifd;
363 {
364 register struct iftrace *t;
365 char *cp = !strcmp(dir, "to") ? "Output" : "Input";
366
367 if (ifd->ifd_front == ifd->ifd_records &&
368 ifd->ifd_front->ift_size == 0) {
369 fprintf(fd, "%s: no packets.\n", cp);
370 fflush(fd);
371 return;
372 }
373 fprintf(fd, "%s trace:\n", cp);
374 t = ifd->ifd_front - ifd->ifd_count;
375 if (t < ifd->ifd_records)
376 t += NRECORDS;
377 for ( ; ifd->ifd_count; ifd->ifd_count--, t++) {
378 if (t >= ifd->ifd_records + NRECORDS)
379 t = ifd->ifd_records;
380 if (t->ift_size == 0)
381 continue;
382 dumppacket(fd, dir, (struct sockaddr_in *)&t->ift_who, t->ift_packet, t->ift_size,
383 &t->ift_stamp);
384 }
385 }
386
387 void
388 dumppacket(fd, dir, who, cp, size, stamp)
389 FILE *fd;
390 struct sockaddr_in *who; /* should be sockaddr */
391 char *dir, *cp;
392 register int size;
393 struct timeval *stamp;
394 {
395 register struct rip *msg = (struct rip *)cp;
396 register struct netinfo *n;
397
398 if (fd == NULL)
399 return;
400 if (msg->rip_cmd && msg->rip_cmd < RIPCMD_MAX)
401 fprintf(fd, "%s %s %s.%d %.19s:\n", ripcmds[msg->rip_cmd],
402 dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port),
403 ctime((time_t *)&stamp->tv_sec));
404 else {
405 fprintf(fd, "Bad cmd 0x%x %s %s.%d\n", msg->rip_cmd,
406 dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port));
407 fprintf(fd, "size=%d cp=%s packet=%s %.19s\n", size, cp, packet,
408 ctime((time_t *)&stamp->tv_sec));
409 fflush(fd);
410 return;
411 }
412 if (tracepackets && tracecontents == 0) {
413 fflush(fd);
414 return;
415 }
416 switch (msg->rip_cmd) {
417
418 case RIPCMD_REQUEST:
419 case RIPCMD_RESPONSE:
420 size -= 4 * sizeof (char);
421 n = msg->rip_nets;
422 for (; size > 0; n++, size -= sizeof (struct netinfo)) {
423 if (size < sizeof (struct netinfo)) {
424 fprintf(fd, "(truncated record, len %d)\n",
425 size);
426 break;
427 }
428 if (sizeof(n->rip_dst.sa_family) > 1)
429 n->rip_dst.sa_family = ntohs(n->rip_dst.sa_family);
430
431 switch ((int)n->rip_dst.sa_family) {
432
433 case AF_INET:
434 fprintf(fd, "\tdst %s metric %d\n",
435 #define satosin(sa) ((struct sockaddr_in *)&sa)
436 inet_ntoa(satosin(n->rip_dst)->sin_addr),
437 ntohl(n->rip_metric));
438 break;
439
440 default:
441 fprintf(fd, "\taf %d? metric %d\n",
442 n->rip_dst.sa_family,
443 ntohl(n->rip_metric));
444 break;
445 }
446 }
447 break;
448
449 case RIPCMD_TRACEON:
450 fprintf(fd, "\tfile=%*s\n", size, msg->rip_tracefile);
451 break;
452
453 case RIPCMD_TRACEOFF:
454 break;
455 }
456 fflush(fd);
457 if (ferror(fd))
458 traceoff();
459 }