trpt.c revision 330897
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 * 4. 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: stable/11/usr.sbin/trpt/trpt.c 330897 2018-03-14 03:19:51Z eadler $"); 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#include <netinet/tcp_var.h> 72#include <netinet/tcpip.h> 73#define TANAMES 74#include <netinet/tcp_debug.h> 75 76#include <arpa/inet.h> 77 78#include <err.h> 79#include <nlist.h> 80#include <paths.h> 81#include <stdio.h> 82#include <stdlib.h> 83#include <string.h> 84#include <unistd.h> 85 86struct nlist nl[3]; 87#define N_TCP_DEBUG 0 88#define N_TCP_DEBX 1 89 90static caddr_t tcp_pcbs[TCP_NDEBUG]; 91static n_time ntime; 92static int aflag, kflag, memf, follow, sflag, tflag; 93 94void dotrace(caddr_t); 95void klseek(int, off_t, int); 96int numeric(const void *, const void *); 97void tcp_trace(short, short, struct tcpcb *, int, void *, struct tcphdr *, int); 98static void usage(void); 99 100int 101main(int argc, char **argv) 102{ 103 int ch, i, jflag, npcbs; 104 const char *core, *syst; 105 106 nl[0].n_name = strdup("_tcp_debug"); 107 nl[1].n_name = strdup("_tcp_debx"); 108 109 jflag = npcbs = 0; 110 while ((ch = getopt(argc, argv, "afjp:st")) != -1) 111 switch (ch) { 112 case 'a': 113 ++aflag; 114 break; 115 case 'f': 116 ++follow; 117 setlinebuf(stdout); 118 break; 119 case 'j': 120 ++jflag; 121 break; 122 case 'p': 123 if (npcbs >= TCP_NDEBUG) 124 errx(1, "too many pcb's specified"); 125 (void)sscanf(optarg, "%x", (int *)&tcp_pcbs[npcbs++]); 126 break; 127 case 's': 128 ++sflag; 129 break; 130 case 't': 131 ++tflag; 132 break; 133 case '?': 134 default: 135 usage(); 136 } 137 argc -= optind; 138 argv += optind; 139 140 core = _PATH_KMEM; 141 if (argc > 0) { 142 syst = *argv; 143 argc--, argv++; 144 if (argc > 0) { 145 core = *argv; 146 argc--, argv++; 147 ++kflag; 148 } 149 /* 150 * Discard setgid privileges if not the running kernel so that 151 * bad guys can't print interesting stuff from kernel memory. 152 */ 153 if (setgid(getgid()) != 0) 154 err(1, "setgid"); 155 } 156 else 157 syst = getbootfile(); 158 159 if (nlist(syst, nl) < 0 || !nl[0].n_value) 160 errx(1, "%s: no namelist", syst); 161 if ((memf = open(core, O_RDONLY)) < 0) 162 err(2, "%s", core); 163 if (setgid(getgid()) != 0) 164 err(1, "setgid"); 165 if (kflag) 166 errx(1, "can't do core files yet"); 167 (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET); 168 if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) != 169 sizeof(tcp_debx)) 170 err(3, "tcp_debx"); 171 (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET); 172 if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) != 173 sizeof(tcp_debug)) 174 err(3, "tcp_debug"); 175 /* 176 * If no control blocks have been specified, figure 177 * out how many distinct one we have and summarize 178 * them in tcp_pcbs for sorting the trace records 179 * below. 180 */ 181 if (!npcbs) { 182 for (i = 0; i < TCP_NDEBUG; i++) { 183 register struct tcp_debug *td = &tcp_debug[i]; 184 register int j; 185 186 if (td->td_tcb == 0) 187 continue; 188 for (j = 0; j < npcbs; j++) 189 if (tcp_pcbs[j] == td->td_tcb) 190 break; 191 if (j >= npcbs) 192 tcp_pcbs[npcbs++] = td->td_tcb; 193 } 194 if (!npcbs) 195 exit(0); 196 } 197 qsort(tcp_pcbs, npcbs, sizeof(caddr_t), numeric); 198 if (jflag) { 199 for (i = 0;;) { 200 printf("%p", (void *)tcp_pcbs[i]); 201 if (++i == npcbs) 202 break; 203 fputs(", ", stdout); 204 } 205 putchar('\n'); 206 } 207 else for (i = 0; i < npcbs; i++) { 208 printf("\n%p:\n", tcp_pcbs[i]); 209 dotrace(tcp_pcbs[i]); 210 } 211 exit(0); 212} 213 214static void 215usage() 216{ 217 (void)fprintf(stderr, 218 "usage: trpt [-afjst] [-p hex-address] [system [core]]\n"); 219 exit(1); 220} 221 222void 223dotrace(tcpcb) 224 register caddr_t tcpcb; 225{ 226 register struct tcp_debug *td; 227 register int i; 228 int prev_debx = tcp_debx, family; 229 230again: if (--tcp_debx < 0) 231 tcp_debx = TCP_NDEBUG - 1; 232 for (i = prev_debx % TCP_NDEBUG; i < TCP_NDEBUG; i++) { 233 td = &tcp_debug[i]; 234 if (tcpcb && td->td_tcb != tcpcb) 235 continue; 236 ntime = ntohl(td->td_time); 237#ifdef INET6 238 family = td->td_family; 239#else 240 family = AF_INET; 241#endif 242 switch(family) { 243 case AF_INET: 244 tcp_trace(td->td_act, td->td_ostate, 245 &td->td_cb, td->td_family, &td->td_ti.ti_i, 246 &td->td_ti.ti_t, td->td_req); 247 break; 248#ifdef INET6 249 case AF_INET6: 250 tcp_trace(td->td_act, td->td_ostate, 251 &td->td_cb, td->td_family, &td->td_ti6.ip6, 252 &td->td_ti6.th, td->td_req); 253 break; 254#endif 255 } 256 if (i == tcp_debx) 257 goto done; 258 } 259 for (i = 0; i <= tcp_debx % TCP_NDEBUG; i++) { 260 td = &tcp_debug[i]; 261 if (tcpcb && td->td_tcb != tcpcb) 262 continue; 263 ntime = ntohl(td->td_time); 264#ifdef INET6 265 family = td->td_family; 266#else 267 family = AF_INET; 268#endif 269 switch(family) { 270 case AF_INET: 271 tcp_trace(td->td_act, td->td_ostate, 272 &td->td_cb, td->td_family, &td->td_ti.ti_i, 273 &td->td_ti.ti_t, td->td_req); 274 break; 275#ifdef INET6 276 case AF_INET6: 277 tcp_trace(td->td_act, td->td_ostate, 278 &td->td_cb, td->td_family, &td->td_ti6.ip6, 279 &td->td_ti6.th, td->td_req); 280 break; 281#endif 282 } 283 } 284done: if (follow) { 285 prev_debx = tcp_debx + 1; 286 if (prev_debx >= TCP_NDEBUG) 287 prev_debx = 0; 288 do { 289 sleep(1); 290 (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET); 291 if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) != 292 sizeof(tcp_debx)) 293 err(3, "tcp_debx"); 294 } while (tcp_debx == prev_debx); 295 (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET); 296 if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) != 297 sizeof(tcp_debug)) 298 err(3, "tcp_debug"); 299 goto again; 300 } 301} 302 303/* 304 * Tcp debug routines 305 */ 306/*ARGSUSED*/ 307void 308tcp_trace(short act, short ostate, struct tcpcb *tp, int family __unused, 309 void *ip, struct tcphdr *th, int req) 310{ 311 tcp_seq seq, ack; 312 int flags, len, win, timer; 313 struct ip *ip4; 314#ifdef INET6 315 int isipv6, nopkt = 1; 316 struct ip6_hdr *ip6; 317 char ntop_buf[INET6_ADDRSTRLEN]; 318#endif 319 320#ifdef INET6 321 switch (family) { 322 case AF_INET: 323 nopkt = 0; 324 isipv6 = 0; 325 ip4 = (struct ip *)ip; 326 break; 327 case AF_INET6: 328 nopkt = 0; 329 isipv6 = 1; 330 ip6 = (struct ip6_hdr *)ip; 331 case 0: 332 default: 333 break; 334 } 335#else 336 ip4 = (struct ip *)ip; 337#endif 338 printf("%03ld %s:%s ", (long)((ntime/10) % 1000), tcpstates[ostate], 339 tanames[act]); 340 switch (act) { 341 case TA_INPUT: 342 case TA_OUTPUT: 343 case TA_DROP: 344#ifdef INET6 345 if (nopkt != 0) 346 break; 347#endif 348 if (aflag) { 349 printf("(src=%s,%u, ", 350 351#ifdef INET6 352 isipv6 353 ? inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf, 354 sizeof(ntop_buf)) : 355#endif 356 inet_ntoa(ip4->ip_src), 357 ntohs(th->th_sport)); 358 printf("dst=%s,%u)", 359#ifdef INET6 360 isipv6 361 ? inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf, 362 sizeof(ntop_buf)) : 363#endif 364 inet_ntoa(ip4->ip_dst), 365 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, 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, 427 (u_long)tp->snd_wl2, tp->snd_wnd); 428 } 429 /* print out timers? */ 430#if 0 431 /* 432 * XXX 433 * kernel now uses callouts, not integer time values. 434 */ 435 if (tflag) { 436 register char *cp = "\t"; 437 register int i; 438 439 for (i = 0; i < TCPT_NTIMERS; i++) { 440 if (tp->t_timer[i] == 0) 441 continue; 442 printf("%s%s=%d", cp, tcptimers[i], tp->t_timer[i]); 443 if (i == TCPT_REXMT) 444 printf(" (t_rxtshft=%d)", tp->t_rxtshift); 445 cp = ", "; 446 } 447 if (*cp != '\t') 448 putchar('\n'); 449 } 450#endif 451} 452 453int 454numeric(v1, v2) 455 const void *v1, *v2; 456{ 457 const caddr_t *c1 = v1, *c2 = v2; 458 return(*c1 - *c2); 459} 460 461void 462klseek(fd, base, off) 463 int fd, off; 464 off_t base; 465{ 466 (void)lseek(fd, base, off); 467} 468