trpt.c revision 189090
1122394Sharti/* 2122394Sharti * Copyright (c) 1983, 1988, 1993 3122394Sharti * The Regents of the University of California. All rights reserved. 4122394Sharti * 5122394Sharti * Redistribution and use in source and binary forms, with or without 6122394Sharti * modification, are permitted provided that the following conditions 7133211Sharti * are met: 8216594Ssyrinx * 1. Redistributions of source code must retain the above copyright 9216594Ssyrinx * notice, this list of conditions and the following disclaimer. 10216594Ssyrinx * 2. Redistributions in binary form must reproduce the above copyright 11216594Ssyrinx * notice, this list of conditions and the following disclaimer in the 12216594Ssyrinx * documentation and/or other materials provided with the distribution. 13216594Ssyrinx * 4. Neither the name of the University nor the names of its contributors 14133211Sharti * may be used to endorse or promote products derived from this software 15133211Sharti * without specific prior written permission. 16133211Sharti * 17133211Sharti * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18133211Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19122394Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20122394Sharti * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21122394Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27133211Sharti * SUCH DAMAGE. 28133211Sharti */ 29133211Sharti 30133211Sharti#if 0 31133211Sharti#ifndef lint 32133211Shartistatic const char copyright[] = 33133211Sharti"@(#) Copyright (c) 1983, 1988, 1993\n\ 34122394Sharti The Regents of the University of California. All rights reserved.\n"; 35156066Sharti#endif /* not lint */ 36122394Sharti 37122394Sharti#ifndef lint 38122394Shartistatic char sccsid[] = "@(#)trpt.c 8.1 (Berkeley) 6/6/93"; 39216294Ssyrinx#endif /* not lint */ 40216294Ssyrinx#endif 41122394Sharti#include <sys/cdefs.h> 42122394Sharti__FBSDID("$FreeBSD: head/usr.sbin/trpt/trpt.c 189090 2009-02-26 20:59:05Z ed $"); 43124861Sharti 44150920Sharti#include <sys/param.h> 45122394Sharti#include <sys/queue.h> 46122394Sharti#include <sys/socket.h> 47122394Sharti#include <sys/socketvar.h> 48122394Sharti#define PRUREQUESTS 49122394Sharti#include <sys/protosw.h> 50122394Sharti#include <sys/file.h> 51122394Sharti#include <sys/time.h> 52122394Sharti 53122394Sharti#include <net/route.h> 54122394Sharti#include <net/if.h> 55122394Sharti 56122394Sharti#include <netinet/in.h> 57122394Sharti#include <netinet/in_systm.h> 58145557Sharti#include <netinet/ip.h> 59145557Sharti#ifdef INET6 60145557Sharti#include <netinet/ip6.h> 61145557Sharti#endif 62145557Sharti#include <netinet/ip_var.h> 63156066Sharti#include <netinet/tcp.h> 64122394Sharti#define TCPSTATES 65122394Sharti#include <netinet/tcp_fsm.h> 66122394Sharti#include <netinet/tcp_seq.h> 67122394Sharti#define TCPTIMERS 68122394Sharti#include <netinet/tcp_timer.h> 69122394Sharti#include <netinet/tcp_var.h> 70122394Sharti#include <netinet/tcpip.h> 71216294Ssyrinx#define TANAMES 72122394Sharti#include <netinet/tcp_debug.h> 73146525Sharti 74146525Sharti#include <arpa/inet.h> 75122394Sharti 76122394Sharti#include <err.h> 77122394Sharti#include <nlist.h> 78122394Sharti#include <paths.h> 79122394Sharti#include <stdio.h> 80122394Sharti#include <stdlib.h> 81122394Sharti#include <string.h> 82122394Sharti#include <unistd.h> 83122394Sharti 84122394Shartistruct nlist nl[3]; 85122394Sharti#define N_TCP_DEBUG 0 86122394Sharti#define N_TCP_DEBX 1 87122394Sharti 88122394Shartistatic caddr_t tcp_pcbs[TCP_NDEBUG]; 89122394Shartistatic n_time ntime; 90122394Shartistatic int aflag, kflag, memf, follow, sflag, tflag; 91122394Sharti 92122394Shartivoid dotrace(caddr_t); 93122394Shartivoid klseek(int, off_t, int); 94122394Shartiint numeric(const void *, const void *); 95124861Shartivoid tcp_trace(short, short, struct tcpcb *, int, void *, struct tcphdr *, int); 96122394Shartistatic void usage(void); 97122394Sharti 98122394Shartiint 99216294Ssyrinxmain(int argc, char **argv) 100216294Ssyrinx{ 101216294Ssyrinx int ch, i, jflag, npcbs; 102216294Ssyrinx const char *core, *syst; 103216294Ssyrinx 104122394Sharti nl[0].n_name = strdup("_tcp_debug"); 105122394Sharti nl[1].n_name = strdup("_tcp_debx"); 106122394Sharti 107216594Ssyrinx jflag = npcbs = 0; 108216594Ssyrinx while ((ch = getopt(argc, argv, "afjp:st")) != -1) 109122394Sharti switch (ch) { 110122394Sharti case 'a': 111122394Sharti ++aflag; 112122394Sharti break; 113122394Sharti case 'f': 114122394Sharti ++follow; 115122394Sharti setlinebuf(stdout); 116122394Sharti break; 117122394Sharti case 'j': 118122394Sharti ++jflag; 119122394Sharti break; 120122394Sharti case 'p': 121216294Ssyrinx if (npcbs >= TCP_NDEBUG) 122216294Ssyrinx errx(1, "too many pcb's specified"); 123216294Ssyrinx (void)sscanf(optarg, "%x", (int *)&tcp_pcbs[npcbs++]); 124216294Ssyrinx break; 125216294Ssyrinx case 's': 126216294Ssyrinx ++sflag; 127216294Ssyrinx break; 128216294Ssyrinx case 't': 129216294Ssyrinx ++tflag; 130216294Ssyrinx break; 131216294Ssyrinx case '?': 132216294Ssyrinx default: 133216294Ssyrinx usage(); 134216294Ssyrinx } 135216294Ssyrinx argc -= optind; 136216294Ssyrinx argv += optind; 137216294Ssyrinx 138216294Ssyrinx core = _PATH_KMEM; 139216294Ssyrinx if (argc > 0) { 140216294Ssyrinx syst = *argv; 141216294Ssyrinx argc--, argv++; 142216294Ssyrinx if (argc > 0) { 143216294Ssyrinx core = *argv; 144122394Sharti argc--, argv++; 145122394Sharti ++kflag; 146122394Sharti } 147122394Sharti /* 148122394Sharti * Discard setgid privileges if not the running kernel so that 149122394Sharti * bad guys can't print interesting stuff from kernel memory. 150122394Sharti */ 151122394Sharti setgid(getgid()); 152122394Sharti } 153122394Sharti else 154122394Sharti syst = getbootfile(); 155122394Sharti 156122394Sharti if (nlist(syst, nl) < 0 || !nl[0].n_value) 157122394Sharti errx(1, "%s: no namelist", syst); 158122394Sharti if ((memf = open(core, O_RDONLY)) < 0) 159122394Sharti err(2, "%s", core); 160122394Sharti setgid(getgid()); 161122394Sharti if (kflag) 162122394Sharti errx(1, "can't do core files yet"); 163122394Sharti (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET); 164122394Sharti if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) != 165122394Sharti sizeof(tcp_debx)) 166122394Sharti err(3, "tcp_debx"); 167122394Sharti (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET); 168122394Sharti if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) != 169122394Sharti sizeof(tcp_debug)) 170216294Ssyrinx err(3, "tcp_debug"); 171216294Ssyrinx /* 172216294Ssyrinx * If no control blocks have been specified, figure 173122394Sharti * out how many distinct one we have and summarize 174122394Sharti * them in tcp_pcbs for sorting the trace records 175122394Sharti * below. 176216294Ssyrinx */ 177122394Sharti if (!npcbs) { 178124861Sharti for (i = 0; i < TCP_NDEBUG; i++) { 179122394Sharti register struct tcp_debug *td = &tcp_debug[i]; 180122394Sharti register int j; 181124861Sharti 182122394Sharti if (td->td_tcb == 0) 183122394Sharti continue; 184122394Sharti for (j = 0; j < npcbs; j++) 185122394Sharti if (tcp_pcbs[j] == td->td_tcb) 186122394Sharti break; 187122394Sharti if (j >= npcbs) 188122394Sharti tcp_pcbs[npcbs++] = td->td_tcb; 189122394Sharti } 190122394Sharti if (!npcbs) 191122394Sharti exit(0); 192122394Sharti } 193122394Sharti qsort(tcp_pcbs, npcbs, sizeof(caddr_t), numeric); 194122394Sharti if (jflag) { 195122394Sharti for (i = 0;;) { 196122394Sharti printf("%p", (void *)tcp_pcbs[i]); 197122394Sharti if (++i == npcbs) 198122394Sharti break; 199122394Sharti fputs(", ", stdout); 200216294Ssyrinx } 201216294Ssyrinx putchar('\n'); 202216294Ssyrinx } 203216294Ssyrinx else for (i = 0; i < npcbs; i++) { 204216294Ssyrinx printf("\n%p:\n", tcp_pcbs[i]); 205216294Ssyrinx dotrace(tcp_pcbs[i]); 206122394Sharti } 207122394Sharti exit(0); 208122394Sharti} 209122394Sharti 210122394Shartistatic void 211122394Shartiusage() 212122394Sharti{ 213216294Ssyrinx (void)fprintf(stderr, 214216294Ssyrinx "usage: trpt [-afjst] [-p hex-address] [system [core]]\n"); 215216294Ssyrinx exit(1); 216122394Sharti} 217122394Sharti 218122394Shartivoid 219122394Shartidotrace(tcpcb) 220122394Sharti register caddr_t tcpcb; 221216294Ssyrinx{ 222122394Sharti register struct tcp_debug *td; 223122394Sharti register int i; 224122394Sharti int prev_debx = tcp_debx, family; 225122394Sharti 226122394Shartiagain: if (--tcp_debx < 0) 227122394Sharti tcp_debx = TCP_NDEBUG - 1; 228145557Sharti for (i = prev_debx % TCP_NDEBUG; i < TCP_NDEBUG; i++) { 229145557Sharti td = &tcp_debug[i]; 230145557Sharti if (tcpcb && td->td_tcb != tcpcb) 231145557Sharti continue; 232145557Sharti ntime = ntohl(td->td_time); 233124861Sharti#ifdef INET6 234124861Sharti family = td->td_family; 235124861Sharti#else 236124861Sharti family = AF_INET; 237124861Sharti#endif 238124861Sharti switch(family) { 239122394Sharti case AF_INET: 240122394Sharti tcp_trace(td->td_act, td->td_ostate, 241122394Sharti &td->td_cb, td->td_family, &td->td_ti.ti_i, 242122394Sharti &td->td_ti.ti_t, td->td_req); 243122394Sharti break; 244122394Sharti#ifdef INET6 245122394Sharti case AF_INET6: 246122394Sharti tcp_trace(td->td_act, td->td_ostate, 247122394Sharti &td->td_cb, td->td_family, &td->td_ti6.ip6, 248122394Sharti &td->td_ti6.th, td->td_req); 249122394Sharti break; 250122394Sharti#endif 251122394Sharti } 252122394Sharti if (i == tcp_debx) 253124861Sharti goto done; 254122394Sharti } 255122394Sharti for (i = 0; i <= tcp_debx % TCP_NDEBUG; i++) { 256122394Sharti td = &tcp_debug[i]; 257122394Sharti if (tcpcb && td->td_tcb != tcpcb) 258122394Sharti continue; 259122394Sharti ntime = ntohl(td->td_time); 260122394Sharti#ifdef INET6 261122394Sharti family = td->td_family; 262122394Sharti#else 263122394Sharti family = AF_INET; 264122394Sharti#endif 265124861Sharti switch(family) { 266122394Sharti case AF_INET: 267122394Sharti tcp_trace(td->td_act, td->td_ostate, 268122394Sharti &td->td_cb, td->td_family, &td->td_ti.ti_i, 269122394Sharti &td->td_ti.ti_t, td->td_req); 270124861Sharti break; 271122394Sharti#ifdef INET6 272122394Sharti case AF_INET6: 273122394Sharti tcp_trace(td->td_act, td->td_ostate, 274122394Sharti &td->td_cb, td->td_family, &td->td_ti6.ip6, 275122394Sharti &td->td_ti6.th, td->td_req); 276122394Sharti break; 277124861Sharti#endif 278122394Sharti } 279122394Sharti } 280122394Shartidone: if (follow) { 281122394Sharti prev_debx = tcp_debx + 1; 282122394Sharti if (prev_debx >= TCP_NDEBUG) 283122394Sharti prev_debx = 0; 284122394Sharti do { 285122394Sharti sleep(1); 286122394Sharti (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET); 287122394Sharti if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) != 288122394Sharti sizeof(tcp_debx)) 289122394Sharti err(3, "tcp_debx"); 290122394Sharti } while (tcp_debx == prev_debx); 291122394Sharti (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET); 292122394Sharti if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) != 293122394Sharti sizeof(tcp_debug)) 294122394Sharti err(3, "tcp_debug"); 295122394Sharti goto again; 296122394Sharti } 297216294Ssyrinx} 298122394Sharti 299216294Ssyrinx/* 300216294Ssyrinx * Tcp debug routines 301216294Ssyrinx */ 302216294Ssyrinx/*ARGSUSED*/ 303216294Ssyrinxvoid 304216294Ssyrinxtcp_trace(short act, short ostate, struct tcpcb *tp, int family __unused, 305216294Ssyrinx void *ip, struct tcphdr *th, int req) 306216294Ssyrinx{ 307216294Ssyrinx tcp_seq seq, ack; 308216294Ssyrinx int flags, len, win, timer; 309216294Ssyrinx struct ip *ip4; 310216294Ssyrinx#ifdef INET6 311216294Ssyrinx int isipv6, nopkt = 1; 312216294Ssyrinx struct ip6_hdr *ip6; 313216294Ssyrinx char ntop_buf[INET6_ADDRSTRLEN]; 314216294Ssyrinx#endif 315216294Ssyrinx 316216294Ssyrinx#ifdef INET6 317216294Ssyrinx switch (family) { 318216294Ssyrinx case AF_INET: 319216294Ssyrinx nopkt = 0; 320216294Ssyrinx isipv6 = 0; 321216294Ssyrinx ip4 = (struct ip *)ip; 322216294Ssyrinx break; 323216294Ssyrinx case AF_INET6: 324216294Ssyrinx nopkt = 0; 325216294Ssyrinx isipv6 = 1; 326216294Ssyrinx ip6 = (struct ip6_hdr *)ip; 327216294Ssyrinx case 0: 328216294Ssyrinx default: 329216294Ssyrinx break; 330216294Ssyrinx } 331216294Ssyrinx#else 332216294Ssyrinx ip4 = (struct ip *)ip; 333216294Ssyrinx#endif 334216294Ssyrinx printf("%03ld %s:%s ", (long)((ntime/10) % 1000), tcpstates[ostate], 335216294Ssyrinx tanames[act]); 336216294Ssyrinx switch (act) { 337216294Ssyrinx case TA_INPUT: 338216294Ssyrinx case TA_OUTPUT: 339216294Ssyrinx case TA_DROP: 340216294Ssyrinx#ifdef INET6 341216294Ssyrinx if (nopkt != 0) 342216294Ssyrinx break; 343216294Ssyrinx#endif 344216294Ssyrinx if (aflag) { 345216294Ssyrinx printf("(src=%s,%u, ", 346216294Ssyrinx 347216294Ssyrinx#ifdef INET6 348216294Ssyrinx isipv6 349216294Ssyrinx ? inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf, 350216294Ssyrinx sizeof(ntop_buf)) : 351216294Ssyrinx#endif 352216294Ssyrinx inet_ntoa(ip4->ip_src), 353216294Ssyrinx ntohs(th->th_sport)); 354216294Ssyrinx printf("dst=%s,%u)", 355216294Ssyrinx#ifdef INET6 356216294Ssyrinx isipv6 357216294Ssyrinx ? inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf, 358216294Ssyrinx sizeof(ntop_buf)) : 359216294Ssyrinx#endif 360216294Ssyrinx inet_ntoa(ip4->ip_dst), 361216294Ssyrinx ntohs(th->th_dport)); 362216294Ssyrinx } 363216294Ssyrinx seq = th->th_seq; 364216294Ssyrinx ack = th->th_ack; 365216294Ssyrinx 366216294Ssyrinx len = 367216294Ssyrinx#ifdef INET6 368216294Ssyrinx isipv6 ? ip6->ip6_plen : 369216294Ssyrinx#endif 370216294Ssyrinx ip4->ip_len; 371216294Ssyrinx win = th->th_win; 372216594Ssyrinx if (act == TA_OUTPUT) { 373216294Ssyrinx seq = ntohl(seq); 374216294Ssyrinx ack = ntohl(ack); 375216294Ssyrinx len = ntohs(len); 376216294Ssyrinx win = ntohs(win); 377216294Ssyrinx } 378216294Ssyrinx if (act == TA_OUTPUT) 379216294Ssyrinx len -= sizeof(struct tcphdr); 380216294Ssyrinx if (len) 381216294Ssyrinx printf("[%lx..%lx)", (u_long)seq, (u_long)(seq + len)); 382216294Ssyrinx else 383216294Ssyrinx printf("%lx", (u_long)seq); 384216294Ssyrinx printf("@%lx", (u_long)ack); 385216294Ssyrinx if (win) 386216294Ssyrinx printf("(win=%x)", win); 387216294Ssyrinx flags = th->th_flags; 388216294Ssyrinx if (flags) { 389216294Ssyrinx const char *cp = "<"; 390216294Ssyrinx#define pf(flag, string) { \ 391216294Ssyrinx if (th->th_flags&flag) { \ 392216294Ssyrinx (void)printf("%s%s", cp, string); \ 393216294Ssyrinx cp = ","; \ 394216294Ssyrinx } \ 395216294Ssyrinx} 396216294Ssyrinx pf(TH_SYN, "SYN"); 397216294Ssyrinx pf(TH_ACK, "ACK"); 398216294Ssyrinx pf(TH_FIN, "FIN"); 399216294Ssyrinx pf(TH_RST, "RST"); 400216294Ssyrinx pf(TH_PUSH, "PUSH"); 401216294Ssyrinx pf(TH_URG, "URG"); 402216294Ssyrinx printf(">"); 403216294Ssyrinx } 404216294Ssyrinx break; 405216294Ssyrinx case TA_USER: 406216294Ssyrinx timer = req >> 8; 407216294Ssyrinx req &= 0xff; 408216294Ssyrinx printf("%s", prurequests[req]); 409216294Ssyrinx if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO) 410216294Ssyrinx printf("<%s>", tcptimers[timer]); 411216294Ssyrinx break; 412216294Ssyrinx } 413216294Ssyrinx printf(" -> %s", tcpstates[tp->t_state]); 414216294Ssyrinx /* print out internal state of tp !?! */ 415216294Ssyrinx printf("\n"); 416216294Ssyrinx if (sflag) { 417216294Ssyrinx printf("\trcv_nxt %lx rcv_wnd %lx snd_una %lx snd_nxt %lx snd_max %lx\n", 418216294Ssyrinx (u_long)tp->rcv_nxt, tp->rcv_wnd, 419216294Ssyrinx (u_long)tp->snd_una, (u_long)tp->snd_nxt, 420216294Ssyrinx (u_long)tp->snd_max); 421216294Ssyrinx printf("\tsnd_wl1 %lx snd_wl2 %lx snd_wnd %lx\n", 422216294Ssyrinx (u_long)tp->snd_wl1, 423216294Ssyrinx (u_long)tp->snd_wl2, tp->snd_wnd); 424216294Ssyrinx } 425216294Ssyrinx /* print out timers? */ 426216294Ssyrinx#if 0 427216294Ssyrinx /* 428216294Ssyrinx * XXX 429216294Ssyrinx * kernel now uses callouts, not integer time values. 430216294Ssyrinx */ 431216294Ssyrinx if (tflag) { 432216294Ssyrinx register char *cp = "\t"; 433216294Ssyrinx register int i; 434216294Ssyrinx 435216294Ssyrinx for (i = 0; i < TCPT_NTIMERS; i++) { 436216294Ssyrinx if (tp->t_timer[i] == 0) 437216294Ssyrinx continue; 438216294Ssyrinx printf("%s%s=%d", cp, tcptimers[i], tp->t_timer[i]); 439216294Ssyrinx if (i == TCPT_REXMT) 440216294Ssyrinx printf(" (t_rxtshft=%d)", tp->t_rxtshift); 441216294Ssyrinx cp = ", "; 442216294Ssyrinx } 443216294Ssyrinx if (*cp != '\t') 444216294Ssyrinx putchar('\n'); 445216294Ssyrinx } 446216294Ssyrinx#endif 447216294Ssyrinx} 448216294Ssyrinx 449216294Ssyrinxint 450216294Ssyrinxnumeric(v1, v2) 451216294Ssyrinx const void *v1, *v2; 452216294Ssyrinx{ 453216294Ssyrinx const caddr_t *c1 = v1, *c2 = v2; 454216294Ssyrinx return(*c1 - *c2); 455216294Ssyrinx} 456216294Ssyrinx 457216294Ssyrinxvoid 458216294Ssyrinxklseek(fd, base, off) 459216294Ssyrinx int fd, off; 460216294Ssyrinx off_t base; 461216294Ssyrinx{ 462216294Ssyrinx (void)lseek(fd, base, off); 463216294Ssyrinx} 464216294Ssyrinx