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