Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.1 6/24/83; site umcp-cs.UUCP Path: utzoo!watmath!clyde!burl!ulysses!allegra!mit-eddie!think!harvard!seismo!umcp-cs!chris From: chris@umcp-cs.UUCP (Chris Torek) Newsgroups: net.sources Subject: TCP debugging aid for 4.2BSD Message-ID: <6118@umcp-cs.UUCP> Date: Tue, 28-May-85 11:07:58 EDT Article-I.D.: umcp-cs.6118 Posted: Tue May 28 11:07:58 1985 Date-Received: Thu, 30-May-85 02:42:37 EDT Distribution: net Organization: U of Maryland, Computer Science Dept., College Park, MD Lines: 246 If you decide to do some TCP hacking on your 4.2BSD system (considering that 4.2 needs a lot of TCP hacking) this program can be invaluable. (It's pointed out a retransmit timing bug, for example; look closely at tcp_output.c ...) Sorry, no manual page; but it's only useful for tcp hackers, who ought to be able to figure out how to use it anyway. Without further ado, here it is: : Run this shell script with "sh" not "csh" PATH=:/bin:/usr/bin:/usr/ucb export PATH all=FALSE if [ $1x = -ax ]; then all=TRUE fi /bin/echo 'Extracting tcpdbug.c' sed 's/^X//' <<'//go.sysin dd *' >tcpdbug.c #ifndef lint static char rcsid[] = "$Header$"; #endif X/* * tcpdbug * * snapshot tcpcbs */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define TCPSTATES #include #include #include #include #include #include #include struct nlist nl[] = { {"_tcb"}, #define X_TCB 0 {0} }; int kmem; struct inpcb tcb, inpcb; struct tcpcb tcpcb; int AFlag, FFlag, LFlag; struct in_addr FAddr; u_short FPort; ReadKernelItem (kaddr, caddr, size) caddr_t kaddr, caddr; int size; { (void) lseek (kmem, (long) kaddr, 0); if (read (kmem, caddr, size) != size) { perror ("kmem read"); exit (1); } } OpenKmem () { if ((kmem = open ("/dev/kmem", 0)) < 0) { perror ("/dev/kmem"); exit (1); } } GetNames () { nlist ("/vmunix", nl); if (nl[0].n_type == 0) { fprintf (stderr, "/vmunix: no namelist\n"); exit (1); } } LoopThrough () { register struct inpcb *inp, *endp; register struct tcpcb *tp; endp = (struct inpcb *) nl[X_TCB].n_value; ReadKernelItem ((caddr_t) endp, (caddr_t) &tcb, sizeof tcb); for (inp = tcb.inp_next; inp != endp; inp = inpcb.inp_next) { ReadKernelItem ((caddr_t) inp, (caddr_t) &inpcb, sizeof inpcb); tp = (struct tcpcb *) inpcb.inp_ppcb; if (tp == 0) continue; ReadKernelItem ((caddr_t) tp, (caddr_t) &tcpcb, sizeof tcpcb); DumpTCP (tp, &tcpcb); } } DumpTCP (ktp, tp) register struct tcpcb *ktp, *tp; { #define flag(x) ((x) ? "true" : "false") struct timeval tv; struct timezone tz; if (FFlag) { /* ignore mismatches */ if (inpcb.inp_faddr.s_addr != FAddr.s_addr) return; if (FPort && inpcb.inp_fport != FPort) return; } else { if (tp -> t_state == TCPS_LISTEN && !AFlag) return; /* ignore LISTENers */ } (void) gettimeofday (&tv, &tz); printf ("time = %d.%03d\n", tv.tv_sec, tv.tv_usec); printf ("\ tcpcb:\n\ \tlocal addr = %d.%d.%d.%d.%d\tforeign addr = %d.%d.%d.%d.%d\n\ \taddr = 0x%x\tstate = %s\n\ \ttimers: rexmt = %d, persist = %d, keep = %d, 2msl = %d\n\ \trxtshift = %d\tmaxseg = %d\tforce %s\n\ \tflags: ack now %s, del ack %s, don't keep %s, no opt %s\n\ \tsend seq: unack = 0x%x, next = 0x%x, urg = 0x%x,\n\ \t\twl1 = 0x%x, wl2 = 0x%x,\n\ \t\tiss= 0x%x, window = 0x%x\n\ \trecv seq: window = 0x%x, next = 0x%x, urg = 0x%x, irs = 0x%x\n\ \tadvertised window = 0x%x, highest seq sent = 0x%x\n\ \tidle = %d, rtt = %d, rttseq = 0x%x, srtt = %12.6f\n\ \toobflag %s, iobc = 0x%x\n\n", #define xpand(x) (x).S_un.S_un_b.s_b1, (x).S_un.S_un_b.s_b2, \ (x).S_un.S_un_b.s_b3, (x).S_un.S_un_b.s_b4 xpand (inpcb.inp_laddr), ntohs (inpcb.inp_lport), xpand (inpcb.inp_faddr), ntohs (inpcb.inp_fport), #undef xpand ktp, tcpstates[tp -> t_state], tp -> t_timer[TCPT_REXMT], tp -> t_timer[TCPT_PERSIST], tp -> t_timer[TCPT_KEEP], tp -> t_timer[TCPT_2MSL], tp -> t_rxtshift, tp -> t_maxseg, flag (tp -> t_force), flag (tp -> t_flags & TF_ACKNOW), flag (tp -> t_flags & TF_DELACK), flag (tp -> t_flags & TF_DONTKEEP), flag (tp -> t_flags & TF_NOOPT), tp -> snd_una, tp -> snd_nxt, tp -> snd_up, tp -> snd_wl1, tp -> snd_wl2, tp -> iss, tp -> snd_wnd, tp -> rcv_wnd, tp -> rcv_nxt, tp -> rcv_up, tp -> irs, tp -> rcv_adv, tp -> snd_max, tp -> t_idle, tp -> t_rtt, tp -> t_rtseq, tp -> t_srtt, flag (tp -> t_oobflags), tp -> t_iobc & 0xff); } GetAddr (s) register char *s; { register char *dotp; register struct hostent *hp; char *rindex (); dotp = rindex (s, '.'); if (!dotp) { fprintf (stderr, "%s: bad address format (should be host.port)\n", s); exit (1); } *dotp++ = 0; hp = gethostbyname (s); if (hp == 0) { fprintf (stderr, "%s: unknown host\n", s); exit (1); } FAddr.s_addr = *(n_long *) hp -> h_addr; FPort = htons (atoi (dotp)); } Options (argc, argv) register int argc; register char **argv; { register char *s; argc--, argv++; while (--argc >= 0) { s = *argv++; if (*s++ != '-') return; switch (*s) { case 'a': AFlag++; break; case 'f': if (*++s == 0) { if (--argc >= 0) s = *argv++; else return; } FFlag++; GetAddr (s); break; case 'l': LFlag++; break; } } } main (argc, argv) char **argv; { Options (argc, argv); if (argc > 1 && strcmp (argv[1], "-a", 0) == 0) AFlag++; OpenKmem (); GetNames (); if (LFlag) { for (;;) { LoopThrough (); fflush (stdout); nap (500); } } else LoopThrough (); exit (0); } nap (ms) { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = ms * 1000; (void) select (0, (int *) 0, (int *) 0, (int *) 0, &tv); } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 tcpdbug.c /bin/echo -n ' '; /bin/ls -ld tcpdbug.c fi -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@maryland