trpt.c revision 189090
1122394Sharti/*
2122394Sharti * Copyright (c) 1983, 1988, 1993
3122394Sharti *	The Regents of the University of California.  All rights reserved.
4122394Sharti *
5122394Sharti * Redistribution and use in source and binary forms, with or without
6122394Sharti * modification, are permitted provided that the following conditions
7133211Sharti * are met:
8216594Ssyrinx * 1. Redistributions of source code must retain the above copyright
9216594Ssyrinx *    notice, this list of conditions and the following disclaimer.
10216594Ssyrinx * 2. Redistributions in binary form must reproduce the above copyright
11216594Ssyrinx *    notice, this list of conditions and the following disclaimer in the
12216594Ssyrinx *    documentation and/or other materials provided with the distribution.
13216594Ssyrinx * 4. Neither the name of the University nor the names of its contributors
14133211Sharti *    may be used to endorse or promote products derived from this software
15133211Sharti *    without specific prior written permission.
16133211Sharti *
17133211Sharti * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18133211Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19122394Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20122394Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21122394Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27133211Sharti * SUCH DAMAGE.
28133211Sharti */
29133211Sharti
30133211Sharti#if 0
31133211Sharti#ifndef lint
32133211Shartistatic const char copyright[] =
33133211Sharti"@(#) Copyright (c) 1983, 1988, 1993\n\
34122394Sharti	The Regents of the University of California.  All rights reserved.\n";
35156066Sharti#endif /* not lint */
36122394Sharti
37122394Sharti#ifndef lint
38122394Shartistatic char sccsid[] = "@(#)trpt.c	8.1 (Berkeley) 6/6/93";
39216294Ssyrinx#endif /* not lint */
40216294Ssyrinx#endif
41122394Sharti#include <sys/cdefs.h>
42122394Sharti__FBSDID("$FreeBSD: head/usr.sbin/trpt/trpt.c 189090 2009-02-26 20:59:05Z ed $");
43124861Sharti
44150920Sharti#include <sys/param.h>
45122394Sharti#include <sys/queue.h>
46122394Sharti#include <sys/socket.h>
47122394Sharti#include <sys/socketvar.h>
48122394Sharti#define PRUREQUESTS
49122394Sharti#include <sys/protosw.h>
50122394Sharti#include <sys/file.h>
51122394Sharti#include <sys/time.h>
52122394Sharti
53122394Sharti#include <net/route.h>
54122394Sharti#include <net/if.h>
55122394Sharti
56122394Sharti#include <netinet/in.h>
57122394Sharti#include <netinet/in_systm.h>
58145557Sharti#include <netinet/ip.h>
59145557Sharti#ifdef INET6
60145557Sharti#include <netinet/ip6.h>
61145557Sharti#endif
62145557Sharti#include <netinet/ip_var.h>
63156066Sharti#include <netinet/tcp.h>
64122394Sharti#define TCPSTATES
65122394Sharti#include <netinet/tcp_fsm.h>
66122394Sharti#include <netinet/tcp_seq.h>
67122394Sharti#define	TCPTIMERS
68122394Sharti#include <netinet/tcp_timer.h>
69122394Sharti#include <netinet/tcp_var.h>
70122394Sharti#include <netinet/tcpip.h>
71216294Ssyrinx#define	TANAMES
72122394Sharti#include <netinet/tcp_debug.h>
73146525Sharti
74146525Sharti#include <arpa/inet.h>
75122394Sharti
76122394Sharti#include <err.h>
77122394Sharti#include <nlist.h>
78122394Sharti#include <paths.h>
79122394Sharti#include <stdio.h>
80122394Sharti#include <stdlib.h>
81122394Sharti#include <string.h>
82122394Sharti#include <unistd.h>
83122394Sharti
84122394Shartistruct nlist nl[3];
85122394Sharti#define	N_TCP_DEBUG	0
86122394Sharti#define	N_TCP_DEBX	1
87122394Sharti
88122394Shartistatic caddr_t tcp_pcbs[TCP_NDEBUG];
89122394Shartistatic n_time ntime;
90122394Shartistatic int aflag, kflag, memf, follow, sflag, tflag;
91122394Sharti
92122394Shartivoid dotrace(caddr_t);
93122394Shartivoid klseek(int, off_t, int);
94122394Shartiint numeric(const void *, const void *);
95124861Shartivoid tcp_trace(short, short, struct tcpcb *, int, void *, struct tcphdr *, int);
96122394Shartistatic void usage(void);
97122394Sharti
98122394Shartiint
99216294Ssyrinxmain(int argc, char **argv)
100216294Ssyrinx{
101216294Ssyrinx	int ch, i, jflag, npcbs;
102216294Ssyrinx	const char *core, *syst;
103216294Ssyrinx
104122394Sharti	nl[0].n_name = strdup("_tcp_debug");
105122394Sharti	nl[1].n_name = strdup("_tcp_debx");
106122394Sharti
107216594Ssyrinx	jflag = npcbs = 0;
108216594Ssyrinx	while ((ch = getopt(argc, argv, "afjp:st")) != -1)
109122394Sharti		switch (ch) {
110122394Sharti		case 'a':
111122394Sharti			++aflag;
112122394Sharti			break;
113122394Sharti		case 'f':
114122394Sharti			++follow;
115122394Sharti			setlinebuf(stdout);
116122394Sharti			break;
117122394Sharti		case 'j':
118122394Sharti			++jflag;
119122394Sharti			break;
120122394Sharti		case 'p':
121216294Ssyrinx			if (npcbs >= TCP_NDEBUG)
122216294Ssyrinx				errx(1, "too many pcb's specified");
123216294Ssyrinx			(void)sscanf(optarg, "%x", (int *)&tcp_pcbs[npcbs++]);
124216294Ssyrinx			break;
125216294Ssyrinx		case 's':
126216294Ssyrinx			++sflag;
127216294Ssyrinx			break;
128216294Ssyrinx		case 't':
129216294Ssyrinx			++tflag;
130216294Ssyrinx			break;
131216294Ssyrinx		case '?':
132216294Ssyrinx		default:
133216294Ssyrinx			usage();
134216294Ssyrinx		}
135216294Ssyrinx	argc -= optind;
136216294Ssyrinx	argv += optind;
137216294Ssyrinx
138216294Ssyrinx	core = _PATH_KMEM;
139216294Ssyrinx	if (argc > 0) {
140216294Ssyrinx		syst = *argv;
141216294Ssyrinx		argc--, argv++;
142216294Ssyrinx		if (argc > 0) {
143216294Ssyrinx			core = *argv;
144122394Sharti			argc--, argv++;
145122394Sharti			++kflag;
146122394Sharti		}
147122394Sharti		/*
148122394Sharti		 * Discard setgid privileges if not the running kernel so that
149122394Sharti		 * bad guys can't print interesting stuff from kernel memory.
150122394Sharti		 */
151122394Sharti		setgid(getgid());
152122394Sharti	}
153122394Sharti	else
154122394Sharti		syst = getbootfile();
155122394Sharti
156122394Sharti	if (nlist(syst, nl) < 0 || !nl[0].n_value)
157122394Sharti		errx(1, "%s: no namelist", syst);
158122394Sharti	if ((memf = open(core, O_RDONLY)) < 0)
159122394Sharti		err(2, "%s", core);
160122394Sharti	setgid(getgid());
161122394Sharti	if (kflag)
162122394Sharti		errx(1, "can't do core files yet");
163122394Sharti	(void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET);
164122394Sharti	if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) !=
165122394Sharti	    sizeof(tcp_debx))
166122394Sharti		err(3, "tcp_debx");
167122394Sharti	(void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
168122394Sharti	if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) !=
169122394Sharti	    sizeof(tcp_debug))
170216294Ssyrinx		err(3, "tcp_debug");
171216294Ssyrinx	/*
172216294Ssyrinx	 * If no control blocks have been specified, figure
173122394Sharti	 * out how many distinct one we have and summarize
174122394Sharti	 * them in tcp_pcbs for sorting the trace records
175122394Sharti	 * below.
176216294Ssyrinx	 */
177122394Sharti	if (!npcbs) {
178124861Sharti		for (i = 0; i < TCP_NDEBUG; i++) {
179122394Sharti			register struct tcp_debug *td = &tcp_debug[i];
180122394Sharti			register int j;
181124861Sharti
182122394Sharti			if (td->td_tcb == 0)
183122394Sharti				continue;
184122394Sharti			for (j = 0; j < npcbs; j++)
185122394Sharti				if (tcp_pcbs[j] == td->td_tcb)
186122394Sharti					break;
187122394Sharti			if (j >= npcbs)
188122394Sharti				tcp_pcbs[npcbs++] = td->td_tcb;
189122394Sharti		}
190122394Sharti		if (!npcbs)
191122394Sharti			exit(0);
192122394Sharti	}
193122394Sharti	qsort(tcp_pcbs, npcbs, sizeof(caddr_t), numeric);
194122394Sharti	if (jflag) {
195122394Sharti		for (i = 0;;) {
196122394Sharti			printf("%p", (void *)tcp_pcbs[i]);
197122394Sharti			if (++i == npcbs)
198122394Sharti				break;
199122394Sharti			fputs(", ", stdout);
200216294Ssyrinx		}
201216294Ssyrinx		putchar('\n');
202216294Ssyrinx	}
203216294Ssyrinx	else for (i = 0; i < npcbs; i++) {
204216294Ssyrinx		printf("\n%p:\n", tcp_pcbs[i]);
205216294Ssyrinx		dotrace(tcp_pcbs[i]);
206122394Sharti	}
207122394Sharti	exit(0);
208122394Sharti}
209122394Sharti
210122394Shartistatic void
211122394Shartiusage()
212122394Sharti{
213216294Ssyrinx	(void)fprintf(stderr,
214216294Ssyrinx		"usage: trpt [-afjst] [-p hex-address] [system [core]]\n");
215216294Ssyrinx	exit(1);
216122394Sharti}
217122394Sharti
218122394Shartivoid
219122394Shartidotrace(tcpcb)
220122394Sharti	register caddr_t tcpcb;
221216294Ssyrinx{
222122394Sharti	register struct tcp_debug *td;
223122394Sharti	register int i;
224122394Sharti	int prev_debx = tcp_debx, family;
225122394Sharti
226122394Shartiagain:	if (--tcp_debx < 0)
227122394Sharti		tcp_debx = TCP_NDEBUG - 1;
228145557Sharti	for (i = prev_debx % TCP_NDEBUG; i < TCP_NDEBUG; i++) {
229145557Sharti		td = &tcp_debug[i];
230145557Sharti		if (tcpcb && td->td_tcb != tcpcb)
231145557Sharti			continue;
232145557Sharti		ntime = ntohl(td->td_time);
233124861Sharti#ifdef INET6
234124861Sharti		family = td->td_family;
235124861Sharti#else
236124861Sharti		family = AF_INET;
237124861Sharti#endif
238124861Sharti		switch(family) {
239122394Sharti		case AF_INET:
240122394Sharti			tcp_trace(td->td_act, td->td_ostate,
241122394Sharti				  &td->td_cb, td->td_family, &td->td_ti.ti_i,
242122394Sharti				  &td->td_ti.ti_t, td->td_req);
243122394Sharti			break;
244122394Sharti#ifdef INET6
245122394Sharti		case AF_INET6:
246122394Sharti			tcp_trace(td->td_act, td->td_ostate,
247122394Sharti				  &td->td_cb, td->td_family, &td->td_ti6.ip6,
248122394Sharti				  &td->td_ti6.th, td->td_req);
249122394Sharti			break;
250122394Sharti#endif
251122394Sharti		}
252122394Sharti		if (i == tcp_debx)
253124861Sharti			goto done;
254122394Sharti	}
255122394Sharti	for (i = 0; i <= tcp_debx % TCP_NDEBUG; i++) {
256122394Sharti		td = &tcp_debug[i];
257122394Sharti		if (tcpcb && td->td_tcb != tcpcb)
258122394Sharti			continue;
259122394Sharti		ntime = ntohl(td->td_time);
260122394Sharti#ifdef INET6
261122394Sharti		family = td->td_family;
262122394Sharti#else
263122394Sharti		family = AF_INET;
264122394Sharti#endif
265124861Sharti		switch(family) {
266122394Sharti		case AF_INET:
267122394Sharti			tcp_trace(td->td_act, td->td_ostate,
268122394Sharti				  &td->td_cb, td->td_family, &td->td_ti.ti_i,
269122394Sharti				  &td->td_ti.ti_t, td->td_req);
270124861Sharti			break;
271122394Sharti#ifdef INET6
272122394Sharti		case AF_INET6:
273122394Sharti			tcp_trace(td->td_act, td->td_ostate,
274122394Sharti				  &td->td_cb, td->td_family, &td->td_ti6.ip6,
275122394Sharti				  &td->td_ti6.th, td->td_req);
276122394Sharti			break;
277124861Sharti#endif
278122394Sharti		}
279122394Sharti	}
280122394Shartidone:	if (follow) {
281122394Sharti		prev_debx = tcp_debx + 1;
282122394Sharti		if (prev_debx >= TCP_NDEBUG)
283122394Sharti			prev_debx = 0;
284122394Sharti		do {
285122394Sharti			sleep(1);
286122394Sharti			(void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET);
287122394Sharti			if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) !=
288122394Sharti			    sizeof(tcp_debx))
289122394Sharti				err(3, "tcp_debx");
290122394Sharti		} while (tcp_debx == prev_debx);
291122394Sharti		(void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
292122394Sharti		if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) !=
293122394Sharti		    sizeof(tcp_debug))
294122394Sharti			err(3, "tcp_debug");
295122394Sharti		goto again;
296122394Sharti	}
297216294Ssyrinx}
298122394Sharti
299216294Ssyrinx/*
300216294Ssyrinx * Tcp debug routines
301216294Ssyrinx */
302216294Ssyrinx/*ARGSUSED*/
303216294Ssyrinxvoid
304216294Ssyrinxtcp_trace(short act, short ostate, struct tcpcb *tp, int family __unused,
305216294Ssyrinx    void *ip, struct tcphdr *th, int req)
306216294Ssyrinx{
307216294Ssyrinx	tcp_seq seq, ack;
308216294Ssyrinx	int flags, len, win, timer;
309216294Ssyrinx	struct ip *ip4;
310216294Ssyrinx#ifdef INET6
311216294Ssyrinx	int isipv6, nopkt = 1;
312216294Ssyrinx	struct ip6_hdr *ip6;
313216294Ssyrinx	char ntop_buf[INET6_ADDRSTRLEN];
314216294Ssyrinx#endif
315216294Ssyrinx
316216294Ssyrinx#ifdef INET6
317216294Ssyrinx	switch (family) {
318216294Ssyrinx	case AF_INET:
319216294Ssyrinx		nopkt = 0;
320216294Ssyrinx		isipv6 = 0;
321216294Ssyrinx		ip4 = (struct ip *)ip;
322216294Ssyrinx		break;
323216294Ssyrinx	case AF_INET6:
324216294Ssyrinx		nopkt = 0;
325216294Ssyrinx		isipv6 = 1;
326216294Ssyrinx		ip6 = (struct ip6_hdr *)ip;
327216294Ssyrinx	case 0:
328216294Ssyrinx	default:
329216294Ssyrinx		break;
330216294Ssyrinx	}
331216294Ssyrinx#else
332216294Ssyrinx	ip4 = (struct ip *)ip;
333216294Ssyrinx#endif
334216294Ssyrinx	printf("%03ld %s:%s ", (long)((ntime/10) % 1000), tcpstates[ostate],
335216294Ssyrinx	    tanames[act]);
336216294Ssyrinx	switch (act) {
337216294Ssyrinx	case TA_INPUT:
338216294Ssyrinx	case TA_OUTPUT:
339216294Ssyrinx	case TA_DROP:
340216294Ssyrinx#ifdef INET6
341216294Ssyrinx		if (nopkt != 0)
342216294Ssyrinx			break;
343216294Ssyrinx#endif
344216294Ssyrinx		if (aflag) {
345216294Ssyrinx			printf("(src=%s,%u, ",
346216294Ssyrinx
347216294Ssyrinx#ifdef INET6
348216294Ssyrinx			       isipv6
349216294Ssyrinx			       ? inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf,
350216294Ssyrinx					   sizeof(ntop_buf)) :
351216294Ssyrinx#endif
352216294Ssyrinx			       inet_ntoa(ip4->ip_src),
353216294Ssyrinx			       ntohs(th->th_sport));
354216294Ssyrinx			printf("dst=%s,%u)",
355216294Ssyrinx#ifdef INET6
356216294Ssyrinx			       isipv6
357216294Ssyrinx			       ? inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf,
358216294Ssyrinx					   sizeof(ntop_buf)) :
359216294Ssyrinx#endif
360216294Ssyrinx			       inet_ntoa(ip4->ip_dst),
361216294Ssyrinx			       ntohs(th->th_dport));
362216294Ssyrinx		}
363216294Ssyrinx		seq = th->th_seq;
364216294Ssyrinx		ack = th->th_ack;
365216294Ssyrinx
366216294Ssyrinx		len =
367216294Ssyrinx#ifdef INET6
368216294Ssyrinx			isipv6 ? ip6->ip6_plen :
369216294Ssyrinx#endif
370216294Ssyrinx			ip4->ip_len;
371216294Ssyrinx		win = th->th_win;
372216594Ssyrinx		if (act == TA_OUTPUT) {
373216294Ssyrinx			seq = ntohl(seq);
374216294Ssyrinx			ack = ntohl(ack);
375216294Ssyrinx			len = ntohs(len);
376216294Ssyrinx			win = ntohs(win);
377216294Ssyrinx		}
378216294Ssyrinx		if (act == TA_OUTPUT)
379216294Ssyrinx			len -= sizeof(struct tcphdr);
380216294Ssyrinx		if (len)
381216294Ssyrinx			printf("[%lx..%lx)", (u_long)seq, (u_long)(seq + len));
382216294Ssyrinx		else
383216294Ssyrinx			printf("%lx", (u_long)seq);
384216294Ssyrinx		printf("@%lx", (u_long)ack);
385216294Ssyrinx		if (win)
386216294Ssyrinx			printf("(win=%x)", win);
387216294Ssyrinx		flags = th->th_flags;
388216294Ssyrinx		if (flags) {
389216294Ssyrinx			const char *cp = "<";
390216294Ssyrinx#define	pf(flag, string) { \
391216294Ssyrinx	if (th->th_flags&flag) { \
392216294Ssyrinx		(void)printf("%s%s", cp, string); \
393216294Ssyrinx		cp = ","; \
394216294Ssyrinx	} \
395216294Ssyrinx}
396216294Ssyrinx			pf(TH_SYN, "SYN");
397216294Ssyrinx			pf(TH_ACK, "ACK");
398216294Ssyrinx			pf(TH_FIN, "FIN");
399216294Ssyrinx			pf(TH_RST, "RST");
400216294Ssyrinx			pf(TH_PUSH, "PUSH");
401216294Ssyrinx			pf(TH_URG, "URG");
402216294Ssyrinx			printf(">");
403216294Ssyrinx		}
404216294Ssyrinx		break;
405216294Ssyrinx	case TA_USER:
406216294Ssyrinx		timer = req >> 8;
407216294Ssyrinx		req &= 0xff;
408216294Ssyrinx		printf("%s", prurequests[req]);
409216294Ssyrinx		if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO)
410216294Ssyrinx			printf("<%s>", tcptimers[timer]);
411216294Ssyrinx		break;
412216294Ssyrinx	}
413216294Ssyrinx	printf(" -> %s", tcpstates[tp->t_state]);
414216294Ssyrinx	/* print out internal state of tp !?! */
415216294Ssyrinx	printf("\n");
416216294Ssyrinx	if (sflag) {
417216294Ssyrinx		printf("\trcv_nxt %lx rcv_wnd %lx snd_una %lx snd_nxt %lx snd_max %lx\n",
418216294Ssyrinx		    (u_long)tp->rcv_nxt, tp->rcv_wnd,
419216294Ssyrinx		    (u_long)tp->snd_una, (u_long)tp->snd_nxt,
420216294Ssyrinx		    (u_long)tp->snd_max);
421216294Ssyrinx		printf("\tsnd_wl1 %lx snd_wl2 %lx snd_wnd %lx\n",
422216294Ssyrinx		    (u_long)tp->snd_wl1,
423216294Ssyrinx		    (u_long)tp->snd_wl2, tp->snd_wnd);
424216294Ssyrinx	}
425216294Ssyrinx	/* print out timers? */
426216294Ssyrinx#if 0
427216294Ssyrinx	/*
428216294Ssyrinx	 * XXX
429216294Ssyrinx	 * kernel now uses callouts, not integer time values.
430216294Ssyrinx	 */
431216294Ssyrinx	if (tflag) {
432216294Ssyrinx		register char *cp = "\t";
433216294Ssyrinx		register int i;
434216294Ssyrinx
435216294Ssyrinx		for (i = 0; i < TCPT_NTIMERS; i++) {
436216294Ssyrinx			if (tp->t_timer[i] == 0)
437216294Ssyrinx				continue;
438216294Ssyrinx			printf("%s%s=%d", cp, tcptimers[i], tp->t_timer[i]);
439216294Ssyrinx			if (i == TCPT_REXMT)
440216294Ssyrinx				printf(" (t_rxtshft=%d)", tp->t_rxtshift);
441216294Ssyrinx			cp = ", ";
442216294Ssyrinx		}
443216294Ssyrinx		if (*cp != '\t')
444216294Ssyrinx			putchar('\n');
445216294Ssyrinx	}
446216294Ssyrinx#endif
447216294Ssyrinx}
448216294Ssyrinx
449216294Ssyrinxint
450216294Ssyrinxnumeric(v1, v2)
451216294Ssyrinx	const void *v1, *v2;
452216294Ssyrinx{
453216294Ssyrinx	const caddr_t *c1 = v1, *c2 = v2;
454216294Ssyrinx	return(*c1 - *c2);
455216294Ssyrinx}
456216294Ssyrinx
457216294Ssyrinxvoid
458216294Ssyrinxklseek(fd, base, off)
459216294Ssyrinx	int fd, off;
460216294Ssyrinx	off_t base;
461216294Ssyrinx{
462216294Ssyrinx	(void)lseek(fd, base, off);
463216294Ssyrinx}
464216294Ssyrinx