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