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