11553Srgrimes/* 21553Srgrimes * Copyright (c) 1983, 1988, 1993 31553Srgrimes * The Regents of the University of California. All rights reserved. 41553Srgrimes * 51553Srgrimes * Redistribution and use in source and binary forms, with or without 61553Srgrimes * modification, are permitted provided that the following conditions 71553Srgrimes * are met: 81553Srgrimes * 1. Redistributions of source code must retain the above copyright 91553Srgrimes * notice, this list of conditions and the following disclaimer. 101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111553Srgrimes * notice, this list of conditions and the following disclaimer in the 121553Srgrimes * documentation and/or other materials provided with the distribution. 131553Srgrimes * 4. Neither the name of the University nor the names of its contributors 141553Srgrimes * may be used to endorse or promote products derived from this software 151553Srgrimes * without specific prior written permission. 161553Srgrimes * 171553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271553Srgrimes * SUCH DAMAGE. 281553Srgrimes */ 291553Srgrimes 30114601Sobrien#if 0 311553Srgrimes#ifndef lint 3230643Scharnierstatic const char copyright[] = 331553Srgrimes"@(#) Copyright (c) 1983, 1988, 1993\n\ 341553Srgrimes The Regents of the University of California. All rights reserved.\n"; 351553Srgrimes#endif /* not lint */ 361553Srgrimes 371553Srgrimes#ifndef lint 381553Srgrimesstatic char sccsid[] = "@(#)trpt.c 8.1 (Berkeley) 6/6/93"; 39114601Sobrien#endif /* not lint */ 4030643Scharnier#endif 41114601Sobrien#include <sys/cdefs.h> 42114601Sobrien__FBSDID("$FreeBSD$"); 431553Srgrimes 441553Srgrimes#include <sys/param.h> 4514544Sdg#include <sys/queue.h> 461553Srgrimes#include <sys/socket.h> 471553Srgrimes#include <sys/socketvar.h> 481553Srgrimes#define PRUREQUESTS 491553Srgrimes#include <sys/protosw.h> 501553Srgrimes#include <sys/file.h> 5120287Swollman#include <sys/time.h> 521553Srgrimes 531553Srgrimes#include <net/route.h> 541553Srgrimes#include <net/if.h> 551553Srgrimes 561553Srgrimes#include <netinet/in.h> 571553Srgrimes#include <netinet/in_systm.h> 581553Srgrimes#include <netinet/ip.h> 5955679Sshin#ifdef INET6 6055679Sshin#include <netinet/ip6.h> 6155679Sshin#endif 621553Srgrimes#include <netinet/ip_var.h> 631553Srgrimes#include <netinet/tcp.h> 641553Srgrimes#define TCPSTATES 651553Srgrimes#include <netinet/tcp_fsm.h> 661553Srgrimes#include <netinet/tcp_seq.h> 671553Srgrimes#define TCPTIMERS 681553Srgrimes#include <netinet/tcp_timer.h> 691553Srgrimes#include <netinet/tcp_var.h> 701553Srgrimes#include <netinet/tcpip.h> 711553Srgrimes#define TANAMES 721553Srgrimes#include <netinet/tcp_debug.h> 731553Srgrimes 741553Srgrimes#include <arpa/inet.h> 751553Srgrimes 7630643Scharnier#include <err.h> 771553Srgrimes#include <nlist.h> 781553Srgrimes#include <paths.h> 7930643Scharnier#include <stdio.h> 8030643Scharnier#include <stdlib.h> 81100114Salfred#include <string.h> 8230643Scharnier#include <unistd.h> 831553Srgrimes 84100114Salfredstruct nlist nl[3]; 851553Srgrimes#define N_TCP_DEBUG 0 861553Srgrimes#define N_TCP_DEBX 1 871553Srgrimes 881553Srgrimesstatic caddr_t tcp_pcbs[TCP_NDEBUG]; 891553Srgrimesstatic n_time ntime; 901553Srgrimesstatic int aflag, kflag, memf, follow, sflag, tflag; 911553Srgrimes 92100114Salfredvoid dotrace(caddr_t); 93100114Salfredvoid klseek(int, off_t, int); 94100114Salfredint numeric(const void *, const void *); 95100114Salfredvoid tcp_trace(short, short, struct tcpcb *, int, void *, struct tcphdr *, int); 96100114Salfredstatic void usage(void); 9730643Scharnier 9830643Scharnierint 99100114Salfredmain(int argc, char **argv) 1001553Srgrimes{ 10130643Scharnier int ch, i, jflag, npcbs; 102100114Salfred const char *core, *syst; 1031553Srgrimes 104100114Salfred nl[0].n_name = strdup("_tcp_debug"); 105100114Salfred nl[1].n_name = strdup("_tcp_debx"); 106100114Salfred 1071553Srgrimes jflag = npcbs = 0; 10824428Simp while ((ch = getopt(argc, argv, "afjp:st")) != -1) 1091553Srgrimes switch (ch) { 1101553Srgrimes case 'a': 1111553Srgrimes ++aflag; 1121553Srgrimes break; 1131553Srgrimes case 'f': 1141553Srgrimes ++follow; 1151553Srgrimes setlinebuf(stdout); 1161553Srgrimes break; 1171553Srgrimes case 'j': 1181553Srgrimes ++jflag; 1191553Srgrimes break; 1201553Srgrimes case 'p': 12130643Scharnier if (npcbs >= TCP_NDEBUG) 12230643Scharnier errx(1, "too many pcb's specified"); 1231553Srgrimes (void)sscanf(optarg, "%x", (int *)&tcp_pcbs[npcbs++]); 1241553Srgrimes break; 1251553Srgrimes case 's': 1261553Srgrimes ++sflag; 1271553Srgrimes break; 1281553Srgrimes case 't': 1291553Srgrimes ++tflag; 1301553Srgrimes break; 1311553Srgrimes case '?': 1321553Srgrimes default: 13330643Scharnier usage(); 1341553Srgrimes } 1351553Srgrimes argc -= optind; 1361553Srgrimes argv += optind; 1371553Srgrimes 1381553Srgrimes core = _PATH_KMEM; 1391553Srgrimes if (argc > 0) { 140100114Salfred syst = *argv; 1411553Srgrimes argc--, argv++; 1421553Srgrimes if (argc > 0) { 1431553Srgrimes core = *argv; 1441553Srgrimes argc--, argv++; 1451553Srgrimes ++kflag; 1461553Srgrimes } 1471553Srgrimes /* 1481553Srgrimes * Discard setgid privileges if not the running kernel so that 1491553Srgrimes * bad guys can't print interesting stuff from kernel memory. 1501553Srgrimes */ 1511553Srgrimes setgid(getgid()); 1521553Srgrimes } 1531553Srgrimes else 154100114Salfred syst = getbootfile(); 1551553Srgrimes 156100114Salfred if (nlist(syst, nl) < 0 || !nl[0].n_value) 157100114Salfred errx(1, "%s: no namelist", syst); 15830643Scharnier if ((memf = open(core, O_RDONLY)) < 0) 15930643Scharnier err(2, "%s", core); 16082664Sru setgid(getgid()); 16130643Scharnier if (kflag) 16230643Scharnier errx(1, "can't do core files yet"); 1631553Srgrimes (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET); 1641553Srgrimes if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) != 16530643Scharnier sizeof(tcp_debx)) 16630643Scharnier err(3, "tcp_debx"); 1671553Srgrimes (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET); 1681553Srgrimes if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) != 16930643Scharnier sizeof(tcp_debug)) 17030643Scharnier err(3, "tcp_debug"); 1711553Srgrimes /* 1721553Srgrimes * If no control blocks have been specified, figure 1731553Srgrimes * out how many distinct one we have and summarize 1741553Srgrimes * them in tcp_pcbs for sorting the trace records 1751553Srgrimes * below. 1761553Srgrimes */ 1771553Srgrimes if (!npcbs) { 1781553Srgrimes for (i = 0; i < TCP_NDEBUG; i++) { 1791553Srgrimes register struct tcp_debug *td = &tcp_debug[i]; 1801553Srgrimes register int j; 1811553Srgrimes 1821553Srgrimes if (td->td_tcb == 0) 1831553Srgrimes continue; 1841553Srgrimes for (j = 0; j < npcbs; j++) 1851553Srgrimes if (tcp_pcbs[j] == td->td_tcb) 1861553Srgrimes break; 1871553Srgrimes if (j >= npcbs) 1881553Srgrimes tcp_pcbs[npcbs++] = td->td_tcb; 1891553Srgrimes } 1901553Srgrimes if (!npcbs) 1911553Srgrimes exit(0); 1921553Srgrimes } 1931553Srgrimes qsort(tcp_pcbs, npcbs, sizeof(caddr_t), numeric); 1941553Srgrimes if (jflag) { 1951553Srgrimes for (i = 0;;) { 196100114Salfred printf("%p", (void *)tcp_pcbs[i]); 1971553Srgrimes if (++i == npcbs) 1981553Srgrimes break; 1991553Srgrimes fputs(", ", stdout); 2001553Srgrimes } 2011553Srgrimes putchar('\n'); 2021553Srgrimes } 2031553Srgrimes else for (i = 0; i < npcbs; i++) { 204100165Sdes printf("\n%p:\n", tcp_pcbs[i]); 2051553Srgrimes dotrace(tcp_pcbs[i]); 2061553Srgrimes } 2071553Srgrimes exit(0); 2081553Srgrimes} 2091553Srgrimes 21030643Scharnierstatic void 21130643Scharnierusage() 21230643Scharnier{ 21330643Scharnier (void)fprintf(stderr, 21430643Scharnier "usage: trpt [-afjst] [-p hex-address] [system [core]]\n"); 21530643Scharnier exit(1); 21630643Scharnier} 21730643Scharnier 21830643Scharniervoid 2191553Srgrimesdotrace(tcpcb) 2201553Srgrimes register caddr_t tcpcb; 2211553Srgrimes{ 2221553Srgrimes register struct tcp_debug *td; 2231553Srgrimes register int i; 22456801Sshin int prev_debx = tcp_debx, family; 2251553Srgrimes 2261553Srgrimesagain: if (--tcp_debx < 0) 2271553Srgrimes tcp_debx = TCP_NDEBUG - 1; 2281553Srgrimes for (i = prev_debx % TCP_NDEBUG; i < TCP_NDEBUG; i++) { 2291553Srgrimes td = &tcp_debug[i]; 2301553Srgrimes if (tcpcb && td->td_tcb != tcpcb) 2311553Srgrimes continue; 2321553Srgrimes ntime = ntohl(td->td_time); 23356801Sshin#ifdef INET6 23456801Sshin family = td->td_family; 23556801Sshin#else 23656801Sshin family = AF_INET; 23756801Sshin#endif 23856801Sshin switch(family) { 23956801Sshin case AF_INET: 24056801Sshin tcp_trace(td->td_act, td->td_ostate, 24156801Sshin &td->td_cb, td->td_family, &td->td_ti.ti_i, 24256801Sshin &td->td_ti.ti_t, td->td_req); 24356801Sshin break; 24456801Sshin#ifdef INET6 24556801Sshin case AF_INET6: 24656801Sshin tcp_trace(td->td_act, td->td_ostate, 24756801Sshin &td->td_cb, td->td_family, &td->td_ti6.ip6, 24856801Sshin &td->td_ti6.th, td->td_req); 24956801Sshin break; 25056801Sshin#endif 25156801Sshin } 2521553Srgrimes if (i == tcp_debx) 2531553Srgrimes goto done; 2541553Srgrimes } 2551553Srgrimes for (i = 0; i <= tcp_debx % TCP_NDEBUG; i++) { 2561553Srgrimes td = &tcp_debug[i]; 2571553Srgrimes if (tcpcb && td->td_tcb != tcpcb) 2581553Srgrimes continue; 2591553Srgrimes ntime = ntohl(td->td_time); 26056801Sshin#ifdef INET6 26156801Sshin family = td->td_family; 26256801Sshin#else 26356801Sshin family = AF_INET; 26456801Sshin#endif 26556801Sshin switch(family) { 26656801Sshin case AF_INET: 26756801Sshin tcp_trace(td->td_act, td->td_ostate, 26856801Sshin &td->td_cb, td->td_family, &td->td_ti.ti_i, 26956801Sshin &td->td_ti.ti_t, td->td_req); 27056801Sshin break; 27156801Sshin#ifdef INET6 27256801Sshin case AF_INET6: 27356801Sshin tcp_trace(td->td_act, td->td_ostate, 27456801Sshin &td->td_cb, td->td_family, &td->td_ti6.ip6, 27556801Sshin &td->td_ti6.th, td->td_req); 27656801Sshin break; 27756801Sshin#endif 27856801Sshin } 2791553Srgrimes } 2801553Srgrimesdone: if (follow) { 2811553Srgrimes prev_debx = tcp_debx + 1; 2821553Srgrimes if (prev_debx >= TCP_NDEBUG) 2831553Srgrimes prev_debx = 0; 2841553Srgrimes do { 2851553Srgrimes sleep(1); 2861553Srgrimes (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET); 2871553Srgrimes if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) != 28830643Scharnier sizeof(tcp_debx)) 28930643Scharnier err(3, "tcp_debx"); 2901553Srgrimes } while (tcp_debx == prev_debx); 2911553Srgrimes (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET); 2921553Srgrimes if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) != 29330643Scharnier sizeof(tcp_debug)) 29430643Scharnier err(3, "tcp_debug"); 2951553Srgrimes goto again; 2961553Srgrimes } 2971553Srgrimes} 2981553Srgrimes 2991553Srgrimes/* 3001553Srgrimes * Tcp debug routines 3011553Srgrimes */ 3021553Srgrimes/*ARGSUSED*/ 30330643Scharniervoid 304189090Sedtcp_trace(short act, short ostate, struct tcpcb *tp, int family __unused, 305189090Sed void *ip, struct tcphdr *th, int req) 3061553Srgrimes{ 3071553Srgrimes tcp_seq seq, ack; 3081553Srgrimes int flags, len, win, timer; 30955679Sshin struct ip *ip4; 31055679Sshin#ifdef INET6 31155679Sshin int isipv6, nopkt = 1; 31255679Sshin struct ip6_hdr *ip6; 31355679Sshin char ntop_buf[INET6_ADDRSTRLEN]; 31455679Sshin#endif 3151553Srgrimes 31655679Sshin#ifdef INET6 31756801Sshin switch (family) { 31856801Sshin case AF_INET: 31955679Sshin nopkt = 0; 32056801Sshin isipv6 = 0; 32155679Sshin ip4 = (struct ip *)ip; 32255679Sshin break; 32356801Sshin case AF_INET6: 32455679Sshin nopkt = 0; 32555679Sshin isipv6 = 1; 32655679Sshin ip6 = (struct ip6_hdr *)ip; 32755679Sshin case 0: 32855679Sshin default: 32955679Sshin break; 33055679Sshin } 33155679Sshin#else 33255679Sshin ip4 = (struct ip *)ip; 33355679Sshin#endif 334100114Salfred printf("%03ld %s:%s ", (long)((ntime/10) % 1000), tcpstates[ostate], 3351553Srgrimes tanames[act]); 3361553Srgrimes switch (act) { 3371553Srgrimes case TA_INPUT: 3381553Srgrimes case TA_OUTPUT: 3391553Srgrimes case TA_DROP: 34055679Sshin#ifdef INET6 34155679Sshin if (nopkt != 0) 34255679Sshin break; 34355679Sshin#endif 3441553Srgrimes if (aflag) { 3451553Srgrimes printf("(src=%s,%u, ", 34655679Sshin 34755679Sshin#ifdef INET6 34855679Sshin isipv6 34955679Sshin ? inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf, 35055679Sshin sizeof(ntop_buf)) : 35155679Sshin#endif 35255679Sshin inet_ntoa(ip4->ip_src), 35355679Sshin ntohs(th->th_sport)); 3541553Srgrimes printf("dst=%s,%u)", 35555679Sshin#ifdef INET6 35655679Sshin isipv6 35755679Sshin ? inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf, 35855679Sshin sizeof(ntop_buf)) : 35955679Sshin#endif 36055679Sshin inet_ntoa(ip4->ip_dst), 36155679Sshin ntohs(th->th_dport)); 3621553Srgrimes } 36355679Sshin seq = th->th_seq; 36455679Sshin ack = th->th_ack; 36555679Sshin 36655679Sshin len = 36755679Sshin#ifdef INET6 36855679Sshin isipv6 ? ip6->ip6_plen : 36955679Sshin#endif 37055679Sshin ip4->ip_len; 37155679Sshin win = th->th_win; 3721553Srgrimes if (act == TA_OUTPUT) { 3731553Srgrimes seq = ntohl(seq); 3741553Srgrimes ack = ntohl(ack); 3751553Srgrimes len = ntohs(len); 3761553Srgrimes win = ntohs(win); 3771553Srgrimes } 3781553Srgrimes if (act == TA_OUTPUT) 3791553Srgrimes len -= sizeof(struct tcphdr); 3801553Srgrimes if (len) 381100114Salfred printf("[%lx..%lx)", (u_long)seq, (u_long)(seq + len)); 3821553Srgrimes else 383100114Salfred printf("%lx", (u_long)seq); 384100114Salfred printf("@%lx", (u_long)ack); 3851553Srgrimes if (win) 3861553Srgrimes printf("(win=%x)", win); 38755679Sshin flags = th->th_flags; 3881553Srgrimes if (flags) { 389100114Salfred const char *cp = "<"; 3901553Srgrimes#define pf(flag, string) { \ 39155679Sshin if (th->th_flags&flag) { \ 3921553Srgrimes (void)printf("%s%s", cp, string); \ 3931553Srgrimes cp = ","; \ 3941553Srgrimes } \ 3951553Srgrimes} 3961553Srgrimes pf(TH_SYN, "SYN"); 3971553Srgrimes pf(TH_ACK, "ACK"); 3981553Srgrimes pf(TH_FIN, "FIN"); 3991553Srgrimes pf(TH_RST, "RST"); 4001553Srgrimes pf(TH_PUSH, "PUSH"); 4011553Srgrimes pf(TH_URG, "URG"); 4021553Srgrimes printf(">"); 4031553Srgrimes } 4041553Srgrimes break; 4051553Srgrimes case TA_USER: 4061553Srgrimes timer = req >> 8; 4071553Srgrimes req &= 0xff; 4081553Srgrimes printf("%s", prurequests[req]); 4091553Srgrimes if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO) 4101553Srgrimes printf("<%s>", tcptimers[timer]); 4111553Srgrimes break; 4121553Srgrimes } 4131553Srgrimes printf(" -> %s", tcpstates[tp->t_state]); 4141553Srgrimes /* print out internal state of tp !?! */ 4151553Srgrimes printf("\n"); 4161553Srgrimes if (sflag) { 417100114Salfred printf("\trcv_nxt %lx rcv_wnd %lx snd_una %lx snd_nxt %lx snd_max %lx\n", 418100114Salfred (u_long)tp->rcv_nxt, tp->rcv_wnd, 419100114Salfred (u_long)tp->snd_una, (u_long)tp->snd_nxt, 420100114Salfred (u_long)tp->snd_max); 421100114Salfred printf("\tsnd_wl1 %lx snd_wl2 %lx snd_wnd %lx\n", 422100114Salfred (u_long)tp->snd_wl1, 423100114Salfred (u_long)tp->snd_wl2, tp->snd_wnd); 4241553Srgrimes } 4251553Srgrimes /* print out timers? */ 42650680Sjlemon#if 0 42750680Sjlemon /* 42850680Sjlemon * XXX 42950680Sjlemon * kernel now uses callouts, not integer time values. 43050680Sjlemon */ 4311553Srgrimes if (tflag) { 4321553Srgrimes register char *cp = "\t"; 4331553Srgrimes register int i; 4341553Srgrimes 4351553Srgrimes for (i = 0; i < TCPT_NTIMERS; i++) { 4361553Srgrimes if (tp->t_timer[i] == 0) 4371553Srgrimes continue; 4381553Srgrimes printf("%s%s=%d", cp, tcptimers[i], tp->t_timer[i]); 4391553Srgrimes if (i == TCPT_REXMT) 4401553Srgrimes printf(" (t_rxtshft=%d)", tp->t_rxtshift); 4411553Srgrimes cp = ", "; 4421553Srgrimes } 4431553Srgrimes if (*cp != '\t') 4441553Srgrimes putchar('\n'); 4451553Srgrimes } 44650680Sjlemon#endif 4471553Srgrimes} 4481553Srgrimes 44930643Scharnierint 45073732Sdwmalonenumeric(v1, v2) 45173732Sdwmalone const void *v1, *v2; 4521553Srgrimes{ 45373732Sdwmalone const caddr_t *c1 = v1, *c2 = v2; 4541553Srgrimes return(*c1 - *c2); 4551553Srgrimes} 4561553Srgrimes 45730643Scharniervoid 4581553Srgrimesklseek(fd, base, off) 4591553Srgrimes int fd, off; 4601553Srgrimes off_t base; 4611553Srgrimes{ 4621553Srgrimes (void)lseek(fd, base, off); 4631553Srgrimes} 464