1/*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1983, 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#if 0 33#ifndef lint 34static const char copyright[] = 35"@(#) Copyright (c) 1983, 1988, 1993\n\ 36 The Regents of the University of California. All rights reserved.\n"; 37#endif /* not lint */ 38 39#ifndef lint 40static char sccsid[] = "@(#)trpt.c 8.1 (Berkeley) 6/6/93"; 41#endif /* not lint */ 42#endif 43#include <sys/cdefs.h> 44__FBSDID("$FreeBSD$"); 45 46#include <sys/param.h> 47#include <sys/queue.h> 48#include <sys/socket.h> 49#include <sys/socketvar.h> 50#define PRUREQUESTS 51#include <sys/protosw.h> 52#include <sys/file.h> 53#include <sys/time.h> 54 55#include <net/route.h> 56#include <net/if.h> 57 58#include <netinet/in.h> 59#include <netinet/in_systm.h> 60#include <netinet/ip.h> 61#ifdef INET6 62#include <netinet/ip6.h> 63#endif 64#include <netinet/ip_var.h> 65#include <netinet/tcp.h> 66#define TCPSTATES 67#include <netinet/tcp_fsm.h> 68#include <netinet/tcp_seq.h> 69#define TCPTIMERS 70#include <netinet/tcp_timer.h> 71#define _WANT_TCPCB 72#include <netinet/tcp_var.h> 73#include <netinet/tcpip.h> 74#define TANAMES 75#include <netinet/tcp_debug.h> 76 77#include <arpa/inet.h> 78 79#include <err.h> 80#include <nlist.h> 81#include <paths.h> 82#include <stdbool.h> 83#include <stdio.h> 84#include <stdlib.h> 85#include <string.h> 86#include <unistd.h> 87 88static struct nlist nl[3]; 89#define N_TCP_DEBUG 0 90#define N_TCP_DEBX 1 91 92static caddr_t tcp_pcbs[TCP_NDEBUG]; 93static n_time ntime; 94static int aflag, kflag, memf, follow, sflag; 95 96static void dotrace(caddr_t); 97static void klseek(int, off_t, int); 98static int numeric(const void *, const void *); 99static void tcp_trace(short, short, struct tcpcb *, int, void *, struct tcphdr *, int); 100static void usage(void); 101 102int 103main(int argc, char **argv) 104{ 105 int ch, i, jflag, npcbs; 106 const char *core, *syst; 107 108 nl[0].n_name = strdup("_tcp_debug"); 109 nl[1].n_name = strdup("_tcp_debx"); 110 111 jflag = npcbs = 0; 112 while ((ch = getopt(argc, argv, "afjp:s")) != -1) 113 switch (ch) { 114 case 'a': 115 ++aflag; 116 break; 117 case 'f': 118 ++follow; 119 setlinebuf(stdout); 120 break; 121 case 'j': 122 ++jflag; 123 break; 124 case 'p': 125 if (npcbs >= TCP_NDEBUG) 126 errx(1, "too many pcb's specified"); 127 (void)sscanf(optarg, "%x", (int *)&tcp_pcbs[npcbs++]); 128 break; 129 case 's': 130 ++sflag; 131 break; 132 case '?': 133 default: 134 usage(); 135 } 136 argc -= optind; 137 argv += optind; 138 139 core = _PATH_KMEM; 140 if (argc > 0) { 141 syst = *argv; 142 argc--, argv++; 143 if (argc > 0) { 144 core = *argv; 145 argc--, argv++; 146 ++kflag; 147 } 148 /* 149 * Discard setgid privileges if not the running kernel so that 150 * bad guys can't print interesting stuff from kernel memory. 151 */ 152 if (setgid(getgid()) != 0) 153 err(1, "setgid"); 154 } else 155 syst = getbootfile(); 156 157 if (nlist(syst, nl) < 0 || !nl[0].n_value) 158 errx(1, "%s: no namelist", syst); 159 if ((memf = open(core, O_RDONLY)) < 0) 160 err(2, "%s", core); 161 if (setgid(getgid()) != 0) 162 err(1, "setgid"); 163 if (kflag) 164 errx(1, "can't do core files yet"); 165 (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET); 166 if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) != 167 sizeof(tcp_debx)) 168 err(3, "tcp_debx"); 169 (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET); 170 if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) != 171 sizeof(tcp_debug)) 172 err(3, "tcp_debug"); 173 /* 174 * If no control blocks have been specified, figure 175 * out how many distinct one we have and summarize 176 * them in tcp_pcbs for sorting the trace records 177 * below. 178 */ 179 if (!npcbs) { 180 for (i = 0; i < TCP_NDEBUG; i++) { 181 struct tcp_debug *td = &tcp_debug[i]; 182 int j; 183 184 if (td->td_tcb == 0) 185 continue; 186 for (j = 0; j < npcbs; j++) 187 if (tcp_pcbs[j] == td->td_tcb) 188 break; 189 if (j >= npcbs) 190 tcp_pcbs[npcbs++] = td->td_tcb; 191 } 192 if (!npcbs) 193 exit(0); 194 } 195 qsort(tcp_pcbs, npcbs, sizeof(caddr_t), numeric); 196 if (jflag) { 197 for (i = 0;;) { 198 printf("%p", (void *)tcp_pcbs[i]); 199 if (++i == npcbs) 200 break; 201 fputs(", ", stdout); 202 } 203 putchar('\n'); 204 } else 205 for (i = 0; i < npcbs; i++) { 206 printf("\n%p:\n", tcp_pcbs[i]); 207 dotrace(tcp_pcbs[i]); 208 } 209 exit(0); 210} 211 212static void 213usage(void) 214{ 215 (void)fprintf(stderr, 216 "usage: trpt [-afjs] [-p hex-address] [system [core]]\n"); 217 exit(1); 218} 219 220static void 221dotrace(caddr_t tcpcb) 222{ 223 struct tcp_debug *td; 224 int i; 225 int prev_debx = tcp_debx, family; 226 227again: 228 if (--tcp_debx < 0) 229 tcp_debx = TCP_NDEBUG - 1; 230 for (i = prev_debx % TCP_NDEBUG; i < TCP_NDEBUG; i++) { 231 td = &tcp_debug[i]; 232 if (tcpcb && td->td_tcb != tcpcb) 233 continue; 234 ntime = ntohl(td->td_time); 235#ifdef INET6 236 family = td->td_family; 237#else 238 family = AF_INET; 239#endif 240 switch (family) { 241 case AF_INET: 242 tcp_trace(td->td_act, td->td_ostate, &td->td_cb, 243 td->td_family, &td->td_ti.ti_i, &td->td_ti.ti_t, 244 td->td_req); 245 break; 246#ifdef INET6 247 case AF_INET6: 248 tcp_trace(td->td_act, td->td_ostate, &td->td_cb, 249 td->td_family, &td->td_ti6.ip6, &td->td_ti6.th, 250 td->td_req); 251 break; 252#endif 253 } 254 if (i == tcp_debx) 255 goto done; 256 } 257 for (i = 0; i <= tcp_debx % TCP_NDEBUG; i++) { 258 td = &tcp_debug[i]; 259 if (tcpcb && td->td_tcb != tcpcb) 260 continue; 261 ntime = ntohl(td->td_time); 262#ifdef INET6 263 family = td->td_family; 264#else 265 family = AF_INET; 266#endif 267 switch (family) { 268 case AF_INET: 269 tcp_trace(td->td_act, td->td_ostate, &td->td_cb, 270 td->td_family, &td->td_ti.ti_i, &td->td_ti.ti_t, 271 td->td_req); 272 break; 273#ifdef INET6 274 case AF_INET6: 275 tcp_trace(td->td_act, td->td_ostate, &td->td_cb, 276 td->td_family, &td->td_ti6.ip6, &td->td_ti6.th, 277 td->td_req); 278 break; 279#endif 280 } 281 } 282done: 283 if (follow) { 284 prev_debx = tcp_debx + 1; 285 if (prev_debx >= TCP_NDEBUG) 286 prev_debx = 0; 287 do { 288 sleep(1); 289 (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET); 290 if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) != 291 sizeof(tcp_debx)) 292 err(3, "tcp_debx"); 293 } while (tcp_debx == prev_debx); 294 (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET); 295 if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) != 296 sizeof(tcp_debug)) 297 err(3, "tcp_debug"); 298 goto again; 299 } 300} 301 302/* 303 * Tcp debug routines 304 */ 305/*ARGSUSED*/ 306static void 307tcp_trace(short act, short ostate, struct tcpcb *tp, int family __unused, 308 void *ip, struct tcphdr *th, int req) 309{ 310 tcp_seq seq, ack; 311 int flags, len, win, timer; 312 struct ip *ip4; 313#ifdef INET6 314 bool isipv6, nopkt = true; 315 struct ip6_hdr *ip6; 316 char ntop_buf[INET6_ADDRSTRLEN]; 317#endif 318 319#ifdef INET6 320 /* Appease GCC -Wmaybe-uninitialized */ 321 ip4 = NULL; 322 ip6 = NULL; 323 isipv6 = false; 324 325 switch (family) { 326 case AF_INET: 327 nopkt = false; 328 isipv6 = false; 329 ip4 = (struct ip *)ip; 330 break; 331 case AF_INET6: 332 nopkt = false; 333 isipv6 = true; 334 ip6 = (struct ip6_hdr *)ip; 335 case 0: 336 default: 337 break; 338 } 339#else 340 ip4 = (struct ip *)ip; 341#endif 342 printf("%03ld %s:%s ", (long)((ntime / 10) % 1000), tcpstates[ostate], 343 tanames[act]); 344 switch (act) { 345 case TA_INPUT: 346 case TA_OUTPUT: 347 case TA_DROP: 348#ifdef INET6 349 if (nopkt) 350 break; 351#endif 352 if (aflag) { 353 printf("(src=%s,%u, ", 354 355#ifdef INET6 356 isipv6 ? inet_ntop(AF_INET6, &ip6->ip6_src, 357 ntop_buf, sizeof(ntop_buf)) : 358#endif 359 inet_ntoa(ip4->ip_src), ntohs(th->th_sport)); 360 printf("dst=%s,%u)", 361#ifdef INET6 362 isipv6 ? inet_ntop(AF_INET6, &ip6->ip6_dst, 363 ntop_buf, sizeof(ntop_buf)) : 364#endif 365 inet_ntoa(ip4->ip_dst), ntohs(th->th_dport)); 366 } 367 seq = th->th_seq; 368 ack = th->th_ack; 369 370 len = 371#ifdef INET6 372 isipv6 ? ip6->ip6_plen : 373#endif 374 ip4->ip_len; 375 win = th->th_win; 376 if (act == TA_OUTPUT) { 377 seq = ntohl(seq); 378 ack = ntohl(ack); 379 len = ntohs(len); 380 win = ntohs(win); 381 } 382 if (act == TA_OUTPUT) 383 len -= sizeof(struct tcphdr); 384 if (len) 385 printf("[%lx..%lx)", (u_long)seq, (u_long)(seq + len)); 386 else 387 printf("%lx", (u_long)seq); 388 printf("@%lx", (u_long)ack); 389 if (win) 390 printf("(win=%x)", win); 391 flags = th->th_flags; 392 if (flags) { 393 const char *cp = "<"; 394#define pf(flag, string) { \ 395 if (th->th_flags&flag) { \ 396 (void)printf("%s%s", cp, string); \ 397 cp = ","; \ 398 } \ 399} 400 pf(TH_SYN, "SYN"); 401 pf(TH_ACK, "ACK"); 402 pf(TH_FIN, "FIN"); 403 pf(TH_RST, "RST"); 404 pf(TH_PUSH, "PUSH"); 405 pf(TH_URG, "URG"); 406 printf(">"); 407 } 408 break; 409 case TA_USER: 410 timer = req >> 8; 411 req &= 0xff; 412 printf("%s", prurequests[req]); 413 if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO) 414 printf("<%s>", tcptimers[timer]); 415 break; 416 } 417 printf(" -> %s", tcpstates[tp->t_state]); 418 /* print out internal state of tp !?! */ 419 printf("\n"); 420 if (sflag) { 421 printf("\trcv_nxt %lx rcv_wnd %lx snd_una %lx snd_nxt %lx snd_max %lx\n", 422 (u_long)tp->rcv_nxt, (u_long)tp->rcv_wnd, 423 (u_long)tp->snd_una, (u_long)tp->snd_nxt, 424 (u_long)tp->snd_max); 425 printf("\tsnd_wl1 %lx snd_wl2 %lx snd_wnd %lx\n", 426 (u_long)tp->snd_wl1, (u_long)tp->snd_wl2, 427 (u_long)tp->snd_wnd); 428 } 429} 430 431static int 432numeric(const void *v1, const void *v2) 433{ 434 const caddr_t *c1 = v1, *c2 = v2; 435 436 return (*c1 - *c2); 437} 438 439static void 440klseek(int fd, off_t base, int off) 441{ 442 (void)lseek(fd, base, off); 443} 444