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