1 /* 2 * Copyright (c) 1983, 1988 Regents of the University of California. 3 * 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[] = "@(#)trace.c 5.11 (Berkeley) 2/28/91"; 36 static char rcsid[] = "$Header: /cvsroot/src/sbin/routed/trace.c,v 1.3 1993/03/23 00:30:48 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 traceinit(ifp) 59 register struct interface *ifp; 60 { 61 static int iftraceinit(); 62 63 if (iftraceinit(ifp, &ifp->int_input) && 64 iftraceinit(ifp, &ifp->int_output)) 65 return; 66 tracehistory = 0; 67 fprintf(stderr, "traceinit: can't init %s\n", ifp->int_name); 68 } 69 70 static 71 iftraceinit(ifp, ifd) 72 struct interface *ifp; 73 register struct ifdebug *ifd; 74 { 75 register struct iftrace *t; 76 77 ifd->ifd_records = 78 (struct iftrace *)malloc(NRECORDS * sizeof (struct iftrace)); 79 if (ifd->ifd_records == 0) 80 return (0); 81 ifd->ifd_front = ifd->ifd_records; 82 ifd->ifd_count = 0; 83 for (t = ifd->ifd_records; t < ifd->ifd_records + NRECORDS; t++) { 84 t->ift_size = 0; 85 t->ift_packet = 0; 86 } 87 ifd->ifd_if = ifp; 88 return (1); 89 } 90 91 traceon(file) 92 char *file; 93 { 94 struct stat stbuf; 95 96 if (ftrace != NULL) 97 return; 98 if (stat(file, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) != S_IFREG) 99 return; 100 savetracename = file; 101 (void) gettimeofday(&now, (struct timezone *)NULL); 102 ftrace = fopen(file, "a"); 103 if (ftrace == NULL) 104 return; 105 dup2(fileno(ftrace), 1); 106 dup2(fileno(ftrace), 2); 107 traceactions = 1; 108 fprintf(ftrace, "Tracing enabled %s\n", ctime((time_t *)&now.tv_sec)); 109 } 110 111 traceoff() 112 { 113 if (!traceactions) 114 return; 115 if (ftrace != NULL) { 116 int fd = open(_PATH_DEVNULL, O_RDWR); 117 118 fprintf(ftrace, "Tracing disabled %s\n", 119 ctime((time_t *)&now.tv_sec)); 120 fflush(ftrace); 121 (void) dup2(fd, 1); 122 (void) dup2(fd, 2); 123 (void) close(fd); 124 fclose(ftrace); 125 ftrace = NULL; 126 } 127 traceactions = 0; 128 tracehistory = 0; 129 tracepackets = 0; 130 tracecontents = 0; 131 } 132 133 void 134 sigtrace(s) 135 int s; 136 { 137 138 if (s == SIGUSR2) 139 traceoff(); 140 else if (ftrace == NULL && savetracename) 141 traceon(savetracename); 142 else 143 bumploglevel(); 144 } 145 146 /* 147 * Move to next higher level of tracing when -t option processed or 148 * SIGUSR1 is received. Successive levels are: 149 * traceactions 150 * traceactions + tracepackets 151 * traceactions + tracehistory (packets and contents after change) 152 * traceactions + tracepackets + tracecontents 153 */ 154 bumploglevel() 155 { 156 157 (void) gettimeofday(&now, (struct timezone *)NULL); 158 if (traceactions == 0) { 159 traceactions++; 160 if (ftrace) 161 fprintf(ftrace, "Tracing actions started %s\n", 162 ctime((time_t *)&now.tv_sec)); 163 } else if (tracepackets == 0) { 164 tracepackets++; 165 tracehistory = 0; 166 tracecontents = 0; 167 if (ftrace) 168 fprintf(ftrace, "Tracing packets started %s\n", 169 ctime((time_t *)&now.tv_sec)); 170 } else if (tracehistory == 0) { 171 tracehistory++; 172 if (ftrace) 173 fprintf(ftrace, "Tracing history started %s\n", 174 ctime((time_t *)&now.tv_sec)); 175 } else { 176 tracepackets++; 177 tracecontents++; 178 tracehistory = 0; 179 if (ftrace) 180 fprintf(ftrace, "Tracing packet contents started %s\n", 181 ctime((time_t *)&now.tv_sec)); 182 } 183 if (ftrace) 184 fflush(ftrace); 185 } 186 187 trace(ifd, who, p, len, m) 188 register struct ifdebug *ifd; 189 struct sockaddr *who; 190 char *p; 191 int len, m; 192 { 193 register struct iftrace *t; 194 195 if (ifd->ifd_records == 0) 196 return; 197 t = ifd->ifd_front++; 198 if (ifd->ifd_front >= ifd->ifd_records + NRECORDS) 199 ifd->ifd_front = ifd->ifd_records; 200 if (ifd->ifd_count < NRECORDS) 201 ifd->ifd_count++; 202 if (t->ift_size > 0 && t->ift_size < len && t->ift_packet) { 203 free(t->ift_packet); 204 t->ift_packet = 0; 205 } 206 t->ift_stamp = now; 207 t->ift_who = *who; 208 if (len > 0 && t->ift_packet == 0) { 209 t->ift_packet = malloc(len); 210 if (t->ift_packet == 0) 211 len = 0; 212 } 213 if (len > 0) 214 bcopy(p, t->ift_packet, len); 215 t->ift_size = len; 216 t->ift_metric = m; 217 } 218 219 traceaction(fd, action, rt) 220 FILE *fd; 221 char *action; 222 struct rt_entry *rt; 223 { 224 struct sockaddr_in *dst, *gate; 225 static struct bits { 226 int t_bits; 227 char *t_name; 228 } flagbits[] = { 229 { RTF_UP, "UP" }, 230 { RTF_GATEWAY, "GATEWAY" }, 231 { RTF_HOST, "HOST" }, 232 { 0 } 233 }, statebits[] = { 234 { RTS_PASSIVE, "PASSIVE" }, 235 { RTS_REMOTE, "REMOTE" }, 236 { RTS_INTERFACE,"INTERFACE" }, 237 { RTS_CHANGED, "CHANGED" }, 238 { RTS_INTERNAL, "INTERNAL" }, 239 { RTS_EXTERNAL, "EXTERNAL" }, 240 { RTS_SUBNET, "SUBNET" }, 241 { 0 } 242 }; 243 register struct bits *p; 244 register int first; 245 char *cp; 246 struct interface *ifp; 247 248 if (fd == NULL) 249 return; 250 if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) { 251 fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec)); 252 lastlog = now; 253 } 254 fprintf(fd, "%s ", action); 255 dst = (struct sockaddr_in *)&rt->rt_dst; 256 gate = (struct sockaddr_in *)&rt->rt_router; 257 fprintf(fd, "dst %s, ", inet_ntoa(dst->sin_addr)); 258 fprintf(fd, "router %s, metric %d, flags", 259 inet_ntoa(gate->sin_addr), rt->rt_metric); 260 cp = " %s"; 261 for (first = 1, p = flagbits; p->t_bits > 0; p++) { 262 if ((rt->rt_flags & p->t_bits) == 0) 263 continue; 264 fprintf(fd, cp, p->t_name); 265 if (first) { 266 cp = "|%s"; 267 first = 0; 268 } 269 } 270 fprintf(fd, " state"); 271 cp = " %s"; 272 for (first = 1, p = statebits; p->t_bits > 0; p++) { 273 if ((rt->rt_state & p->t_bits) == 0) 274 continue; 275 fprintf(fd, cp, p->t_name); 276 if (first) { 277 cp = "|%s"; 278 first = 0; 279 } 280 } 281 fprintf(fd, " timer %d\n", rt->rt_timer); 282 if (tracehistory && !tracepackets && 283 (rt->rt_state & RTS_PASSIVE) == 0 && rt->rt_ifp) 284 dumpif(fd, rt->rt_ifp); 285 fflush(fd); 286 if (ferror(fd)) 287 traceoff(); 288 } 289 290 tracenewmetric(fd, rt, newmetric) 291 FILE *fd; 292 struct rt_entry *rt; 293 int newmetric; 294 { 295 struct sockaddr_in *dst, *gate; 296 297 if (fd == NULL) 298 return; 299 if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) { 300 fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec)); 301 lastlog = now; 302 } 303 dst = (struct sockaddr_in *)&rt->rt_dst; 304 gate = (struct sockaddr_in *)&rt->rt_router; 305 fprintf(fd, "CHANGE metric dst %s, ", inet_ntoa(dst->sin_addr)); 306 fprintf(fd, "router %s, from %d to %d\n", 307 inet_ntoa(gate->sin_addr), rt->rt_metric, newmetric); 308 fflush(fd); 309 if (ferror(fd)) 310 traceoff(); 311 } 312 313 dumpif(fd, ifp) 314 FILE *fd; 315 register struct interface *ifp; 316 { 317 if (ifp->int_input.ifd_count || ifp->int_output.ifd_count) { 318 fprintf(fd, "*** Packet history for interface %s ***\n", 319 ifp->int_name); 320 #ifdef notneeded 321 dumptrace(fd, "to", &ifp->int_output); 322 #endif 323 dumptrace(fd, "from", &ifp->int_input); 324 fprintf(fd, "*** end packet history ***\n"); 325 } 326 } 327 328 dumptrace(fd, dir, ifd) 329 FILE *fd; 330 char *dir; 331 register struct ifdebug *ifd; 332 { 333 register struct iftrace *t; 334 char *cp = !strcmp(dir, "to") ? "Output" : "Input"; 335 336 if (ifd->ifd_front == ifd->ifd_records && 337 ifd->ifd_front->ift_size == 0) { 338 fprintf(fd, "%s: no packets.\n", cp); 339 fflush(fd); 340 return; 341 } 342 fprintf(fd, "%s trace:\n", cp); 343 t = ifd->ifd_front - ifd->ifd_count; 344 if (t < ifd->ifd_records) 345 t += NRECORDS; 346 for ( ; ifd->ifd_count; ifd->ifd_count--, t++) { 347 if (t >= ifd->ifd_records + NRECORDS) 348 t = ifd->ifd_records; 349 if (t->ift_size == 0) 350 continue; 351 dumppacket(fd, dir, &t->ift_who, t->ift_packet, t->ift_size, 352 &t->ift_stamp); 353 } 354 } 355 356 dumppacket(fd, dir, who, cp, size, stamp) 357 FILE *fd; 358 struct sockaddr_in *who; /* should be sockaddr */ 359 char *dir, *cp; 360 register int size; 361 struct timeval *stamp; 362 { 363 register struct rip *msg = (struct rip *)cp; 364 register struct netinfo *n; 365 366 if (fd == NULL) 367 return; 368 if (msg->rip_cmd && msg->rip_cmd < RIPCMD_MAX) 369 fprintf(fd, "%s %s %s.%d %.19s:\n", ripcmds[msg->rip_cmd], 370 dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port), 371 ctime((time_t *)&stamp->tv_sec)); 372 else { 373 fprintf(fd, "Bad cmd 0x%x %s %x.%d %.19s\n", msg->rip_cmd, 374 dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port)); 375 fprintf(fd, "size=%d cp=%x packet=%x\n", size, cp, packet, 376 ctime((time_t *)&stamp->tv_sec)); 377 fflush(fd); 378 return; 379 } 380 if (tracepackets && tracecontents == 0) { 381 fflush(fd); 382 return; 383 } 384 switch (msg->rip_cmd) { 385 386 case RIPCMD_REQUEST: 387 case RIPCMD_RESPONSE: 388 size -= 4 * sizeof (char); 389 n = msg->rip_nets; 390 for (; size > 0; n++, size -= sizeof (struct netinfo)) { 391 if (size < sizeof (struct netinfo)) { 392 fprintf(fd, "(truncated record, len %d)\n", 393 size); 394 break; 395 } 396 if (sizeof(n->rip_dst.sa_family) > 1) 397 n->rip_dst.sa_family = ntohs(n->rip_dst.sa_family); 398 399 switch ((int)n->rip_dst.sa_family) { 400 401 case AF_INET: 402 fprintf(fd, "\tdst %s metric %d\n", 403 #define satosin(sa) ((struct sockaddr_in *)&sa) 404 inet_ntoa(satosin(n->rip_dst)->sin_addr), 405 ntohl(n->rip_metric)); 406 break; 407 408 default: 409 fprintf(fd, "\taf %d? metric %d\n", 410 n->rip_dst.sa_family, 411 ntohl(n->rip_metric)); 412 break; 413 } 414 } 415 break; 416 417 case RIPCMD_TRACEON: 418 fprintf(fd, "\tfile=%*s\n", size, msg->rip_tracefile); 419 break; 420 421 case RIPCMD_TRACEOFF: 422 break; 423 } 424 fflush(fd); 425 if (ferror(fd)) 426 traceoff(); 427 } 428