/* * Copyright (c) 1983, 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint char copyright[] = "@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\ All rights reserved.\n"; #endif /* not lint */ #ifndef lint /*static char sccsid[] = "from: @(#)trpt.c 5.14 (Berkeley) 7/1/91";*/ static char rcsid[] = "$Id: trpt.c,v 1.5 1997/01/15 23:44:26 millert Exp $"; #endif /* not lint */ #include #include #if BSD >= 199103 #define NEWVM #endif #ifndef NEWVM #include #include #endif #include #include #define PRUREQUESTS #include #include #include #include #include #include #include #include #include #include #define TCPSTATES #include #include #define TCPTIMERS #include #include #include #define TANAMES #include #include #include #include #include #include struct nlist nl[] = { #define N_TCP_DEBUG 0 { "_tcp_debug" }, #define N_TCP_DEBX 1 { "_tcp_debx" }, #ifndef NEWVM #define N_SYSMAP 2 { "_Sysmap" }, #define N_SYSSIZE 3 { "_Syssize" }, #endif { "" }, }; #ifndef NEWVM static struct pte *Sysmap; #endif static caddr_t tcp_pcbs[TCP_NDEBUG]; static n_time ntime; static int aflag, kflag, memf, follow, sflag, tflag; main(argc, argv) int argc; char **argv; { extern char *optarg; extern int optind; int ch, i, jflag, npcbs, numeric(); char *system, *core, *malloc(); off_t lseek(); jflag = npcbs = 0; while ((ch = getopt(argc, argv, "afjp:st")) != -1) switch (ch) { case 'a': ++aflag; break; case 'f': ++follow; setlinebuf(stdout); break; case 'j': ++jflag; break; case 'p': if (npcbs >= TCP_NDEBUG) { fputs("trpt: too many pcb's specified\n", stderr); exit(1); } (void)sscanf(optarg, "%x", (int *)&tcp_pcbs[npcbs++]); break; case 's': ++sflag; break; case 't': ++tflag; break; case '?': default: (void)fprintf(stderr, "usage: trpt [-afjst] [-p hex-address] [system [core]]\n"); exit(1); } argc -= optind; argv += optind; core = _PATH_KMEM; if (argc > 0) { system = *argv; argc--, argv++; if (argc > 0) { core = *argv; argc--, argv++; ++kflag; } } else system = _PATH_UNIX; /* * Discard setgid priviledges if not the running kernel so that bad * guys can't print interesting stuff from kernel memory. */ if (!strcmp(core, _PATH_KMEM) || !strcmp(system, _PATH_UNIX)) { setegid(getgid()); setgid(getgid()); } if (nlist(system, nl) < 0 || !nl[0].n_value) { fprintf(stderr, "trpt: %s: no namelist\n", system); exit(1); } if ((memf = open(core, O_RDONLY)) < 0) { perror(core); exit(2); } if (kflag) { #ifdef NEWVM fputs("trpt: can't do core files yet\n", stderr); exit(1); #else off_t off; Sysmap = (struct pte *) malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte))); if (!Sysmap) { fputs("trpt: can't get memory for Sysmap.\n", stderr); exit(1); } off = nl[N_SYSMAP].n_value & ~KERNBASE; (void)lseek(memf, off, L_SET); (void)read(memf, (char *)Sysmap, (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte))); #endif } (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET); if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) != sizeof(tcp_debx)) { perror("trpt: tcp_debx"); exit(3); } (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET); if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) != sizeof(tcp_debug)) { perror("trpt: tcp_debug"); exit(3); } /* * If no control blocks have been specified, figure * out how many distinct one we have and summarize * them in tcp_pcbs for sorting the trace records * below. */ if (!npcbs) { for (i = 0; i < TCP_NDEBUG; i++) { register struct tcp_debug *td = &tcp_debug[i]; register int j; if (td->td_tcb == 0) continue; for (j = 0; j < npcbs; j++) if (tcp_pcbs[j] == td->td_tcb) break; if (j >= npcbs) tcp_pcbs[npcbs++] = td->td_tcb; } if (!npcbs) exit(0); } qsort(tcp_pcbs, npcbs, sizeof(caddr_t), numeric); if (jflag) { for (i = 0;;) { printf("%lx", (long)tcp_pcbs[i]); if (++i == npcbs) break; fputs(", ", stdout); } putchar('\n'); } else for (i = 0; i < npcbs; i++) { printf("\n%lx:\n", (long)tcp_pcbs[i]); dotrace(tcp_pcbs[i]); } exit(0); } dotrace(tcpcb) register caddr_t tcpcb; { register struct tcp_debug *td; register int i; int prev_debx = tcp_debx; again: if (--tcp_debx < 0) tcp_debx = TCP_NDEBUG - 1; for (i = prev_debx % TCP_NDEBUG; i < TCP_NDEBUG; i++) { td = &tcp_debug[i]; if (tcpcb && td->td_tcb != tcpcb) continue; ntime = ntohl(td->td_time); tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb, &td->td_ti, td->td_req); if (i == tcp_debx) goto done; } for (i = 0; i <= tcp_debx % TCP_NDEBUG; i++) { td = &tcp_debug[i]; if (tcpcb && td->td_tcb != tcpcb) continue; ntime = ntohl(td->td_time); tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb, &td->td_ti, td->td_req); } done: if (follow) { prev_debx = tcp_debx + 1; if (prev_debx >= TCP_NDEBUG) prev_debx = 0; do { sleep(1); (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET); if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) != sizeof(tcp_debx)) { perror("trpt: tcp_debx"); exit(3); } } while (tcp_debx == prev_debx); (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET); if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) != sizeof(tcp_debug)) { perror("trpt: tcp_debug"); exit(3); } goto again; } } /* * Tcp debug routines */ /*ARGSUSED*/ tcp_trace(act, ostate, atp, tp, ti, req) short act, ostate; struct tcpcb *atp, *tp; struct tcpiphdr *ti; int req; { tcp_seq seq, ack; int flags, len, win, timer; printf("%03ld %s:%s ",(ntime/10) % 1000, tcpstates[ostate], tanames[act]); switch (act) { case TA_INPUT: case TA_OUTPUT: case TA_DROP: if (aflag) { printf("(src=%s,%u, ", inet_ntoa(ti->ti_src), ntohs(ti->ti_sport)); printf("dst=%s,%u)", inet_ntoa(ti->ti_dst), ntohs(ti->ti_dport)); } seq = ti->ti_seq; ack = ti->ti_ack; len = ti->ti_len; win = ti->ti_win; if (act == TA_OUTPUT) { seq = ntohl(seq); ack = ntohl(ack); len = ntohs(len); win = ntohs(win); } if (act == TA_OUTPUT) len -= sizeof(struct tcphdr); if (len) printf("[%lx..%lx)", seq, seq + len); else printf("%lx", seq); printf("@%lx", ack); if (win) printf("(win=%x)", win); flags = ti->ti_flags; if (flags) { register char *cp = "<"; #define pf(flag, string) { \ if (ti->ti_flags&flag) { \ (void)printf("%s%s", cp, string); \ cp = ","; \ } \ } pf(TH_SYN, "SYN"); pf(TH_ACK, "ACK"); pf(TH_FIN, "FIN"); pf(TH_RST, "RST"); pf(TH_PUSH, "PUSH"); pf(TH_URG, "URG"); printf(">"); } break; case TA_USER: timer = req >> 8; req &= 0xff; printf("%s", prurequests[req]); if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO) printf("<%s>", tcptimers[timer]); break; } printf(" -> %s", tcpstates[tp->t_state]); /* print out internal state of tp !?! */ printf("\n"); if (sflag) { printf("\trcv_nxt %lx rcv_wnd %x snd_una %lx snd_nxt %lx snd_max %lx\n", tp->rcv_nxt, tp->rcv_wnd, tp->snd_una, tp->snd_nxt, tp->snd_max); printf("\tsnd_wl1 %lx snd_wl2 %lx snd_wnd %x\n", tp->snd_wl1, tp->snd_wl2, tp->snd_wnd); } /* print out timers? */ if (tflag) { register char *cp = "\t"; register int i; for (i = 0; i < TCPT_NTIMERS; i++) { if (tp->t_timer[i] == 0) continue; printf("%s%s=%d", cp, tcptimers[i], tp->t_timer[i]); if (i == TCPT_REXMT) printf(" (t_rxtshft=%d)", tp->t_rxtshift); cp = ", "; } if (*cp != '\t') putchar('\n'); } } numeric(c1, c2) caddr_t *c1, *c2; { return(*c1 - *c2); } klseek(fd, base, off) int fd, off; off_t base; { off_t lseek(); #ifndef NEWVM if (kflag) { /* get kernel pte */ base &= ~KERNBASE; base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET); } #endif (void)lseek(fd, base, off); }