]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/trpt/trpt.c
This commit was generated by cvs2svn to compensate for changes in r95415,
[FreeBSD/FreeBSD.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$";
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((const void *, const void *));
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         setgid(getgid());
168         if (kflag)
169                 errx(1, "can't do core files yet");
170         (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET);
171         if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) !=
172             sizeof(tcp_debx))
173                 err(3, "tcp_debx");
174         (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
175         if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) !=
176             sizeof(tcp_debug))
177                 err(3, "tcp_debug");
178         /*
179          * If no control blocks have been specified, figure
180          * out how many distinct one we have and summarize
181          * them in tcp_pcbs for sorting the trace records
182          * below.
183          */
184         if (!npcbs) {
185                 for (i = 0; i < TCP_NDEBUG; i++) {
186                         register struct tcp_debug *td = &tcp_debug[i];
187                         register int j;
188
189                         if (td->td_tcb == 0)
190                                 continue;
191                         for (j = 0; j < npcbs; j++)
192                                 if (tcp_pcbs[j] == td->td_tcb)
193                                         break;
194                         if (j >= npcbs)
195                                 tcp_pcbs[npcbs++] = td->td_tcb;
196                 }
197                 if (!npcbs)
198                         exit(0);
199         }
200         qsort(tcp_pcbs, npcbs, sizeof(caddr_t), numeric);
201         if (jflag) {
202                 for (i = 0;;) {
203                         printf("%x", (int)tcp_pcbs[i]);
204                         if (++i == npcbs)
205                                 break;
206                         fputs(", ", stdout);
207                 }
208                 putchar('\n');
209         }
210         else for (i = 0; i < npcbs; i++) {
211                 printf("\n%x:\n", (int)tcp_pcbs[i]);
212                 dotrace(tcp_pcbs[i]);
213         }
214         exit(0);
215 }
216
217 static void
218 usage()
219 {
220         (void)fprintf(stderr,
221                 "usage: trpt [-afjst] [-p hex-address] [system [core]]\n");
222         exit(1);
223 }
224
225 void
226 dotrace(tcpcb)
227         register caddr_t tcpcb;
228 {
229         register struct tcp_debug *td;
230         register int i;
231         int prev_debx = tcp_debx, family;
232
233 again:  if (--tcp_debx < 0)
234                 tcp_debx = TCP_NDEBUG - 1;
235         for (i = prev_debx % TCP_NDEBUG; i < TCP_NDEBUG; i++) {
236                 td = &tcp_debug[i];
237                 if (tcpcb && td->td_tcb != tcpcb)
238                         continue;
239                 ntime = ntohl(td->td_time);
240 #ifdef INET6
241                 family = td->td_family;
242 #else
243                 family = AF_INET;
244 #endif
245                 switch(family) {
246                 case AF_INET:
247                         tcp_trace(td->td_act, td->td_ostate,
248                                   (struct tcpcb *)td->td_tcb,
249                                   &td->td_cb, td->td_family, &td->td_ti.ti_i,
250                                   &td->td_ti.ti_t, td->td_req);
251                         break;
252 #ifdef INET6
253                 case AF_INET6:
254                         tcp_trace(td->td_act, td->td_ostate,
255                                   (struct tcpcb *)td->td_tcb,
256                                   &td->td_cb, td->td_family, &td->td_ti6.ip6,
257                                   &td->td_ti6.th, td->td_req);
258                         break;
259 #endif
260                 }
261                 if (i == tcp_debx)
262                         goto done;
263         }
264         for (i = 0; i <= tcp_debx % TCP_NDEBUG; i++) {
265                 td = &tcp_debug[i];
266                 if (tcpcb && td->td_tcb != tcpcb)
267                         continue;
268                 ntime = ntohl(td->td_time);
269 #ifdef INET6
270                 family = td->td_family;
271 #else
272                 family = AF_INET;
273 #endif
274                 switch(family) {
275                 case AF_INET:
276                         tcp_trace(td->td_act, td->td_ostate,
277                                   (struct tcpcb *)td->td_tcb,
278                                   &td->td_cb, td->td_family, &td->td_ti.ti_i,
279                                   &td->td_ti.ti_t, td->td_req);
280                         break;
281 #ifdef INET6
282                 case AF_INET6:
283                         tcp_trace(td->td_act, td->td_ostate,
284                                   (struct tcpcb *)td->td_tcb,
285                                   &td->td_cb, td->td_family, &td->td_ti6.ip6,
286                                   &td->td_ti6.th, td->td_req);
287                         break;
288 #endif
289                 }
290         }
291 done:   if (follow) {
292                 prev_debx = tcp_debx + 1;
293                 if (prev_debx >= TCP_NDEBUG)
294                         prev_debx = 0;
295                 do {
296                         sleep(1);
297                         (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET);
298                         if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) !=
299                             sizeof(tcp_debx))
300                                 err(3, "tcp_debx");
301                 } while (tcp_debx == prev_debx);
302                 (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
303                 if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) !=
304                     sizeof(tcp_debug))
305                         err(3, "tcp_debug");
306                 goto again;
307         }
308 }
309
310 /*
311  * Tcp debug routines
312  */
313 /*ARGSUSED*/
314 void
315 tcp_trace(act, ostate, atp, tp, family, ip, th, req)
316         short act, ostate;
317         struct tcpcb *atp, *tp;
318         int family;
319         void *ip;
320         struct tcphdr *th;
321         int req;
322 {
323         tcp_seq seq, ack;
324         int flags, len, win, timer;
325         struct ip *ip4;
326 #ifdef INET6
327         int isipv6, nopkt = 1;
328         struct ip6_hdr *ip6;
329         char ntop_buf[INET6_ADDRSTRLEN];
330 #endif
331
332 #ifdef INET6
333         switch (family) {
334         case AF_INET:
335                 nopkt = 0;
336                 isipv6 = 0;
337                 ip4 = (struct ip *)ip;
338                 break;
339         case AF_INET6:
340                 nopkt = 0;
341                 isipv6 = 1;
342                 ip6 = (struct ip6_hdr *)ip;
343         case 0:
344         default:
345                 break;
346         }
347 #else
348         ip4 = (struct ip *)ip;
349 #endif
350         printf("%03ld %s:%s ",(ntime/10) % 1000, tcpstates[ostate],
351             tanames[act]);
352         switch (act) {
353         case TA_INPUT:
354         case TA_OUTPUT:
355         case TA_DROP:
356 #ifdef INET6
357                 if (nopkt != 0)
358                         break;
359 #endif
360                 if (aflag) {
361                         printf("(src=%s,%u, ",
362
363 #ifdef INET6
364                                isipv6
365                                ? inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf,
366                                            sizeof(ntop_buf)) :
367 #endif
368                                inet_ntoa(ip4->ip_src),
369                                ntohs(th->th_sport));
370                         printf("dst=%s,%u)",
371 #ifdef INET6
372                                isipv6
373                                ? inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf,
374                                            sizeof(ntop_buf)) :
375 #endif
376                                inet_ntoa(ip4->ip_dst),
377                                ntohs(th->th_dport));
378                 }
379                 seq = th->th_seq;
380                 ack = th->th_ack;
381
382                 len =
383 #ifdef INET6
384                         isipv6 ? ip6->ip6_plen :
385 #endif
386                         ip4->ip_len;
387                 win = th->th_win;
388                 if (act == TA_OUTPUT) {
389                         seq = ntohl(seq);
390                         ack = ntohl(ack);
391                         len = ntohs(len);
392                         win = ntohs(win);
393                 }
394                 if (act == TA_OUTPUT)
395                         len -= sizeof(struct tcphdr);
396                 if (len)
397                         printf("[%lx..%lx)", seq, seq + len);
398                 else
399                         printf("%lx", seq);
400                 printf("@%lx", ack);
401                 if (win)
402                         printf("(win=%x)", win);
403                 flags = th->th_flags;
404                 if (flags) {
405                         register char *cp = "<";
406 #define pf(flag, string) { \
407         if (th->th_flags&flag) { \
408                 (void)printf("%s%s", cp, string); \
409                 cp = ","; \
410         } \
411 }
412                         pf(TH_SYN, "SYN");
413                         pf(TH_ACK, "ACK");
414                         pf(TH_FIN, "FIN");
415                         pf(TH_RST, "RST");
416                         pf(TH_PUSH, "PUSH");
417                         pf(TH_URG, "URG");
418                         printf(">");
419                 }
420                 break;
421         case TA_USER:
422                 timer = req >> 8;
423                 req &= 0xff;
424                 printf("%s", prurequests[req]);
425                 if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO)
426                         printf("<%s>", tcptimers[timer]);
427                 break;
428         }
429         printf(" -> %s", tcpstates[tp->t_state]);
430         /* print out internal state of tp !?! */
431         printf("\n");
432         if (sflag) {
433                 printf("\trcv_nxt %lx rcv_wnd %x snd_una %lx snd_nxt %lx snd_max %lx\n",
434                     tp->rcv_nxt, tp->rcv_wnd, tp->snd_una, tp->snd_nxt,
435                     tp->snd_max);
436                 printf("\tsnd_wl1 %lx snd_wl2 %lx snd_wnd %x\n", tp->snd_wl1,
437                     tp->snd_wl2, tp->snd_wnd);
438         }
439         /* print out timers? */
440 #if 0
441         /*
442          * XXX 
443          * kernel now uses callouts, not integer time values.
444          */
445         if (tflag) {
446                 register char *cp = "\t";
447                 register int i;
448
449                 for (i = 0; i < TCPT_NTIMERS; i++) {
450                         if (tp->t_timer[i] == 0)
451                                 continue;
452                         printf("%s%s=%d", cp, tcptimers[i], tp->t_timer[i]);
453                         if (i == TCPT_REXMT)
454                                 printf(" (t_rxtshft=%d)", tp->t_rxtshift);
455                         cp = ", ";
456                 }
457                 if (*cp != '\t')
458                         putchar('\n');
459         }
460 #endif
461 }
462
463 int
464 numeric(v1, v2)
465         const void *v1, *v2;
466 {
467         const caddr_t *c1 = v1, *c2 = v2;
468         return(*c1 - *c2);
469 }
470
471 void
472 klseek(fd, base, off)
473         int fd, off;
474         off_t base;
475 {
476         (void)lseek(fd, base, off);
477 }