Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.sbin / trpt / trpt.c
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
35 static 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
42 static char sccsid[] = "@(#)trpt.c      8.1 (Berkeley) 6/6/93";
43 #endif
44 static const char rcsid[] =
45   "$FreeBSD: src/usr.sbin/trpt/trpt.c,v 1.12 2000/01/29 11:49:07 shin Exp $";
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 #ifdef INET6
64 #include <netinet/ip6.h>
65 #endif
66 #include <netinet/ip_var.h>
67 #include <netinet/tcp.h>
68 #define TCPSTATES
69 #include <netinet/tcp_fsm.h>
70 #include <netinet/tcp_seq.h>
71 #define TCPTIMERS
72 #include <netinet/tcp_timer.h>
73 #include <netinet/tcp_var.h>
74 #include <netinet/tcpip.h>
75 #define TANAMES
76 #include <netinet/tcp_debug.h>
77
78 #include <arpa/inet.h>
79
80 #include <err.h>
81 #include <nlist.h>
82 #include <paths.h>
83 #include <stdio.h>
84 #include <stdlib.h>
85 #include <unistd.h>
86
87 struct nlist nl[] = {
88 #define N_TCP_DEBUG     0
89         { "_tcp_debug" },
90 #define N_TCP_DEBX      1
91         { "_tcp_debx" },
92         { "" },
93 };
94
95 static caddr_t tcp_pcbs[TCP_NDEBUG];
96 static n_time ntime;
97 static int aflag, kflag, memf, follow, sflag, tflag;
98
99 void dotrace __P((caddr_t));
100 void klseek __P((int, off_t, int));
101 int numeric __P((caddr_t *, caddr_t *));
102 void tcp_trace __P((short, short, struct tcpcb *, struct tcpcb *,
103                         int, void *, struct tcphdr *, int));
104 static void usage __P((void));
105
106 int
107 main(argc, argv)
108         int argc;
109         char **argv;
110 {
111         int ch, i, jflag, npcbs;
112         char *system, *core;
113
114         jflag = npcbs = 0;
115         while ((ch = getopt(argc, argv, "afjp:st")) != -1)
116                 switch (ch) {
117                 case 'a':
118                         ++aflag;
119                         break;
120                 case 'f':
121                         ++follow;
122                         setlinebuf(stdout);
123                         break;
124                 case 'j':
125                         ++jflag;
126                         break;
127                 case 'p':
128                         if (npcbs >= TCP_NDEBUG)
129                                 errx(1, "too many pcb's specified");
130                         (void)sscanf(optarg, "%x", (int *)&tcp_pcbs[npcbs++]);
131                         break;
132                 case 's':
133                         ++sflag;
134                         break;
135                 case 't':
136                         ++tflag;
137                         break;
138                 case '?':
139                 default:
140                         usage();
141                 }
142         argc -= optind;
143         argv += optind;
144
145         core = _PATH_KMEM;
146         if (argc > 0) {
147                 system = *argv;
148                 argc--, argv++;
149                 if (argc > 0) {
150                         core = *argv;
151                         argc--, argv++;
152                         ++kflag;
153                 }
154                 /*
155                  * Discard setgid privileges if not the running kernel so that
156                  * bad guys can't print interesting stuff from kernel memory.
157                  */
158                 setgid(getgid());
159         }
160         else
161                 system = (char *)getbootfile();
162
163         if (nlist(system, nl) < 0 || !nl[0].n_value)
164                 errx(1, "%s: no namelist", system);
165         if ((memf = open(core, O_RDONLY)) < 0)
166                 err(2, "%s", core);
167         if (kflag)
168                 errx(1, "can't do core files yet");
169         (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET);
170         if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) !=
171             sizeof(tcp_debx))
172                 err(3, "tcp_debx");
173         (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
174         if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) !=
175             sizeof(tcp_debug))
176                 err(3, "tcp_debug");
177         /*
178          * If no control blocks have been specified, figure
179          * out how many distinct one we have and summarize
180          * them in tcp_pcbs for sorting the trace records
181          * below.
182          */
183         if (!npcbs) {
184                 for (i = 0; i < TCP_NDEBUG; i++) {
185                         register struct tcp_debug *td = &tcp_debug[i];
186                         register int j;
187
188                         if (td->td_tcb == 0)
189                                 continue;
190                         for (j = 0; j < npcbs; j++)
191                                 if (tcp_pcbs[j] == td->td_tcb)
192                                         break;
193                         if (j >= npcbs)
194                                 tcp_pcbs[npcbs++] = td->td_tcb;
195                 }
196                 if (!npcbs)
197                         exit(0);
198         }
199         qsort(tcp_pcbs, npcbs, sizeof(caddr_t), numeric);
200         if (jflag) {
201                 for (i = 0;;) {
202                         printf("%x", (int)tcp_pcbs[i]);
203                         if (++i == npcbs)
204                                 break;
205                         fputs(", ", stdout);
206                 }
207                 putchar('\n');
208         }
209         else for (i = 0; i < npcbs; i++) {
210                 printf("\n%x:\n", (int)tcp_pcbs[i]);
211                 dotrace(tcp_pcbs[i]);
212         }
213         exit(0);
214 }
215
216 static void
217 usage()
218 {
219         (void)fprintf(stderr,
220                 "usage: trpt [-afjst] [-p hex-address] [system [core]]\n");
221         exit(1);
222 }
223
224 void
225 dotrace(tcpcb)
226         register caddr_t tcpcb;
227 {
228         register struct tcp_debug *td;
229         register int i;
230         int prev_debx = tcp_debx, family;
231
232 again:  if (--tcp_debx < 0)
233                 tcp_debx = TCP_NDEBUG - 1;
234         for (i = prev_debx % TCP_NDEBUG; i < TCP_NDEBUG; i++) {
235                 td = &tcp_debug[i];
236                 if (tcpcb && td->td_tcb != tcpcb)
237                         continue;
238                 ntime = ntohl(td->td_time);
239 #ifdef INET6
240                 family = td->td_family;
241 #else
242                 family = AF_INET;
243 #endif
244                 switch(family) {
245                 case AF_INET:
246                         tcp_trace(td->td_act, td->td_ostate,
247                                   (struct tcpcb *)td->td_tcb,
248                                   &td->td_cb, td->td_family, &td->td_ti.ti_i,
249                                   &td->td_ti.ti_t, td->td_req);
250                         break;
251 #ifdef INET6
252                 case AF_INET6:
253                         tcp_trace(td->td_act, td->td_ostate,
254                                   (struct tcpcb *)td->td_tcb,
255                                   &td->td_cb, td->td_family, &td->td_ti6.ip6,
256                                   &td->td_ti6.th, td->td_req);
257                         break;
258 #endif
259                 }
260                 if (i == tcp_debx)
261                         goto done;
262         }
263         for (i = 0; i <= tcp_debx % TCP_NDEBUG; i++) {
264                 td = &tcp_debug[i];
265                 if (tcpcb && td->td_tcb != tcpcb)
266                         continue;
267                 ntime = ntohl(td->td_time);
268 #ifdef INET6
269                 family = td->td_family;
270 #else
271                 family = AF_INET;
272 #endif
273                 switch(family) {
274                 case AF_INET:
275                         tcp_trace(td->td_act, td->td_ostate,
276                                   (struct tcpcb *)td->td_tcb,
277                                   &td->td_cb, td->td_family, &td->td_ti.ti_i,
278                                   &td->td_ti.ti_t, td->td_req);
279                         break;
280 #ifdef INET6
281                 case AF_INET6:
282                         tcp_trace(td->td_act, td->td_ostate,
283                                   (struct tcpcb *)td->td_tcb,
284                                   &td->td_cb, td->td_family, &td->td_ti6.ip6,
285                                   &td->td_ti6.th, td->td_req);
286                         break;
287 #endif
288                 }
289         }
290 done:   if (follow) {
291                 prev_debx = tcp_debx + 1;
292                 if (prev_debx >= TCP_NDEBUG)
293                         prev_debx = 0;
294                 do {
295                         sleep(1);
296                         (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET);
297                         if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) !=
298                             sizeof(tcp_debx))
299                                 err(3, "tcp_debx");
300                 } while (tcp_debx == prev_debx);
301                 (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
302                 if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) !=
303                     sizeof(tcp_debug))
304                         err(3, "tcp_debug");
305                 goto again;
306         }
307 }
308
309 /*
310  * Tcp debug routines
311  */
312 /*ARGSUSED*/
313 void
314 tcp_trace(act, ostate, atp, tp, family, ip, th, req)
315         short act, ostate;
316         struct tcpcb *atp, *tp;
317         int family;
318         void *ip;
319         struct tcphdr *th;
320         int req;
321 {
322         tcp_seq seq, ack;
323         int flags, len, win, timer;
324         struct ip *ip4;
325 #ifdef INET6
326         int isipv6, nopkt = 1;
327         struct ip6_hdr *ip6;
328         char ntop_buf[INET6_ADDRSTRLEN];
329 #endif
330
331 #ifdef INET6
332         switch (family) {
333         case AF_INET:
334                 nopkt = 0;
335                 isipv6 = 0;
336                 ip4 = (struct ip *)ip;
337                 break;
338         case AF_INET6:
339                 nopkt = 0;
340                 isipv6 = 1;
341                 ip6 = (struct ip6_hdr *)ip;
342         case 0:
343         default:
344                 break;
345         }
346 #else
347         ip4 = (struct ip *)ip;
348 #endif
349         printf("%03ld %s:%s ",(ntime/10) % 1000, tcpstates[ostate],
350             tanames[act]);
351         switch (act) {
352         case TA_INPUT:
353         case TA_OUTPUT:
354         case TA_DROP:
355 #ifdef INET6
356                 if (nopkt != 0)
357                         break;
358 #endif
359                 if (aflag) {
360                         printf("(src=%s,%u, ",
361
362 #ifdef INET6
363                                isipv6
364                                ? inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf,
365                                            sizeof(ntop_buf)) :
366 #endif
367                                inet_ntoa(ip4->ip_src),
368                                ntohs(th->th_sport));
369                         printf("dst=%s,%u)",
370 #ifdef INET6
371                                isipv6
372                                ? inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf,
373                                            sizeof(ntop_buf)) :
374 #endif
375                                inet_ntoa(ip4->ip_dst),
376                                ntohs(th->th_dport));
377                 }
378                 seq = th->th_seq;
379                 ack = th->th_ack;
380
381                 len =
382 #ifdef INET6
383                         isipv6 ? ip6->ip6_plen :
384 #endif
385                         ip4->ip_len;
386                 win = th->th_win;
387                 if (act == TA_OUTPUT) {
388                         seq = ntohl(seq);
389                         ack = ntohl(ack);
390                         len = ntohs(len);
391                         win = ntohs(win);
392                 }
393                 if (act == TA_OUTPUT)
394                         len -= sizeof(struct tcphdr);
395                 if (len)
396                         printf("[%lx..%lx)", seq, seq + len);
397                 else
398                         printf("%lx", seq);
399                 printf("@%lx", ack);
400                 if (win)
401                         printf("(win=%x)", win);
402                 flags = th->th_flags;
403                 if (flags) {
404                         register char *cp = "<";
405 #define pf(flag, string) { \
406         if (th->th_flags&flag) { \
407                 (void)printf("%s%s", cp, string); \
408                 cp = ","; \
409         } \
410 }
411                         pf(TH_SYN, "SYN");
412                         pf(TH_ACK, "ACK");
413                         pf(TH_FIN, "FIN");
414                         pf(TH_RST, "RST");
415                         pf(TH_PUSH, "PUSH");
416                         pf(TH_URG, "URG");
417                         printf(">");
418                 }
419                 break;
420         case TA_USER:
421                 timer = req >> 8;
422                 req &= 0xff;
423                 printf("%s", prurequests[req]);
424                 if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO)
425                         printf("<%s>", tcptimers[timer]);
426                 break;
427         }
428         printf(" -> %s", tcpstates[tp->t_state]);
429         /* print out internal state of tp !?! */
430         printf("\n");
431         if (sflag) {
432                 printf("\trcv_nxt %lx rcv_wnd %x snd_una %lx snd_nxt %lx snd_max %lx\n",
433                     tp->rcv_nxt, tp->rcv_wnd, tp->snd_una, tp->snd_nxt,
434                     tp->snd_max);
435                 printf("\tsnd_wl1 %lx snd_wl2 %lx snd_wnd %x\n", tp->snd_wl1,
436                     tp->snd_wl2, tp->snd_wnd);
437         }
438         /* print out timers? */
439 #if 0
440         /*
441          * XXX 
442          * kernel now uses callouts, not integer time values.
443          */
444         if (tflag) {
445                 register char *cp = "\t";
446                 register int i;
447
448                 for (i = 0; i < TCPT_NTIMERS; i++) {
449                         if (tp->t_timer[i] == 0)
450                                 continue;
451                         printf("%s%s=%d", cp, tcptimers[i], tp->t_timer[i]);
452                         if (i == TCPT_REXMT)
453                                 printf(" (t_rxtshft=%d)", tp->t_rxtshift);
454                         cp = ", ";
455                 }
456                 if (*cp != '\t')
457                         putchar('\n');
458         }
459 #endif
460 }
461
462 int
463 numeric(c1, c2)
464         caddr_t *c1, *c2;
465 {
466         return(*c1 - *c2);
467 }
468
469 void
470 klseek(fd, base, off)
471         int fd, off;
472         off_t base;
473 {
474         (void)lseek(fd, base, off);
475 }