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