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