trpt.c revision 73732
1204076Spjd/*
2204076Spjd * Copyright (c) 1983, 1988, 1993
3219351Spjd *	The Regents of the University of California.  All rights reserved.
4204076Spjd *
5204076Spjd * Redistribution and use in source and binary forms, with or without
6204076Spjd * modification, are permitted provided that the following conditions
7204076Spjd * are met:
8204076Spjd * 1. Redistributions of source code must retain the above copyright
9204076Spjd *    notice, this list of conditions and the following disclaimer.
10204076Spjd * 2. Redistributions in binary form must reproduce the above copyright
11204076Spjd *    notice, this list of conditions and the following disclaimer in the
12204076Spjd *    documentation and/or other materials provided with the distribution.
13204076Spjd * 3. All advertising materials mentioning features or use of this software
14204076Spjd *    must display the following acknowledgement:
15204076Spjd *	This product includes software developed by the University of
16204076Spjd *	California, Berkeley and its contributors.
17204076Spjd * 4. Neither the name of the University nor the names of its contributors
18204076Spjd *    may be used to endorse or promote products derived from this software
19204076Spjd *    without specific prior written permission.
20204076Spjd *
21204076Spjd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24204076Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31204076Spjd * SUCH DAMAGE.
32204076Spjd */
33204076Spjd
34204076Spjd#ifndef lint
35204076Spjdstatic const char copyright[] =
36204076Spjd"@(#) Copyright (c) 1983, 1988, 1993\n\
37204076Spjd	The Regents of the University of California.  All rights reserved.\n";
38204076Spjd#endif /* not lint */
39204076Spjd
40204076Spjd#ifndef lint
41204076Spjd#if 0
42204076Spjdstatic char sccsid[] = "@(#)trpt.c	8.1 (Berkeley) 6/6/93";
43204076Spjd#endif
44204076Spjdstatic const char rcsid[] =
45204076Spjd  "$FreeBSD: head/usr.sbin/trpt/trpt.c 73732 2001-03-05 12:13:12Z dwmalone $";
46204076Spjd#endif /* not lint */
47211982Spjd
48204076Spjd#include <sys/param.h>
49204076Spjd#include <sys/queue.h>
50204076Spjd#include <sys/socket.h>
51204076Spjd#include <sys/socketvar.h>
52204076Spjd#define PRUREQUESTS
53204076Spjd#include <sys/protosw.h>
54204076Spjd#include <sys/file.h>
55204076Spjd#include <sys/time.h>
56204076Spjd
57204076Spjd#include <net/route.h>
58204076Spjd#include <net/if.h>
59212038Spjd
60204076Spjd#include <netinet/in.h>
61204076Spjd#include <netinet/in_systm.h>
62204076Spjd#include <netinet/ip.h>
63211886Spjd#ifdef INET6
64204076Spjd#include <netinet/ip6.h>
65204076Spjd#endif
66204076Spjd#include <netinet/ip_var.h>
67246922Spjd#include <netinet/tcp.h>
68204076Spjd#define TCPSTATES
69204076Spjd#include <netinet/tcp_fsm.h>
70204076Spjd#include <netinet/tcp_seq.h>
71210886Spjd#define	TCPTIMERS
72210886Spjd#include <netinet/tcp_timer.h>
73210886Spjd#include <netinet/tcp_var.h>
74204076Spjd#include <netinet/tcpip.h>
75204076Spjd#define	TANAMES
76204076Spjd#include <netinet/tcp_debug.h>
77204076Spjd
78204076Spjd#include <arpa/inet.h>
79204076Spjd
80204076Spjd#include <err.h>
81249969Sed#include <nlist.h>
82204076Spjd#include <paths.h>
83204076Spjd#include <stdio.h>
84204076Spjd#include <stdlib.h>
85204076Spjd#include <unistd.h>
86204076Spjd
87204076Spjdstruct nlist nl[] = {
88204076Spjd#define	N_TCP_DEBUG	0
89219818Spjd	{ "_tcp_debug" },
90204076Spjd#define	N_TCP_DEBX	1
91204076Spjd	{ "_tcp_debx" },
92226859Spjd	{ "" },
93226859Spjd};
94226859Spjd
95226859Spjdstatic caddr_t tcp_pcbs[TCP_NDEBUG];
96226859Spjdstatic n_time ntime;
97226859Spjdstatic int aflag, kflag, memf, follow, sflag, tflag;
98226859Spjd
99226859Spjdvoid dotrace __P((caddr_t));
100226859Spjdvoid klseek __P((int, off_t, int));
101204076Spjdint numeric __P((const void *, const void *));
102204076Spjdvoid tcp_trace __P((short, short, struct tcpcb *, struct tcpcb *,
103204076Spjd			int, void *, struct tcphdr *, int));
104204076Spjdstatic void usage __P((void));
105204076Spjd
106204076Spjdint
107204076Spjdmain(argc, argv)
108204076Spjd	int argc;
109204076Spjd	char **argv;
110204076Spjd{
111204076Spjd	int ch, i, jflag, npcbs;
112204076Spjd	char *system, *core;
113204076Spjd
114204076Spjd	jflag = npcbs = 0;
115204076Spjd	while ((ch = getopt(argc, argv, "afjp:st")) != -1)
116204076Spjd		switch (ch) {
117204076Spjd		case 'a':
118204076Spjd			++aflag;
119204076Spjd			break;
120204076Spjd		case 'f':
121204076Spjd			++follow;
122204076Spjd			setlinebuf(stdout);
123204076Spjd			break;
124204076Spjd		case 'j':
125204076Spjd			++jflag;
126204076Spjd			break;
127204076Spjd		case 'p':
128204076Spjd			if (npcbs >= TCP_NDEBUG)
129204076Spjd				errx(1, "too many pcb's specified");
130204076Spjd			(void)sscanf(optarg, "%x", (int *)&tcp_pcbs[npcbs++]);
131204076Spjd			break;
132204076Spjd		case 's':
133204076Spjd			++sflag;
134204076Spjd			break;
135204076Spjd		case 't':
136204076Spjd			++tflag;
137204076Spjd			break;
138204076Spjd		case '?':
139204076Spjd		default:
140204076Spjd			usage();
141204076Spjd		}
142204076Spjd	argc -= optind;
143204076Spjd	argv += optind;
144204076Spjd
145204076Spjd	core = _PATH_KMEM;
146204076Spjd	if (argc > 0) {
147204076Spjd		system = *argv;
148204076Spjd		argc--, argv++;
149204076Spjd		if (argc > 0) {
150204076Spjd			core = *argv;
151204076Spjd			argc--, argv++;
152204076Spjd			++kflag;
153204076Spjd		}
154204076Spjd		/*
155204076Spjd		 * Discard setgid privileges if not the running kernel so that
156204076Spjd		 * bad guys can't print interesting stuff from kernel memory.
157204076Spjd		 */
158204076Spjd		setgid(getgid());
159204076Spjd	}
160204076Spjd	else
161204076Spjd		system = (char *)getbootfile();
162204076Spjd
163204076Spjd	if (nlist(system, nl) < 0 || !nl[0].n_value)
164204076Spjd		errx(1, "%s: no namelist", system);
165204076Spjd	if ((memf = open(core, O_RDONLY)) < 0)
166204076Spjd		err(2, "%s", core);
167204076Spjd	if (kflag)
168204076Spjd		errx(1, "can't do core files yet");
169204076Spjd	(void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET);
170204076Spjd	if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) !=
171204076Spjd	    sizeof(tcp_debx))
172204076Spjd		err(3, "tcp_debx");
173204076Spjd	(void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
174204076Spjd	if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) !=
175204076Spjd	    sizeof(tcp_debug))
176204076Spjd		err(3, "tcp_debug");
177204076Spjd	/*
178204076Spjd	 * If no control blocks have been specified, figure
179204076Spjd	 * out how many distinct one we have and summarize
180204076Spjd	 * them in tcp_pcbs for sorting the trace records
181204076Spjd	 * below.
182204076Spjd	 */
183204076Spjd	if (!npcbs) {
184204076Spjd		for (i = 0; i < TCP_NDEBUG; i++) {
185204076Spjd			register struct tcp_debug *td = &tcp_debug[i];
186204076Spjd			register int j;
187214692Spjd
188214692Spjd			if (td->td_tcb == 0)
189214692Spjd				continue;
190204076Spjd			for (j = 0; j < npcbs; j++)
191214692Spjd				if (tcp_pcbs[j] == td->td_tcb)
192214692Spjd					break;
193214692Spjd			if (j >= npcbs)
194214692Spjd				tcp_pcbs[npcbs++] = td->td_tcb;
195219864Spjd		}
196214692Spjd		if (!npcbs)
197204076Spjd			exit(0);
198214692Spjd	}
199214692Spjd	qsort(tcp_pcbs, npcbs, sizeof(caddr_t), numeric);
200214692Spjd	if (jflag) {
201214692Spjd		for (i = 0;;) {
202204076Spjd			printf("%x", (int)tcp_pcbs[i]);
203204076Spjd			if (++i == npcbs)
204204076Spjd				break;
205204076Spjd			fputs(", ", stdout);
206204076Spjd		}
207204076Spjd		putchar('\n');
208204076Spjd	}
209204076Spjd	else for (i = 0; i < npcbs; i++) {
210204076Spjd		printf("\n%x:\n", (int)tcp_pcbs[i]);
211204076Spjd		dotrace(tcp_pcbs[i]);
212204076Spjd	}
213204076Spjd	exit(0);
214209183Spjd}
215209183Spjd
216209183Spjdstatic void
217209183Spjdusage()
218204076Spjd{
219204076Spjd	(void)fprintf(stderr,
220204076Spjd		"usage: trpt [-afjst] [-p hex-address] [system [core]]\n");
221204076Spjd	exit(1);
222204076Spjd}
223204076Spjd
224204076Spjdvoid
225204076Spjddotrace(tcpcb)
226204076Spjd	register caddr_t tcpcb;
227204076Spjd{
228204076Spjd	register struct tcp_debug *td;
229204076Spjd	register int i;
230204076Spjd	int prev_debx = tcp_debx, family;
231220898Spjd
232204076Spjdagain:	if (--tcp_debx < 0)
233204076Spjd		tcp_debx = TCP_NDEBUG - 1;
234204076Spjd	for (i = prev_debx % TCP_NDEBUG; i < TCP_NDEBUG; i++) {
235204076Spjd		td = &tcp_debug[i];
236204076Spjd		if (tcpcb && td->td_tcb != tcpcb)
237204076Spjd			continue;
238204076Spjd		ntime = ntohl(td->td_time);
239204076Spjd#ifdef INET6
240204076Spjd		family = td->td_family;
241211982Spjd#else
242204076Spjd		family = AF_INET;
243204076Spjd#endif
244204076Spjd		switch(family) {
245204076Spjd		case AF_INET:
246204076Spjd			tcp_trace(td->td_act, td->td_ostate,
247204076Spjd				  (struct tcpcb *)td->td_tcb,
248204076Spjd				  &td->td_cb, td->td_family, &td->td_ti.ti_i,
249204076Spjd				  &td->td_ti.ti_t, td->td_req);
250204076Spjd			break;
251204076Spjd#ifdef INET6
252204076Spjd		case AF_INET6:
253213533Spjd			tcp_trace(td->td_act, td->td_ostate,
254204076Spjd				  (struct tcpcb *)td->td_tcb,
255204076Spjd				  &td->td_cb, td->td_family, &td->td_ti6.ip6,
256204076Spjd				  &td->td_ti6.th, td->td_req);
257229945Spjd			break;
258213531Spjd#endif
259213531Spjd		}
260204076Spjd		if (i == tcp_debx)
261204076Spjd			goto done;
262204076Spjd	}
263204076Spjd	for (i = 0; i <= tcp_debx % TCP_NDEBUG; i++) {
264204076Spjd		td = &tcp_debug[i];
265204076Spjd		if (tcpcb && td->td_tcb != tcpcb)
266204076Spjd			continue;
267204076Spjd		ntime = ntohl(td->td_time);
268204076Spjd#ifdef INET6
269212899Spjd		family = td->td_family;
270204076Spjd#else
271204076Spjd		family = AF_INET;
272204076Spjd#endif
273204076Spjd		switch(family) {
274218138Spjd		case AF_INET:
275204076Spjd			tcp_trace(td->td_act, td->td_ostate,
276204076Spjd				  (struct tcpcb *)td->td_tcb,
277204076Spjd				  &td->td_cb, td->td_family, &td->td_ti.ti_i,
278204076Spjd				  &td->td_ti.ti_t, td->td_req);
279204076Spjd			break;
280204076Spjd#ifdef INET6
281204076Spjd		case AF_INET6:
282212899Spjd			tcp_trace(td->td_act, td->td_ostate,
283204076Spjd				  (struct tcpcb *)td->td_tcb,
284204076Spjd				  &td->td_cb, td->td_family, &td->td_ti6.ip6,
285204076Spjd				  &td->td_ti6.th, td->td_req);
286204076Spjd			break;
287204076Spjd#endif
288204076Spjd		}
289204076Spjd	}
290204076Spjddone:	if (follow) {
291204076Spjd		prev_debx = tcp_debx + 1;
292204076Spjd		if (prev_debx >= TCP_NDEBUG)
293204076Spjd			prev_debx = 0;
294204076Spjd		do {
295204076Spjd			sleep(1);
296204076Spjd			(void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET);
297204076Spjd			if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) !=
298204076Spjd			    sizeof(tcp_debx))
299204076Spjd				err(3, "tcp_debx");
300204076Spjd		} while (tcp_debx == prev_debx);
301218138Spjd		(void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
302218138Spjd		if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) !=
303204076Spjd		    sizeof(tcp_debug))
304204076Spjd			err(3, "tcp_debug");
305225786Spjd		goto again;
306247281Strociny	}
307204076Spjd}
308204076Spjd
309225830Spjd/*
310225830Spjd * Tcp debug routines
311225830Spjd */
312225830Spjd/*ARGSUSED*/
313225830Spjdvoid
314225830Spjdtcp_trace(act, ostate, atp, tp, family, ip, th, req)
315225830Spjd	short act, ostate;
316225830Spjd	struct tcpcb *atp, *tp;
317247281Strociny	int family;
318225830Spjd	void *ip;
319225830Spjd	struct tcphdr *th;
320225830Spjd	int req;
321204076Spjd{
322204076Spjd	tcp_seq seq, ack;
323204076Spjd	int flags, len, win, timer;
324210881Spjd	struct ip *ip4;
325210881Spjd#ifdef INET6
326210881Spjd	int isipv6, nopkt = 1;
327210881Spjd	struct ip6_hdr *ip6;
328210881Spjd	char ntop_buf[INET6_ADDRSTRLEN];
329210881Spjd#endif
330210881Spjd
331204076Spjd#ifdef INET6
332204076Spjd	switch (family) {
333204076Spjd	case AF_INET:
334204076Spjd		nopkt = 0;
335204076Spjd		isipv6 = 0;
336204076Spjd		ip4 = (struct ip *)ip;
337204076Spjd		break;
338204076Spjd	case AF_INET6:
339204076Spjd		nopkt = 0;
340204076Spjd		isipv6 = 1;
341204076Spjd		ip6 = (struct ip6_hdr *)ip;
342204076Spjd	case 0:
343204076Spjd	default:
344204076Spjd		break;
345204076Spjd	}
346204076Spjd#else
347204076Spjd	ip4 = (struct ip *)ip;
348204076Spjd#endif
349204076Spjd	printf("%03ld %s:%s ",(ntime/10) % 1000, tcpstates[ostate],
350204076Spjd	    tanames[act]);
351204076Spjd	switch (act) {
352204076Spjd	case TA_INPUT:
353204076Spjd	case TA_OUTPUT:
354204076Spjd	case TA_DROP:
355204076Spjd#ifdef INET6
356204076Spjd		if (nopkt != 0)
357204076Spjd			break;
358204076Spjd#endif
359204076Spjd		if (aflag) {
360204076Spjd			printf("(src=%s,%u, ",
361204076Spjd
362204076Spjd#ifdef INET6
363204076Spjd			       isipv6
364204076Spjd			       ? inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf,
365204076Spjd					   sizeof(ntop_buf)) :
366204076Spjd#endif
367204076Spjd			       inet_ntoa(ip4->ip_src),
368204076Spjd			       ntohs(th->th_sport));
369204076Spjd			printf("dst=%s,%u)",
370204076Spjd#ifdef INET6
371204076Spjd			       isipv6
372204076Spjd			       ? inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf,
373204076Spjd					   sizeof(ntop_buf)) :
374204076Spjd#endif
375204076Spjd			       inet_ntoa(ip4->ip_dst),
376204076Spjd			       ntohs(th->th_dport));
377204076Spjd		}
378204076Spjd		seq = th->th_seq;
379204076Spjd		ack = th->th_ack;
380204076Spjd
381204076Spjd		len =
382204076Spjd#ifdef INET6
383204076Spjd			isipv6 ? ip6->ip6_plen :
384204076Spjd#endif
385204076Spjd			ip4->ip_len;
386204076Spjd		win = th->th_win;
387204076Spjd		if (act == TA_OUTPUT) {
388204076Spjd			seq = ntohl(seq);
389204076Spjd			ack = ntohl(ack);
390204076Spjd			len = ntohs(len);
391204076Spjd			win = ntohs(win);
392204076Spjd		}
393204076Spjd		if (act == TA_OUTPUT)
394204076Spjd			len -= sizeof(struct tcphdr);
395204076Spjd		if (len)
396204076Spjd			printf("[%lx..%lx)", seq, seq + len);
397204076Spjd		else
398204076Spjd			printf("%lx", seq);
399204076Spjd		printf("@%lx", ack);
400204076Spjd		if (win)
401204076Spjd			printf("(win=%x)", win);
402204076Spjd		flags = th->th_flags;
403204076Spjd		if (flags) {
404204076Spjd			register char *cp = "<";
405204076Spjd#define	pf(flag, string) { \
406204076Spjd	if (th->th_flags&flag) { \
407204076Spjd		(void)printf("%s%s", cp, string); \
408204076Spjd		cp = ","; \
409204076Spjd	} \
410204076Spjd}
411204076Spjd			pf(TH_SYN, "SYN");
412204076Spjd			pf(TH_ACK, "ACK");
413204076Spjd			pf(TH_FIN, "FIN");
414204076Spjd			pf(TH_RST, "RST");
415204076Spjd			pf(TH_PUSH, "PUSH");
416204076Spjd			pf(TH_URG, "URG");
417204076Spjd			printf(">");
418249969Sed		}
419204076Spjd		break;
420204076Spjd	case TA_USER:
421204076Spjd		timer = req >> 8;
422204076Spjd		req &= 0xff;
423204076Spjd		printf("%s", prurequests[req]);
424204076Spjd		if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO)
425204076Spjd			printf("<%s>", tcptimers[timer]);
426204076Spjd		break;
427204076Spjd	}
428204076Spjd	printf(" -> %s", tcpstates[tp->t_state]);
429204076Spjd	/* print out internal state of tp !?! */
430204076Spjd	printf("\n");
431204076Spjd	if (sflag) {
432204076Spjd		printf("\trcv_nxt %lx rcv_wnd %x snd_una %lx snd_nxt %lx snd_max %lx\n",
433204076Spjd		    tp->rcv_nxt, tp->rcv_wnd, tp->snd_una, tp->snd_nxt,
434204076Spjd		    tp->snd_max);
435204076Spjd		printf("\tsnd_wl1 %lx snd_wl2 %lx snd_wnd %x\n", tp->snd_wl1,
436204076Spjd		    tp->snd_wl2, tp->snd_wnd);
437204076Spjd	}
438204076Spjd	/* print out timers? */
439204076Spjd#if 0
440204076Spjd	/*
441204076Spjd	 * XXX
442204076Spjd	 * kernel now uses callouts, not integer time values.
443204076Spjd	 */
444214284Spjd	if (tflag) {
445214284Spjd		register char *cp = "\t";
446214284Spjd		register int i;
447214284Spjd
448214284Spjd		for (i = 0; i < TCPT_NTIMERS; i++) {
449214284Spjd			if (tp->t_timer[i] == 0)
450214284Spjd				continue;
451214284Spjd			printf("%s%s=%d", cp, tcptimers[i], tp->t_timer[i]);
452214284Spjd			if (i == TCPT_REXMT)
453214284Spjd				printf(" (t_rxtshft=%d)", tp->t_rxtshift);
454214284Spjd			cp = ", ";
455214284Spjd		}
456229945Spjd		if (*cp != '\t')
457214284Spjd			putchar('\n');
458214284Spjd	}
459214284Spjd#endif
460214284Spjd}
461214284Spjd
462204076Spjdint
463204076Spjdnumeric(v1, v2)
464204076Spjd	const void *v1, *v2;
465204076Spjd{
466204076Spjd	const caddr_t *c1 = v1, *c2 = v2;
467204076Spjd	return(*c1 - *c2);
468229945Spjd}
469204076Spjd
470204076Spjdvoid
471204076Spjdklseek(fd, base, off)
472229945Spjd	int fd, off;
473204076Spjd	off_t base;
474204076Spjd{
475204076Spjd	(void)lseek(fd, base, off);
476204076Spjd}
477229945Spjd