1 /* $NetBSD: trpt.c,v 1.14 2002/11/16 04:23:28 itojun Exp $ */ 2 3 /*- 4 * Copyright (c) 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * Copyright (c) 1983, 1988, 1993 42 * The Regents of the University of California. All rights reserved. 43 * 44 * Redistribution and use in source and binary forms, with or without 45 * modification, are permitted provided that the following conditions 46 * are met: 47 * 1. Redistributions of source code must retain the above copyright 48 * notice, this list of conditions and the following disclaimer. 49 * 2. Redistributions in binary form must reproduce the above copyright 50 * notice, this list of conditions and the following disclaimer in the 51 * documentation and/or other materials provided with the distribution. 52 * 3. All advertising materials mentioning features or use of this software 53 * must display the following acknowledgement: 54 * This product includes software developed by the University of 55 * California, Berkeley and its contributors. 56 * 4. Neither the name of the University nor the names of its contributors 57 * may be used to endorse or promote products derived from this software 58 * without specific prior written permission. 59 * 60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 70 * SUCH DAMAGE. 71 */ 72 73 #include <sys/cdefs.h> 74 #ifndef lint 75 __COPYRIGHT( 76 "@(#) Copyright (c) 1983, 1988, 1993\n\ 77 The Regents of the University of California. All rights reserved.\n"); 78 #endif /* not lint */ 79 80 #ifndef lint 81 #if 0 82 static char sccsid[] = "@(#)trpt.c 8.1 (Berkeley) 6/6/93"; 83 #else 84 __RCSID("$NetBSD: trpt.c,v 1.14 2002/11/16 04:23:28 itojun Exp $"); 85 #endif 86 #endif /* not lint */ 87 88 #include <sys/param.h> 89 #include <sys/queue.h> 90 #include <sys/socket.h> 91 #include <sys/socketvar.h> 92 #define PRUREQUESTS 93 #include <sys/protosw.h> 94 #include <sys/file.h> 95 96 #include <net/route.h> 97 #include <net/if.h> 98 99 #include <netinet/in.h> 100 #include <netinet/in_systm.h> 101 #include <netinet/ip.h> 102 #include <netinet/in_pcb.h> 103 #include <netinet/ip_var.h> 104 105 #ifdef INET6 106 #ifndef INET 107 #include <netinet/in.h> 108 #endif 109 #include <netinet/ip6.h> 110 #endif 111 112 #include <netinet/tcp.h> 113 #define TCPSTATES 114 #include <netinet/tcp_fsm.h> 115 #include <netinet/tcp_seq.h> 116 #define TCPTIMERS 117 #include <netinet/tcp_timer.h> 118 #include <netinet/tcp_var.h> 119 #include <netinet/tcpip.h> 120 #define TANAMES 121 #include <netinet/tcp_debug.h> 122 123 #include <arpa/inet.h> 124 125 #include <err.h> 126 #include <stdio.h> 127 #include <errno.h> 128 #include <kvm.h> 129 #include <nlist.h> 130 #include <paths.h> 131 #include <limits.h> 132 #include <stdlib.h> 133 #include <unistd.h> 134 135 struct nlist nl[] = { 136 #define N_TCP_DEBUG 0 137 { "_tcp_debug" }, 138 #define N_TCP_DEBX 1 139 { "_tcp_debx" }, 140 { NULL }, 141 }; 142 143 static caddr_t tcp_pcbs[TCP_NDEBUG]; 144 static n_time ntime; 145 static int aflag, follow, sflag, tflag; 146 147 /* see sys/netinet/tcp_debug.c */ 148 struct tcp_debug tcp_debug[TCP_NDEBUG]; 149 int tcp_debx; 150 151 int main __P((int, char *[])); 152 void dotrace __P((caddr_t)); 153 void tcp_trace __P((short, short, struct tcpcb *, struct tcpcb *, 154 int, void *, int)); 155 int numeric __P((const void *, const void *)); 156 void usage __P((void)); 157 158 kvm_t *kd; 159 160 int 161 main(argc, argv) 162 int argc; 163 char *argv[]; 164 { 165 int ch, i, jflag, npcbs; 166 char *system, *core, *cp, errbuf[_POSIX2_LINE_MAX]; 167 gid_t egid = getegid(); 168 unsigned long l; 169 170 (void)setegid(getgid()); 171 system = core = NULL; 172 173 jflag = npcbs = 0; 174 while ((ch = getopt(argc, argv, "afjp:stN:M:")) != -1) { 175 switch (ch) { 176 case 'a': 177 ++aflag; 178 break; 179 case 'f': 180 ++follow; 181 setlinebuf(stdout); 182 break; 183 case 'j': 184 ++jflag; 185 break; 186 case 'p': 187 if (npcbs >= TCP_NDEBUG) 188 errx(1, "too many pcbs specified"); 189 errno = 0; 190 cp = NULL; 191 l = strtoul(optarg, &cp, 16); 192 tcp_pcbs[npcbs] = (caddr_t)l; 193 if (*optarg == '\0' || *cp != '\0' || errno || 194 (unsigned long)tcp_pcbs[npcbs] != l) 195 errx(1, "invalid address: %s", optarg); 196 npcbs++; 197 break; 198 case 's': 199 ++sflag; 200 break; 201 case 't': 202 ++tflag; 203 break; 204 case 'N': 205 system = optarg; 206 break; 207 case 'M': 208 core = optarg; 209 break; 210 case '?': 211 default: 212 usage(); 213 /* NOTREACHED */ 214 } 215 } 216 argc -= optind; 217 argv += optind; 218 219 if (argc) 220 usage(); 221 222 /* 223 * Discard setgid privileges. If not the running kernel, we toss 224 * them away totally so that bad guys can't print interesting stuff 225 * from kernel memory, otherwise switch back to kmem for the 226 * duration of the kvm_openfiles() call. 227 */ 228 if (core != NULL || system != NULL) 229 setgid(getgid()); 230 else 231 setegid(egid); 232 233 kd = kvm_openfiles(system, core, NULL, O_RDONLY, errbuf); 234 if (kd == NULL) 235 errx(1, "can't open kmem: %s", errbuf); 236 237 /* get rid of it now anyway */ 238 if (core == NULL && system == NULL) 239 setgid(getgid()); 240 241 if (kvm_nlist(kd, nl)) 242 errx(2, "%s: no namelist", system ? system : _PATH_UNIX); 243 244 if (kvm_read(kd, nl[N_TCP_DEBX].n_value, (char *)&tcp_debx, 245 sizeof(tcp_debx)) != sizeof(tcp_debx)) 246 errx(3, "tcp_debx: %s", kvm_geterr(kd)); 247 248 if (kvm_read(kd, nl[N_TCP_DEBUG].n_value, (char *)tcp_debug, 249 sizeof(tcp_debug)) != sizeof(tcp_debug)) 250 errx(3, "tcp_debug: %s", kvm_geterr(kd)); 251 252 /* 253 * If no control blocks have been specified, figure 254 * out how many distinct one we have and summarize 255 * them in tcp_pcbs for sorting the trace records 256 * below. 257 */ 258 if (npcbs == 0) { 259 for (i = 0; i < TCP_NDEBUG; i++) { 260 struct tcp_debug *td = &tcp_debug[i]; 261 int j; 262 263 if (td->td_tcb == 0) 264 continue; 265 for (j = 0; j < npcbs; j++) 266 if (tcp_pcbs[j] == td->td_tcb) 267 break; 268 if (j >= npcbs) 269 tcp_pcbs[npcbs++] = td->td_tcb; 270 } 271 if (npcbs == 0) 272 exit(0); 273 } 274 qsort(tcp_pcbs, npcbs, sizeof(caddr_t), numeric); 275 if (jflag) { 276 for (i = 0;;) { 277 printf("%lx", (long)tcp_pcbs[i]); 278 if (++i == npcbs) 279 break; 280 fputs(", ", stdout); 281 } 282 putchar('\n'); 283 } else { 284 for (i = 0; i < npcbs; i++) { 285 printf("\n%lx:\n", (long)tcp_pcbs[i]); 286 dotrace(tcp_pcbs[i]); 287 } 288 } 289 exit(0); 290 } 291 292 void 293 dotrace(tcpcb) 294 caddr_t tcpcb; 295 { 296 struct tcp_debug *td; 297 int prev_debx = tcp_debx; 298 int i; 299 300 again: 301 if (--tcp_debx < 0) 302 tcp_debx = TCP_NDEBUG - 1; 303 for (i = prev_debx % TCP_NDEBUG; i < TCP_NDEBUG; i++) { 304 td = &tcp_debug[i]; 305 if (tcpcb && td->td_tcb != tcpcb) 306 continue; 307 ntime = ntohl(td->td_time); 308 switch (td->td_family) { 309 case AF_INET: 310 tcp_trace(td->td_act, td->td_ostate, 311 (struct tcpcb *)td->td_tcb, &td->td_cb, 312 td->td_family, &td->td_ti, td->td_req); 313 break; 314 #ifdef INET6 315 case AF_INET6: 316 tcp_trace(td->td_act, td->td_ostate, 317 (struct tcpcb *)td->td_tcb, &td->td_cb, 318 td->td_family, &td->td_ti6, td->td_req); 319 break; 320 #endif 321 default: 322 tcp_trace(td->td_act, td->td_ostate, 323 (struct tcpcb *)td->td_tcb, &td->td_cb, 324 td->td_family, NULL, td->td_req); 325 break; 326 } 327 if (i == tcp_debx) 328 goto done; 329 } 330 for (i = 0; i <= tcp_debx % TCP_NDEBUG; i++) { 331 td = &tcp_debug[i]; 332 if (tcpcb && td->td_tcb != tcpcb) 333 continue; 334 ntime = ntohl(td->td_time); 335 switch (td->td_family) { 336 case AF_INET: 337 tcp_trace(td->td_act, td->td_ostate, 338 (struct tcpcb *)td->td_tcb, &td->td_cb, 339 td->td_family, &td->td_ti, td->td_req); 340 break; 341 #ifdef INET6 342 case AF_INET6: 343 tcp_trace(td->td_act, td->td_ostate, 344 (struct tcpcb *)td->td_tcb, &td->td_cb, 345 td->td_family, &td->td_ti6, td->td_req); 346 break; 347 #endif 348 default: 349 tcp_trace(td->td_act, td->td_ostate, 350 (struct tcpcb *)td->td_tcb, &td->td_cb, 351 td->td_family, NULL, td->td_req); 352 break; 353 } 354 } 355 done: 356 if (follow) { 357 prev_debx = tcp_debx + 1; 358 if (prev_debx >= TCP_NDEBUG) 359 prev_debx = 0; 360 do { 361 sleep(1); 362 if (kvm_read(kd, nl[N_TCP_DEBX].n_value, 363 (char *)&tcp_debx, sizeof(tcp_debx)) != 364 sizeof(tcp_debx)) 365 errx(3, "tcp_debx: %s", kvm_geterr(kd)); 366 } while (tcp_debx == prev_debx); 367 368 if (kvm_read(kd, nl[N_TCP_DEBUG].n_value, (char *)tcp_debug, 369 sizeof(tcp_debug)) != sizeof(tcp_debug)) 370 errx(3, "tcp_debug: %s", kvm_geterr(kd)); 371 372 goto again; 373 } 374 } 375 376 /* 377 * Tcp debug routines 378 */ 379 /*ARGSUSED*/ 380 void 381 tcp_trace(act, ostate, atp, tp, family, packet, req) 382 short act, ostate; 383 struct tcpcb *atp, *tp; 384 int family; 385 void *packet; 386 int req; 387 { 388 tcp_seq seq, ack; 389 int flags, len, win, timer; 390 struct tcphdr *th = NULL; 391 struct ip *ip = NULL; 392 #ifdef INET6 393 struct ip6_hdr *ip6 = NULL; 394 #endif 395 char hbuf[MAXHOSTNAMELEN]; 396 397 switch (family) { 398 case AF_INET: 399 if (packet) { 400 ip = (struct ip *)packet; 401 th = (struct tcphdr *)(ip + 1); 402 } 403 break; 404 #ifdef INET6 405 case AF_INET6: 406 if (packet) { 407 ip6 = (struct ip6_hdr *)packet; 408 th = (struct tcphdr *)(ip6 + 1); 409 } 410 break; 411 #endif 412 default: 413 return; 414 } 415 416 printf("%03d %s:%s ", (ntime/10) % 1000, tcpstates[ostate], 417 tanames[act]); 418 419 #ifndef INET6 420 if (!ip) 421 #else 422 if (!(ip || ip6)) 423 #endif 424 goto skipact; 425 426 switch (act) { 427 case TA_INPUT: 428 case TA_OUTPUT: 429 case TA_DROP: 430 if (aflag) { 431 inet_ntop(family, 432 #ifndef INET6 433 (void *)&ip->ip_src, 434 #else 435 family == AF_INET ? (void *)&ip->ip_src 436 : (void *)&ip6->ip6_src, 437 #endif 438 hbuf, sizeof(hbuf)); 439 printf("(src=%s,%u, ", 440 hbuf, ntohs(th->th_sport)); 441 inet_ntop(family, 442 #ifndef INET6 443 (void *)&ip->ip_dst, 444 #else 445 family == AF_INET ? (void *)&ip->ip_dst 446 : (void *)&ip6->ip6_dst, 447 #endif 448 hbuf, sizeof(hbuf)); 449 printf("dst=%s,%u)", 450 hbuf, ntohs(th->th_dport)); 451 } 452 seq = th->th_seq; 453 ack = th->th_ack; 454 if (ip) 455 len = ip->ip_len; 456 #ifdef INET6 457 else if (ip6) 458 len = ip6->ip6_plen; 459 #endif 460 win = th->th_win; 461 if (act == TA_OUTPUT) { 462 NTOHL(seq); 463 NTOHL(ack); 464 NTOHS(len); 465 NTOHS(win); 466 } 467 if (act == TA_OUTPUT) 468 len -= sizeof(struct tcphdr); 469 if (len) 470 printf("[%x..%x)", seq, seq + len); 471 else 472 printf("%x", seq); 473 printf("@%x", ack); 474 if (win) 475 printf("(win=%x)", win); 476 flags = th->th_flags; 477 if (flags) { 478 register char *cp = "<"; 479 #define pf(flag, string) { \ 480 if (th->th_flags&flag) { \ 481 (void)printf("%s%s", cp, string); \ 482 cp = ","; \ 483 } \ 484 } 485 pf(TH_SYN, "SYN"); 486 pf(TH_ACK, "ACK"); 487 pf(TH_FIN, "FIN"); 488 pf(TH_RST, "RST"); 489 pf(TH_PUSH, "PUSH"); 490 pf(TH_URG, "URG"); 491 printf(">"); 492 } 493 break; 494 case TA_USER: 495 timer = req >> 8; 496 req &= 0xff; 497 printf("%s", prurequests[req]); 498 if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO) 499 printf("<%s>", tcptimers[timer]); 500 break; 501 } 502 503 skipact: 504 printf(" -> %s", tcpstates[tp->t_state]); 505 /* print out internal state of tp !?! */ 506 printf("\n"); 507 if (sflag) { 508 printf("\trcv_nxt %x rcv_wnd %lx snd_una %x snd_nxt %x snd_max %x\n", 509 tp->rcv_nxt, tp->rcv_wnd, tp->snd_una, tp->snd_nxt, 510 tp->snd_max); 511 printf("\tsnd_wl1 %x snd_wl2 %x snd_wnd %lx\n", tp->snd_wl1, 512 tp->snd_wl2, tp->snd_wnd); 513 } 514 /* print out timers? */ 515 if (tflag) { 516 register char *cp = "\t"; 517 register int i; 518 519 for (i = 0; i < TCPT_NTIMERS; i++) { 520 if ((tp->t_timer[i].c_flags & CALLOUT_ACTIVE) == 0) 521 continue; 522 printf("%s%s=%llu", cp, tcptimers[i], 523 (unsigned long long) tp->t_timer[i].c_time); 524 if (i == TCPT_REXMT) 525 printf(" (t_rxtshft=%d)", tp->t_rxtshift); 526 cp = ", "; 527 } 528 if (*cp != '\t') 529 putchar('\n'); 530 } 531 } 532 533 int 534 numeric(v1, v2) 535 const void *v1, *v2; 536 { 537 const caddr_t *c1 = v1; 538 const caddr_t *c2 = v2; 539 int rv; 540 541 if (*c1 < *c2) 542 rv = -1; 543 else if (*c1 > *c2) 544 rv = 1; 545 else 546 rv = 0; 547 548 return (rv); 549 } 550 551 void 552 usage() 553 { 554 555 (void) fprintf(stderr, "usage: %s [-afjst] [-p hex-address]" 556 " [-N system] [-M core]\n", getprogname()); 557 exit(1); 558 } 559