trpt.c revision 50479
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 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static const char copyright[] = 36"@(#) Copyright (c) 1983, 1988, 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41#if 0 42static char sccsid[] = "@(#)trpt.c 8.1 (Berkeley) 6/6/93"; 43#endif 44static const char rcsid[] = 45 "$FreeBSD: head/usr.sbin/trpt/trpt.c 50479 1999-08-28 01:35:59Z peter $"; 46#endif /* not lint */ 47 48#include <sys/param.h> 49#include <sys/queue.h> 50#include <sys/socket.h> 51#include <sys/socketvar.h> 52#define PRUREQUESTS 53#include <sys/protosw.h> 54#include <sys/file.h> 55#include <sys/time.h> 56 57#include <net/route.h> 58#include <net/if.h> 59 60#include <netinet/in.h> 61#include <netinet/in_systm.h> 62#include <netinet/ip.h> 63#include <netinet/ip_var.h> 64#include <netinet/tcp.h> 65#define TCPSTATES 66#include <netinet/tcp_fsm.h> 67#include <netinet/tcp_seq.h> 68#define TCPTIMERS 69#include <netinet/tcp_timer.h> 70#include <netinet/tcp_var.h> 71#include <netinet/tcpip.h> 72#define TANAMES 73#include <netinet/tcp_debug.h> 74 75#include <arpa/inet.h> 76 77#include <err.h> 78#include <nlist.h> 79#include <paths.h> 80#include <stdio.h> 81#include <stdlib.h> 82#include <unistd.h> 83 84struct nlist nl[] = { 85#define N_TCP_DEBUG 0 86 { "_tcp_debug" }, 87#define N_TCP_DEBX 1 88 { "_tcp_debx" }, 89 { "" }, 90}; 91 92static caddr_t tcp_pcbs[TCP_NDEBUG]; 93static n_time ntime; 94static int aflag, kflag, memf, follow, sflag, tflag; 95 96void dotrace __P((caddr_t)); 97void klseek __P((int, off_t, int)); 98int numeric __P((caddr_t *, caddr_t *)); 99void tcp_trace __P((short, short, struct tcpcb *, struct tcpcb *, 100 struct tcpiphdr *, int)); 101static void usage __P((void)); 102 103int 104main(argc, argv) 105 int argc; 106 char **argv; 107{ 108 int ch, i, jflag, npcbs; 109 char *system, *core; 110 111 jflag = npcbs = 0; 112 while ((ch = getopt(argc, argv, "afjp:st")) != -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 't': 133 ++tflag; 134 break; 135 case '?': 136 default: 137 usage(); 138 } 139 argc -= optind; 140 argv += optind; 141 142 core = _PATH_KMEM; 143 if (argc > 0) { 144 system = *argv; 145 argc--, argv++; 146 if (argc > 0) { 147 core = *argv; 148 argc--, argv++; 149 ++kflag; 150 } 151 /* 152 * Discard setgid privileges if not the running kernel so that 153 * bad guys can't print interesting stuff from kernel memory. 154 */ 155 setgid(getgid()); 156 } 157 else 158 system = (char *)getbootfile(); 159 160 if (nlist(system, nl) < 0 || !nl[0].n_value) 161 errx(1, "%s: no namelist", system); 162 if ((memf = open(core, O_RDONLY)) < 0) 163 err(2, "%s", core); 164 if (kflag) 165 errx(1, "can't do core files yet"); 166 (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET); 167 if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) != 168 sizeof(tcp_debx)) 169 err(3, "tcp_debx"); 170 (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET); 171 if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) != 172 sizeof(tcp_debug)) 173 err(3, "tcp_debug"); 174 /* 175 * If no control blocks have been specified, figure 176 * out how many distinct one we have and summarize 177 * them in tcp_pcbs for sorting the trace records 178 * below. 179 */ 180 if (!npcbs) { 181 for (i = 0; i < TCP_NDEBUG; i++) { 182 register struct tcp_debug *td = &tcp_debug[i]; 183 register int j; 184 185 if (td->td_tcb == 0) 186 continue; 187 for (j = 0; j < npcbs; j++) 188 if (tcp_pcbs[j] == td->td_tcb) 189 break; 190 if (j >= npcbs) 191 tcp_pcbs[npcbs++] = td->td_tcb; 192 } 193 if (!npcbs) 194 exit(0); 195 } 196 qsort(tcp_pcbs, npcbs, sizeof(caddr_t), numeric); 197 if (jflag) { 198 for (i = 0;;) { 199 printf("%x", (int)tcp_pcbs[i]); 200 if (++i == npcbs) 201 break; 202 fputs(", ", stdout); 203 } 204 putchar('\n'); 205 } 206 else for (i = 0; i < npcbs; i++) { 207 printf("\n%x:\n", (int)tcp_pcbs[i]); 208 dotrace(tcp_pcbs[i]); 209 } 210 exit(0); 211} 212 213static void 214usage() 215{ 216 (void)fprintf(stderr, 217 "usage: trpt [-afjst] [-p hex-address] [system [core]]\n"); 218 exit(1); 219} 220 221void 222dotrace(tcpcb) 223 register caddr_t tcpcb; 224{ 225 register struct tcp_debug *td; 226 register int i; 227 int prev_debx = tcp_debx; 228 229again: if (--tcp_debx < 0) 230 tcp_debx = TCP_NDEBUG - 1; 231 for (i = prev_debx % TCP_NDEBUG; i < TCP_NDEBUG; i++) { 232 td = &tcp_debug[i]; 233 if (tcpcb && td->td_tcb != tcpcb) 234 continue; 235 ntime = ntohl(td->td_time); 236 tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb, 237 &td->td_ti, td->td_req); 238 if (i == tcp_debx) 239 goto done; 240 } 241 for (i = 0; i <= tcp_debx % TCP_NDEBUG; i++) { 242 td = &tcp_debug[i]; 243 if (tcpcb && td->td_tcb != tcpcb) 244 continue; 245 ntime = ntohl(td->td_time); 246 tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb, 247 &td->td_ti, td->td_req); 248 } 249done: if (follow) { 250 prev_debx = tcp_debx + 1; 251 if (prev_debx >= TCP_NDEBUG) 252 prev_debx = 0; 253 do { 254 sleep(1); 255 (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET); 256 if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) != 257 sizeof(tcp_debx)) 258 err(3, "tcp_debx"); 259 } while (tcp_debx == prev_debx); 260 (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET); 261 if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) != 262 sizeof(tcp_debug)) 263 err(3, "tcp_debug"); 264 goto again; 265 } 266} 267 268/* 269 * Tcp debug routines 270 */ 271/*ARGSUSED*/ 272void 273tcp_trace(act, ostate, atp, tp, ti, req) 274 short act, ostate; 275 struct tcpcb *atp, *tp; 276 struct tcpiphdr *ti; 277 int req; 278{ 279 tcp_seq seq, ack; 280 int flags, len, win, timer; 281 282 printf("%03ld %s:%s ",(ntime/10) % 1000, tcpstates[ostate], 283 tanames[act]); 284 switch (act) { 285 case TA_INPUT: 286 case TA_OUTPUT: 287 case TA_DROP: 288 if (aflag) { 289 printf("(src=%s,%u, ", 290 inet_ntoa(ti->ti_src), ntohs(ti->ti_sport)); 291 printf("dst=%s,%u)", 292 inet_ntoa(ti->ti_dst), ntohs(ti->ti_dport)); 293 } 294 seq = ti->ti_seq; 295 ack = ti->ti_ack; 296 len = ti->ti_len; 297 win = ti->ti_win; 298 if (act == TA_OUTPUT) { 299 seq = ntohl(seq); 300 ack = ntohl(ack); 301 len = ntohs(len); 302 win = ntohs(win); 303 } 304 if (act == TA_OUTPUT) 305 len -= sizeof(struct tcphdr); 306 if (len) 307 printf("[%lx..%lx)", seq, seq + len); 308 else 309 printf("%lx", seq); 310 printf("@%lx", ack); 311 if (win) 312 printf("(win=%x)", win); 313 flags = ti->ti_flags; 314 if (flags) { 315 register char *cp = "<"; 316#define pf(flag, string) { \ 317 if (ti->ti_flags&flag) { \ 318 (void)printf("%s%s", cp, string); \ 319 cp = ","; \ 320 } \ 321} 322 pf(TH_SYN, "SYN"); 323 pf(TH_ACK, "ACK"); 324 pf(TH_FIN, "FIN"); 325 pf(TH_RST, "RST"); 326 pf(TH_PUSH, "PUSH"); 327 pf(TH_URG, "URG"); 328 printf(">"); 329 } 330 break; 331 case TA_USER: 332 timer = req >> 8; 333 req &= 0xff; 334 printf("%s", prurequests[req]); 335 if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO) 336 printf("<%s>", tcptimers[timer]); 337 break; 338 } 339 printf(" -> %s", tcpstates[tp->t_state]); 340 /* print out internal state of tp !?! */ 341 printf("\n"); 342 if (sflag) { 343 printf("\trcv_nxt %lx rcv_wnd %x snd_una %lx snd_nxt %lx snd_max %lx\n", 344 tp->rcv_nxt, tp->rcv_wnd, tp->snd_una, tp->snd_nxt, 345 tp->snd_max); 346 printf("\tsnd_wl1 %lx snd_wl2 %lx snd_wnd %x\n", tp->snd_wl1, 347 tp->snd_wl2, tp->snd_wnd); 348 } 349 /* print out timers? */ 350 if (tflag) { 351 register char *cp = "\t"; 352 register int i; 353 354 for (i = 0; i < TCPT_NTIMERS; i++) { 355 if (tp->t_timer[i] == 0) 356 continue; 357 printf("%s%s=%d", cp, tcptimers[i], tp->t_timer[i]); 358 if (i == TCPT_REXMT) 359 printf(" (t_rxtshft=%d)", tp->t_rxtshift); 360 cp = ", "; 361 } 362 if (*cp != '\t') 363 putchar('\n'); 364 } 365} 366 367int 368numeric(c1, c2) 369 caddr_t *c1, *c2; 370{ 371 return(*c1 - *c2); 372} 373 374void 375klseek(fd, base, off) 376 int fd, off; 377 off_t base; 378{ 379 (void)lseek(fd, base, off); 380} 381