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