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