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: releng/11.0/usr.sbin/trpt/trpt.c 287346 2015-09-01 06:32:02Z delphij $"); 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 */ 151287346Sdelphij if (setgid(getgid()) != 0) 152287346Sdelphij err(1, "setgid"); 1531553Srgrimes } 1541553Srgrimes else 155100114Salfred syst = getbootfile(); 1561553Srgrimes 157100114Salfred if (nlist(syst, nl) < 0 || !nl[0].n_value) 158100114Salfred errx(1, "%s: no namelist", syst); 15930643Scharnier if ((memf = open(core, O_RDONLY)) < 0) 16030643Scharnier err(2, "%s", core); 161287346Sdelphij if (setgid(getgid()) != 0) 162287346Sdelphij err(1, "setgid"); 16330643Scharnier if (kflag) 16430643Scharnier errx(1, "can't do core files yet"); 1651553Srgrimes (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET); 1661553Srgrimes if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) != 16730643Scharnier sizeof(tcp_debx)) 16830643Scharnier err(3, "tcp_debx"); 1691553Srgrimes (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET); 1701553Srgrimes if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) != 17130643Scharnier sizeof(tcp_debug)) 17230643Scharnier err(3, "tcp_debug"); 1731553Srgrimes /* 1741553Srgrimes * If no control blocks have been specified, figure 1751553Srgrimes * out how many distinct one we have and summarize 1761553Srgrimes * them in tcp_pcbs for sorting the trace records 1771553Srgrimes * below. 1781553Srgrimes */ 1791553Srgrimes if (!npcbs) { 1801553Srgrimes for (i = 0; i < TCP_NDEBUG; i++) { 1811553Srgrimes register struct tcp_debug *td = &tcp_debug[i]; 1821553Srgrimes register int j; 1831553Srgrimes 1841553Srgrimes if (td->td_tcb == 0) 1851553Srgrimes continue; 1861553Srgrimes for (j = 0; j < npcbs; j++) 1871553Srgrimes if (tcp_pcbs[j] == td->td_tcb) 1881553Srgrimes break; 1891553Srgrimes if (j >= npcbs) 1901553Srgrimes tcp_pcbs[npcbs++] = td->td_tcb; 1911553Srgrimes } 1921553Srgrimes if (!npcbs) 1931553Srgrimes exit(0); 1941553Srgrimes } 1951553Srgrimes qsort(tcp_pcbs, npcbs, sizeof(caddr_t), numeric); 1961553Srgrimes if (jflag) { 1971553Srgrimes for (i = 0;;) { 198100114Salfred printf("%p", (void *)tcp_pcbs[i]); 1991553Srgrimes if (++i == npcbs) 2001553Srgrimes break; 2011553Srgrimes fputs(", ", stdout); 2021553Srgrimes } 2031553Srgrimes putchar('\n'); 2041553Srgrimes } 2051553Srgrimes else for (i = 0; i < npcbs; i++) { 206100165Sdes printf("\n%p:\n", tcp_pcbs[i]); 2071553Srgrimes dotrace(tcp_pcbs[i]); 2081553Srgrimes } 2091553Srgrimes exit(0); 2101553Srgrimes} 2111553Srgrimes 21230643Scharnierstatic void 21330643Scharnierusage() 21430643Scharnier{ 21530643Scharnier (void)fprintf(stderr, 21630643Scharnier "usage: trpt [-afjst] [-p hex-address] [system [core]]\n"); 21730643Scharnier exit(1); 21830643Scharnier} 21930643Scharnier 22030643Scharniervoid 2211553Srgrimesdotrace(tcpcb) 2221553Srgrimes register caddr_t tcpcb; 2231553Srgrimes{ 2241553Srgrimes register struct tcp_debug *td; 2251553Srgrimes register int i; 22656801Sshin int prev_debx = tcp_debx, family; 2271553Srgrimes 2281553Srgrimesagain: if (--tcp_debx < 0) 2291553Srgrimes tcp_debx = TCP_NDEBUG - 1; 2301553Srgrimes for (i = prev_debx % TCP_NDEBUG; i < TCP_NDEBUG; i++) { 2311553Srgrimes td = &tcp_debug[i]; 2321553Srgrimes if (tcpcb && td->td_tcb != tcpcb) 2331553Srgrimes continue; 2341553Srgrimes ntime = ntohl(td->td_time); 23556801Sshin#ifdef INET6 23656801Sshin family = td->td_family; 23756801Sshin#else 23856801Sshin family = AF_INET; 23956801Sshin#endif 24056801Sshin switch(family) { 24156801Sshin case AF_INET: 24256801Sshin tcp_trace(td->td_act, td->td_ostate, 24356801Sshin &td->td_cb, td->td_family, &td->td_ti.ti_i, 24456801Sshin &td->td_ti.ti_t, td->td_req); 24556801Sshin break; 24656801Sshin#ifdef INET6 24756801Sshin case AF_INET6: 24856801Sshin tcp_trace(td->td_act, td->td_ostate, 24956801Sshin &td->td_cb, td->td_family, &td->td_ti6.ip6, 25056801Sshin &td->td_ti6.th, td->td_req); 25156801Sshin break; 25256801Sshin#endif 25356801Sshin } 2541553Srgrimes if (i == tcp_debx) 2551553Srgrimes goto done; 2561553Srgrimes } 2571553Srgrimes for (i = 0; i <= tcp_debx % TCP_NDEBUG; i++) { 2581553Srgrimes td = &tcp_debug[i]; 2591553Srgrimes if (tcpcb && td->td_tcb != tcpcb) 2601553Srgrimes continue; 2611553Srgrimes ntime = ntohl(td->td_time); 26256801Sshin#ifdef INET6 26356801Sshin family = td->td_family; 26456801Sshin#else 26556801Sshin family = AF_INET; 26656801Sshin#endif 26756801Sshin switch(family) { 26856801Sshin case AF_INET: 26956801Sshin tcp_trace(td->td_act, td->td_ostate, 27056801Sshin &td->td_cb, td->td_family, &td->td_ti.ti_i, 27156801Sshin &td->td_ti.ti_t, td->td_req); 27256801Sshin break; 27356801Sshin#ifdef INET6 27456801Sshin case AF_INET6: 27556801Sshin tcp_trace(td->td_act, td->td_ostate, 27656801Sshin &td->td_cb, td->td_family, &td->td_ti6.ip6, 27756801Sshin &td->td_ti6.th, td->td_req); 27856801Sshin break; 27956801Sshin#endif 28056801Sshin } 2811553Srgrimes } 2821553Srgrimesdone: if (follow) { 2831553Srgrimes prev_debx = tcp_debx + 1; 2841553Srgrimes if (prev_debx >= TCP_NDEBUG) 2851553Srgrimes prev_debx = 0; 2861553Srgrimes do { 2871553Srgrimes sleep(1); 2881553Srgrimes (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET); 2891553Srgrimes if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) != 29030643Scharnier sizeof(tcp_debx)) 29130643Scharnier err(3, "tcp_debx"); 2921553Srgrimes } while (tcp_debx == prev_debx); 2931553Srgrimes (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET); 2941553Srgrimes if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) != 29530643Scharnier sizeof(tcp_debug)) 29630643Scharnier err(3, "tcp_debug"); 2971553Srgrimes goto again; 2981553Srgrimes } 2991553Srgrimes} 3001553Srgrimes 3011553Srgrimes/* 3021553Srgrimes * Tcp debug routines 3031553Srgrimes */ 3041553Srgrimes/*ARGSUSED*/ 30530643Scharniervoid 306189090Sedtcp_trace(short act, short ostate, struct tcpcb *tp, int family __unused, 307189090Sed void *ip, struct tcphdr *th, int req) 3081553Srgrimes{ 3091553Srgrimes tcp_seq seq, ack; 3101553Srgrimes int flags, len, win, timer; 31155679Sshin struct ip *ip4; 31255679Sshin#ifdef INET6 31355679Sshin int isipv6, nopkt = 1; 31455679Sshin struct ip6_hdr *ip6; 31555679Sshin char ntop_buf[INET6_ADDRSTRLEN]; 31655679Sshin#endif 3171553Srgrimes 31855679Sshin#ifdef INET6 31956801Sshin switch (family) { 32056801Sshin case AF_INET: 32155679Sshin nopkt = 0; 32256801Sshin isipv6 = 0; 32355679Sshin ip4 = (struct ip *)ip; 32455679Sshin break; 32556801Sshin case AF_INET6: 32655679Sshin nopkt = 0; 32755679Sshin isipv6 = 1; 32855679Sshin ip6 = (struct ip6_hdr *)ip; 32955679Sshin case 0: 33055679Sshin default: 33155679Sshin break; 33255679Sshin } 33355679Sshin#else 33455679Sshin ip4 = (struct ip *)ip; 33555679Sshin#endif 336100114Salfred printf("%03ld %s:%s ", (long)((ntime/10) % 1000), tcpstates[ostate], 3371553Srgrimes tanames[act]); 3381553Srgrimes switch (act) { 3391553Srgrimes case TA_INPUT: 3401553Srgrimes case TA_OUTPUT: 3411553Srgrimes case TA_DROP: 34255679Sshin#ifdef INET6 34355679Sshin if (nopkt != 0) 34455679Sshin break; 34555679Sshin#endif 3461553Srgrimes if (aflag) { 3471553Srgrimes printf("(src=%s,%u, ", 34855679Sshin 34955679Sshin#ifdef INET6 35055679Sshin isipv6 35155679Sshin ? inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf, 35255679Sshin sizeof(ntop_buf)) : 35355679Sshin#endif 35455679Sshin inet_ntoa(ip4->ip_src), 35555679Sshin ntohs(th->th_sport)); 3561553Srgrimes printf("dst=%s,%u)", 35755679Sshin#ifdef INET6 35855679Sshin isipv6 35955679Sshin ? inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf, 36055679Sshin sizeof(ntop_buf)) : 36155679Sshin#endif 36255679Sshin inet_ntoa(ip4->ip_dst), 36355679Sshin ntohs(th->th_dport)); 3641553Srgrimes } 36555679Sshin seq = th->th_seq; 36655679Sshin ack = th->th_ack; 36755679Sshin 36855679Sshin len = 36955679Sshin#ifdef INET6 37055679Sshin isipv6 ? ip6->ip6_plen : 37155679Sshin#endif 37255679Sshin ip4->ip_len; 37355679Sshin win = th->th_win; 3741553Srgrimes if (act == TA_OUTPUT) { 3751553Srgrimes seq = ntohl(seq); 3761553Srgrimes ack = ntohl(ack); 3771553Srgrimes len = ntohs(len); 3781553Srgrimes win = ntohs(win); 3791553Srgrimes } 3801553Srgrimes if (act == TA_OUTPUT) 3811553Srgrimes len -= sizeof(struct tcphdr); 3821553Srgrimes if (len) 383100114Salfred printf("[%lx..%lx)", (u_long)seq, (u_long)(seq + len)); 3841553Srgrimes else 385100114Salfred printf("%lx", (u_long)seq); 386100114Salfred printf("@%lx", (u_long)ack); 3871553Srgrimes if (win) 3881553Srgrimes printf("(win=%x)", win); 38955679Sshin flags = th->th_flags; 3901553Srgrimes if (flags) { 391100114Salfred const char *cp = "<"; 3921553Srgrimes#define pf(flag, string) { \ 39355679Sshin if (th->th_flags&flag) { \ 3941553Srgrimes (void)printf("%s%s", cp, string); \ 3951553Srgrimes cp = ","; \ 3961553Srgrimes } \ 3971553Srgrimes} 3981553Srgrimes pf(TH_SYN, "SYN"); 3991553Srgrimes pf(TH_ACK, "ACK"); 4001553Srgrimes pf(TH_FIN, "FIN"); 4011553Srgrimes pf(TH_RST, "RST"); 4021553Srgrimes pf(TH_PUSH, "PUSH"); 4031553Srgrimes pf(TH_URG, "URG"); 4041553Srgrimes printf(">"); 4051553Srgrimes } 4061553Srgrimes break; 4071553Srgrimes case TA_USER: 4081553Srgrimes timer = req >> 8; 4091553Srgrimes req &= 0xff; 4101553Srgrimes printf("%s", prurequests[req]); 4111553Srgrimes if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO) 4121553Srgrimes printf("<%s>", tcptimers[timer]); 4131553Srgrimes break; 4141553Srgrimes } 4151553Srgrimes printf(" -> %s", tcpstates[tp->t_state]); 4161553Srgrimes /* print out internal state of tp !?! */ 4171553Srgrimes printf("\n"); 4181553Srgrimes if (sflag) { 419100114Salfred printf("\trcv_nxt %lx rcv_wnd %lx snd_una %lx snd_nxt %lx snd_max %lx\n", 420100114Salfred (u_long)tp->rcv_nxt, tp->rcv_wnd, 421100114Salfred (u_long)tp->snd_una, (u_long)tp->snd_nxt, 422100114Salfred (u_long)tp->snd_max); 423100114Salfred printf("\tsnd_wl1 %lx snd_wl2 %lx snd_wnd %lx\n", 424100114Salfred (u_long)tp->snd_wl1, 425100114Salfred (u_long)tp->snd_wl2, tp->snd_wnd); 4261553Srgrimes } 4271553Srgrimes /* print out timers? */ 42850680Sjlemon#if 0 42950680Sjlemon /* 43050680Sjlemon * XXX 43150680Sjlemon * kernel now uses callouts, not integer time values. 43250680Sjlemon */ 4331553Srgrimes if (tflag) { 4341553Srgrimes register char *cp = "\t"; 4351553Srgrimes register int i; 4361553Srgrimes 4371553Srgrimes for (i = 0; i < TCPT_NTIMERS; i++) { 4381553Srgrimes if (tp->t_timer[i] == 0) 4391553Srgrimes continue; 4401553Srgrimes printf("%s%s=%d", cp, tcptimers[i], tp->t_timer[i]); 4411553Srgrimes if (i == TCPT_REXMT) 4421553Srgrimes printf(" (t_rxtshft=%d)", tp->t_rxtshift); 4431553Srgrimes cp = ", "; 4441553Srgrimes } 4451553Srgrimes if (*cp != '\t') 4461553Srgrimes putchar('\n'); 4471553Srgrimes } 44850680Sjlemon#endif 4491553Srgrimes} 4501553Srgrimes 45130643Scharnierint 45273732Sdwmalonenumeric(v1, v2) 45373732Sdwmalone const void *v1, *v2; 4541553Srgrimes{ 45573732Sdwmalone const caddr_t *c1 = v1, *c2 = v2; 4561553Srgrimes return(*c1 - *c2); 4571553Srgrimes} 4581553Srgrimes 45930643Scharniervoid 4601553Srgrimesklseek(fd, base, off) 4611553Srgrimes int fd, off; 4621553Srgrimes off_t base; 4631553Srgrimes{ 4641553Srgrimes (void)lseek(fd, base, off); 4651553Srgrimes} 466