trpt.c revision 160752
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: head/usr.sbin/trpt/trpt.c 160752 2006-07-27 14:49:51Z yar $"); 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(act, ostate, tp, family, ip, th, req) 305 short act, ostate; 306 struct tcpcb *tp; 307#ifdef INET6 308 int family; 309#else 310 int family __unused; 311#endif 312 void *ip; 313 struct tcphdr *th; 314 int req; 315{ 316 tcp_seq seq, ack; 317 int flags, len, win, timer; 318 struct ip *ip4; 319#ifdef INET6 320 int isipv6, nopkt = 1; 321 struct ip6_hdr *ip6; 322 char ntop_buf[INET6_ADDRSTRLEN]; 323#endif 324 325#ifdef INET6 326 switch (family) { 327 case AF_INET: 328 nopkt = 0; 329 isipv6 = 0; 330 ip4 = (struct ip *)ip; 331 break; 332 case AF_INET6: 333 nopkt = 0; 334 isipv6 = 1; 335 ip6 = (struct ip6_hdr *)ip; 336 case 0: 337 default: 338 break; 339 } 340#else 341 ip4 = (struct ip *)ip; 342#endif 343 printf("%03ld %s:%s ", (long)((ntime/10) % 1000), tcpstates[ostate], 344 tanames[act]); 345 switch (act) { 346 case TA_INPUT: 347 case TA_OUTPUT: 348 case TA_DROP: 349#ifdef INET6 350 if (nopkt != 0) 351 break; 352#endif 353 if (aflag) { 354 printf("(src=%s,%u, ", 355 356#ifdef INET6 357 isipv6 358 ? inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf, 359 sizeof(ntop_buf)) : 360#endif 361 inet_ntoa(ip4->ip_src), 362 ntohs(th->th_sport)); 363 printf("dst=%s,%u)", 364#ifdef INET6 365 isipv6 366 ? inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf, 367 sizeof(ntop_buf)) : 368#endif 369 inet_ntoa(ip4->ip_dst), 370 ntohs(th->th_dport)); 371 } 372 seq = th->th_seq; 373 ack = th->th_ack; 374 375 len = 376#ifdef INET6 377 isipv6 ? ip6->ip6_plen : 378#endif 379 ip4->ip_len; 380 win = th->th_win; 381 if (act == TA_OUTPUT) { 382 seq = ntohl(seq); 383 ack = ntohl(ack); 384 len = ntohs(len); 385 win = ntohs(win); 386 } 387 if (act == TA_OUTPUT) 388 len -= sizeof(struct tcphdr); 389 if (len) 390 printf("[%lx..%lx)", (u_long)seq, (u_long)(seq + len)); 391 else 392 printf("%lx", (u_long)seq); 393 printf("@%lx", (u_long)ack); 394 if (win) 395 printf("(win=%x)", win); 396 flags = th->th_flags; 397 if (flags) { 398 const char *cp = "<"; 399#define pf(flag, string) { \ 400 if (th->th_flags&flag) { \ 401 (void)printf("%s%s", cp, string); \ 402 cp = ","; \ 403 } \ 404} 405 pf(TH_SYN, "SYN"); 406 pf(TH_ACK, "ACK"); 407 pf(TH_FIN, "FIN"); 408 pf(TH_RST, "RST"); 409 pf(TH_PUSH, "PUSH"); 410 pf(TH_URG, "URG"); 411 printf(">"); 412 } 413 break; 414 case TA_USER: 415 timer = req >> 8; 416 req &= 0xff; 417 printf("%s", prurequests[req]); 418 if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO) 419 printf("<%s>", tcptimers[timer]); 420 break; 421 } 422 printf(" -> %s", tcpstates[tp->t_state]); 423 /* print out internal state of tp !?! */ 424 printf("\n"); 425 if (sflag) { 426 printf("\trcv_nxt %lx rcv_wnd %lx snd_una %lx snd_nxt %lx snd_max %lx\n", 427 (u_long)tp->rcv_nxt, tp->rcv_wnd, 428 (u_long)tp->snd_una, (u_long)tp->snd_nxt, 429 (u_long)tp->snd_max); 430 printf("\tsnd_wl1 %lx snd_wl2 %lx snd_wnd %lx\n", 431 (u_long)tp->snd_wl1, 432 (u_long)tp->snd_wl2, tp->snd_wnd); 433 } 434 /* print out timers? */ 435#if 0 436 /* 437 * XXX 438 * kernel now uses callouts, not integer time values. 439 */ 440 if (tflag) { 441 register char *cp = "\t"; 442 register int i; 443 444 for (i = 0; i < TCPT_NTIMERS; i++) { 445 if (tp->t_timer[i] == 0) 446 continue; 447 printf("%s%s=%d", cp, tcptimers[i], tp->t_timer[i]); 448 if (i == TCPT_REXMT) 449 printf(" (t_rxtshft=%d)", tp->t_rxtshift); 450 cp = ", "; 451 } 452 if (*cp != '\t') 453 putchar('\n'); 454 } 455#endif 456} 457 458int 459numeric(v1, v2) 460 const void *v1, *v2; 461{ 462 const caddr_t *c1 = v1, *c2 = v2; 463 return(*c1 - *c2); 464} 465 466void 467klseek(fd, base, off) 468 int fd, off; 469 off_t base; 470{ 471 (void)lseek(fd, base, off); 472} 473