trpt.c revision 1.16 1 /* $NetBSD: trpt.c,v 1.16 2003/02/04 01:22:10 thorpej 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.16 2003/02/04 01:22:10 thorpej 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_HARDCLOCK_TICKS 0
137 { "_hardclock_ticks" },
138 #define N_TCP_DEBUG 1
139 { "_tcp_debug" },
140 #define N_TCP_DEBX 2
141 { "_tcp_debx" },
142 { NULL },
143 };
144
145 static caddr_t tcp_pcbs[TCP_NDEBUG];
146 static n_time ntime;
147 static int aflag, follow, sflag, tflag;
148
149 /* see sys/netinet/tcp_debug.c */
150 struct tcp_debug tcp_debug[TCP_NDEBUG];
151 int tcp_debx;
152
153 int main __P((int, char *[]));
154 void dotrace __P((caddr_t));
155 void tcp_trace __P((short, short, struct tcpcb *, struct tcpcb *,
156 int, void *, int));
157 int numeric __P((const void *, const void *));
158 void usage __P((void));
159
160 kvm_t *kd;
161
162 int
163 main(argc, argv)
164 int argc;
165 char *argv[];
166 {
167 int ch, i, jflag, npcbs;
168 char *system, *core, *cp, errbuf[_POSIX2_LINE_MAX];
169 gid_t egid = getegid();
170 unsigned long l;
171
172 (void)setegid(getgid());
173 system = core = NULL;
174
175 jflag = npcbs = 0;
176 while ((ch = getopt(argc, argv, "afjp:stN:M:")) != -1) {
177 switch (ch) {
178 case 'a':
179 ++aflag;
180 break;
181 case 'f':
182 ++follow;
183 setlinebuf(stdout);
184 break;
185 case 'j':
186 ++jflag;
187 break;
188 case 'p':
189 if (npcbs >= TCP_NDEBUG)
190 errx(1, "too many pcbs specified");
191 errno = 0;
192 cp = NULL;
193 l = strtoul(optarg, &cp, 16);
194 tcp_pcbs[npcbs] = (caddr_t)l;
195 if (*optarg == '\0' || *cp != '\0' || errno ||
196 (unsigned long)tcp_pcbs[npcbs] != l)
197 errx(1, "invalid address: %s", optarg);
198 npcbs++;
199 break;
200 case 's':
201 ++sflag;
202 break;
203 case 't':
204 ++tflag;
205 break;
206 case 'N':
207 system = optarg;
208 break;
209 case 'M':
210 core = optarg;
211 break;
212 case '?':
213 default:
214 usage();
215 /* NOTREACHED */
216 }
217 }
218 argc -= optind;
219 argv += optind;
220
221 if (argc)
222 usage();
223
224 /*
225 * Discard setgid privileges. If not the running kernel, we toss
226 * them away totally so that bad guys can't print interesting stuff
227 * from kernel memory, otherwise switch back to kmem for the
228 * duration of the kvm_openfiles() call.
229 */
230 if (core != NULL || system != NULL)
231 setgid(getgid());
232 else
233 setegid(egid);
234
235 kd = kvm_openfiles(system, core, NULL, O_RDONLY, errbuf);
236 if (kd == NULL)
237 errx(1, "can't open kmem: %s", errbuf);
238
239 /* get rid of it now anyway */
240 if (core == NULL && system == NULL)
241 setgid(getgid());
242
243 if (kvm_nlist(kd, nl))
244 errx(2, "%s: no namelist", system ? system : _PATH_UNIX);
245
246 if (kvm_read(kd, nl[N_TCP_DEBX].n_value, (char *)&tcp_debx,
247 sizeof(tcp_debx)) != sizeof(tcp_debx))
248 errx(3, "tcp_debx: %s", kvm_geterr(kd));
249
250 if (kvm_read(kd, nl[N_TCP_DEBUG].n_value, (char *)tcp_debug,
251 sizeof(tcp_debug)) != sizeof(tcp_debug))
252 errx(3, "tcp_debug: %s", kvm_geterr(kd));
253
254 /*
255 * If no control blocks have been specified, figure
256 * out how many distinct one we have and summarize
257 * them in tcp_pcbs for sorting the trace records
258 * below.
259 */
260 if (npcbs == 0) {
261 for (i = 0; i < TCP_NDEBUG; i++) {
262 struct tcp_debug *td = &tcp_debug[i];
263 int j;
264
265 if (td->td_tcb == 0)
266 continue;
267 for (j = 0; j < npcbs; j++)
268 if (tcp_pcbs[j] == td->td_tcb)
269 break;
270 if (j >= npcbs)
271 tcp_pcbs[npcbs++] = td->td_tcb;
272 }
273 if (npcbs == 0)
274 exit(0);
275 }
276 qsort(tcp_pcbs, npcbs, sizeof(caddr_t), numeric);
277 if (jflag) {
278 for (i = 0;;) {
279 printf("%lx", (long)tcp_pcbs[i]);
280 if (++i == npcbs)
281 break;
282 fputs(", ", stdout);
283 }
284 putchar('\n');
285 } else {
286 for (i = 0; i < npcbs; i++) {
287 printf("\n%lx:\n", (long)tcp_pcbs[i]);
288 dotrace(tcp_pcbs[i]);
289 }
290 }
291 exit(0);
292 }
293
294 void
295 dotrace(tcpcb)
296 caddr_t tcpcb;
297 {
298 struct tcp_debug *td;
299 int prev_debx = tcp_debx;
300 int i;
301
302 again:
303 if (--tcp_debx < 0)
304 tcp_debx = TCP_NDEBUG - 1;
305 for (i = prev_debx % TCP_NDEBUG; i < TCP_NDEBUG; i++) {
306 td = &tcp_debug[i];
307 if (tcpcb && td->td_tcb != tcpcb)
308 continue;
309 ntime = ntohl(td->td_time);
310 switch (td->td_family) {
311 case AF_INET:
312 tcp_trace(td->td_act, td->td_ostate,
313 (struct tcpcb *)td->td_tcb, &td->td_cb,
314 td->td_family, &td->td_ti, td->td_req);
315 break;
316 #ifdef INET6
317 case AF_INET6:
318 tcp_trace(td->td_act, td->td_ostate,
319 (struct tcpcb *)td->td_tcb, &td->td_cb,
320 td->td_family, &td->td_ti6, td->td_req);
321 break;
322 #endif
323 default:
324 tcp_trace(td->td_act, td->td_ostate,
325 (struct tcpcb *)td->td_tcb, &td->td_cb,
326 td->td_family, NULL, td->td_req);
327 break;
328 }
329 if (i == tcp_debx)
330 goto done;
331 }
332 for (i = 0; i <= tcp_debx % TCP_NDEBUG; i++) {
333 td = &tcp_debug[i];
334 if (tcpcb && td->td_tcb != tcpcb)
335 continue;
336 ntime = ntohl(td->td_time);
337 switch (td->td_family) {
338 case AF_INET:
339 tcp_trace(td->td_act, td->td_ostate,
340 (struct tcpcb *)td->td_tcb, &td->td_cb,
341 td->td_family, &td->td_ti, td->td_req);
342 break;
343 #ifdef INET6
344 case AF_INET6:
345 tcp_trace(td->td_act, td->td_ostate,
346 (struct tcpcb *)td->td_tcb, &td->td_cb,
347 td->td_family, &td->td_ti6, td->td_req);
348 break;
349 #endif
350 default:
351 tcp_trace(td->td_act, td->td_ostate,
352 (struct tcpcb *)td->td_tcb, &td->td_cb,
353 td->td_family, NULL, td->td_req);
354 break;
355 }
356 }
357 done:
358 if (follow) {
359 prev_debx = tcp_debx + 1;
360 if (prev_debx >= TCP_NDEBUG)
361 prev_debx = 0;
362 do {
363 sleep(1);
364 if (kvm_read(kd, nl[N_TCP_DEBX].n_value,
365 (char *)&tcp_debx, sizeof(tcp_debx)) !=
366 sizeof(tcp_debx))
367 errx(3, "tcp_debx: %s", kvm_geterr(kd));
368 } while (tcp_debx == prev_debx);
369
370 if (kvm_read(kd, nl[N_TCP_DEBUG].n_value, (char *)tcp_debug,
371 sizeof(tcp_debug)) != sizeof(tcp_debug))
372 errx(3, "tcp_debug: %s", kvm_geterr(kd));
373
374 goto again;
375 }
376 }
377
378 /*
379 * Tcp debug routines
380 */
381 /*ARGSUSED*/
382 void
383 tcp_trace(act, ostate, atp, tp, family, packet, req)
384 short act, ostate;
385 struct tcpcb *atp, *tp;
386 int family;
387 void *packet;
388 int req;
389 {
390 tcp_seq seq, ack;
391 int flags, len, win, timer;
392 struct tcphdr *th = NULL;
393 struct ip *ip = NULL;
394 #ifdef INET6
395 struct ip6_hdr *ip6 = NULL;
396 #endif
397 char hbuf[MAXHOSTNAMELEN];
398
399 switch (family) {
400 case AF_INET:
401 if (packet) {
402 ip = (struct ip *)packet;
403 th = (struct tcphdr *)(ip + 1);
404 }
405 break;
406 #ifdef INET6
407 case AF_INET6:
408 if (packet) {
409 ip6 = (struct ip6_hdr *)packet;
410 th = (struct tcphdr *)(ip6 + 1);
411 }
412 break;
413 #endif
414 default:
415 return;
416 }
417
418 printf("%03d %s:%s ", (ntime/10) % 1000, tcpstates[ostate],
419 tanames[act]);
420
421 #ifndef INET6
422 if (!ip)
423 #else
424 if (!(ip || ip6))
425 #endif
426 goto skipact;
427
428 switch (act) {
429 case TA_INPUT:
430 case TA_OUTPUT:
431 case TA_DROP:
432 if (aflag) {
433 inet_ntop(family,
434 #ifndef INET6
435 (void *)&ip->ip_src,
436 #else
437 family == AF_INET ? (void *)&ip->ip_src
438 : (void *)&ip6->ip6_src,
439 #endif
440 hbuf, sizeof(hbuf));
441 printf("(src=%s,%u, ",
442 hbuf, ntohs(th->th_sport));
443 inet_ntop(family,
444 #ifndef INET6
445 (void *)&ip->ip_dst,
446 #else
447 family == AF_INET ? (void *)&ip->ip_dst
448 : (void *)&ip6->ip6_dst,
449 #endif
450 hbuf, sizeof(hbuf));
451 printf("dst=%s,%u)",
452 hbuf, ntohs(th->th_dport));
453 }
454 seq = th->th_seq;
455 ack = th->th_ack;
456 if (ip)
457 len = ip->ip_len;
458 #ifdef INET6
459 else if (ip6)
460 len = ip6->ip6_plen;
461 #endif
462 win = th->th_win;
463 if (act == TA_OUTPUT) {
464 NTOHL(seq);
465 NTOHL(ack);
466 NTOHS(len);
467 NTOHS(win);
468 }
469 if (act == TA_OUTPUT)
470 len -= sizeof(struct tcphdr);
471 if (len)
472 printf("[%x..%x)", seq, seq + len);
473 else
474 printf("%x", seq);
475 printf("@%x", ack);
476 if (win)
477 printf("(win=%x)", win);
478 flags = th->th_flags;
479 if (flags) {
480 register char *cp = "<";
481 #define pf(flag, string) { \
482 if (th->th_flags&flag) { \
483 (void)printf("%s%s", cp, string); \
484 cp = ","; \
485 } \
486 }
487 pf(TH_SYN, "SYN");
488 pf(TH_ACK, "ACK");
489 pf(TH_FIN, "FIN");
490 pf(TH_RST, "RST");
491 pf(TH_PUSH, "PUSH");
492 pf(TH_URG, "URG");
493 printf(">");
494 }
495 break;
496 case TA_USER:
497 timer = req >> 8;
498 req &= 0xff;
499 printf("%s", prurequests[req]);
500 if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO)
501 printf("<%s>", tcptimers[timer]);
502 break;
503 }
504
505 skipact:
506 printf(" -> %s", tcpstates[tp->t_state]);
507 /* print out internal state of tp !?! */
508 printf("\n");
509 if (sflag) {
510 printf("\trcv_nxt %x rcv_wnd %lx snd_una %x snd_nxt %x snd_max %x\n",
511 tp->rcv_nxt, tp->rcv_wnd, tp->snd_una, tp->snd_nxt,
512 tp->snd_max);
513 printf("\tsnd_wl1 %x snd_wl2 %x snd_wnd %lx\n", tp->snd_wl1,
514 tp->snd_wl2, tp->snd_wnd);
515 }
516 /* print out timers? */
517 if (tflag) {
518 register char *cp = "\t";
519 register int i;
520 int hardticks;
521
522 if (kvm_read(kd, nl[N_HARDCLOCK_TICKS].n_value,
523 (char *)&hardticks, sizeof(hardticks)) != sizeof(hardticks))
524 errx(3, "hardclock_ticks: %s", kvm_geterr(kd));
525
526 for (i = 0; i < TCPT_NTIMERS; i++) {
527 if ((tp->t_timer[i].c_flags & CALLOUT_PENDING) == 0)
528 continue;
529 printf("%s%s=%d", cp, tcptimers[i],
530 tp->t_timer[i].c_time - hardticks);
531 if (i == TCPT_REXMT)
532 printf(" (t_rxtshft=%d)", tp->t_rxtshift);
533 cp = ", ";
534 }
535 if (*cp != '\t')
536 putchar('\n');
537 }
538 }
539
540 int
541 numeric(v1, v2)
542 const void *v1, *v2;
543 {
544 const caddr_t *c1 = v1;
545 const caddr_t *c2 = v2;
546 int rv;
547
548 if (*c1 < *c2)
549 rv = -1;
550 else if (*c1 > *c2)
551 rv = 1;
552 else
553 rv = 0;
554
555 return (rv);
556 }
557
558 void
559 usage()
560 {
561
562 (void) fprintf(stderr, "usage: %s [-afjst] [-p hex-address]"
563 " [-N system] [-M core]\n", getprogname());
564 exit(1);
565 }
566