xref: /openbsd/usr.sbin/trpt/trpt.c (revision 07ea8d15)
1 /*
2  * Copyright (c) 1983, 1988 Regents of the University of California.
3  * 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 char copyright[] =
36 "@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\
37  All rights reserved.\n";
38 #endif /* not lint */
39 
40 #ifndef lint
41 /*static char sccsid[] = "from: @(#)trpt.c	5.14 (Berkeley) 7/1/91";*/
42 static char rcsid[] = "$Id: trpt.c,v 1.3 1996/06/03 18:06:18 deraadt Exp $";
43 #endif /* not lint */
44 
45 #include <sys/param.h>
46 #include <sys/queue.h>
47 #if BSD >= 199103
48 #define NEWVM
49 #endif
50 #ifndef NEWVM
51 #include <machine/pte.h>
52 #include <sys/vmmac.h>
53 #endif
54 #include <sys/socket.h>
55 #include <sys/socketvar.h>
56 #define PRUREQUESTS
57 #include <sys/protosw.h>
58 #include <sys/file.h>
59 
60 #include <net/route.h>
61 #include <net/if.h>
62 
63 #include <netinet/in.h>
64 #include <netinet/in_systm.h>
65 #include <netinet/ip.h>
66 #include <netinet/in_pcb.h>
67 #include <netinet/ip_var.h>
68 #include <netinet/tcp.h>
69 #define TCPSTATES
70 #include <netinet/tcp_fsm.h>
71 #include <netinet/tcp_seq.h>
72 #define	TCPTIMERS
73 #include <netinet/tcp_timer.h>
74 #include <netinet/tcp_var.h>
75 #include <netinet/tcpip.h>
76 #define	TANAMES
77 #include <netinet/tcp_debug.h>
78 
79 #include <arpa/inet.h>
80 
81 #include <stdio.h>
82 #include <errno.h>
83 #include <nlist.h>
84 #include <paths.h>
85 
86 struct nlist nl[] = {
87 #define	N_TCP_DEBUG	0
88 	{ "_tcp_debug" },
89 #define	N_TCP_DEBX	1
90 	{ "_tcp_debx" },
91 #ifndef NEWVM
92 #define	N_SYSMAP	2
93 	{ "_Sysmap" },
94 #define	N_SYSSIZE	3
95 	{ "_Syssize" },
96 #endif
97 	{ "" },
98 };
99 
100 #ifndef NEWVM
101 static struct pte *Sysmap;
102 #endif
103 static caddr_t tcp_pcbs[TCP_NDEBUG];
104 static n_time ntime;
105 static int aflag, kflag, memf, follow, sflag, tflag;
106 
107 main(argc, argv)
108 	int argc;
109 	char **argv;
110 {
111 	extern char *optarg;
112 	extern int optind;
113 	int ch, i, jflag, npcbs, numeric();
114 	char *system, *core, *malloc();
115 	off_t lseek();
116 
117 	jflag = npcbs = 0;
118 	while ((ch = getopt(argc, argv, "afjp:st")) != EOF)
119 		switch (ch) {
120 		case 'a':
121 			++aflag;
122 			break;
123 		case 'f':
124 			++follow;
125 			setlinebuf(stdout);
126 			break;
127 		case 'j':
128 			++jflag;
129 			break;
130 		case 'p':
131 			if (npcbs >= TCP_NDEBUG) {
132 				fputs("trpt: too many pcb's specified\n",
133 				    stderr);
134 				exit(1);
135 			}
136 			(void)sscanf(optarg, "%x", (int *)&tcp_pcbs[npcbs++]);
137 			break;
138 		case 's':
139 			++sflag;
140 			break;
141 		case 't':
142 			++tflag;
143 			break;
144 		case '?':
145 		default:
146 			(void)fprintf(stderr,
147 "usage: trpt [-afjst] [-p hex-address] [system [core]]\n");
148 			exit(1);
149 		}
150 	argc -= optind;
151 	argv += optind;
152 
153 	core = _PATH_KMEM;
154 	if (argc > 0) {
155 		system = *argv;
156 		argc--, argv++;
157 		if (argc > 0) {
158 			core = *argv;
159 			argc--, argv++;
160 			++kflag;
161 		}
162 	}
163 	else
164 		system = _PATH_UNIX;
165 
166 	/*
167 	 * Discard setgid priviledges if not the running kernel so that bad
168 	 * guys can't print interesting stuff from kernel memory.
169 	 */
170 	if (!strcmp(core, _PATH_KMEM) || !strcmp(system, _PATH_UNIX))
171 		setgid(getgid());
172 
173 	if (nlist(system, nl) < 0 || !nl[0].n_value) {
174 		fprintf(stderr, "trpt: %s: no namelist\n", system);
175 		exit(1);
176 	}
177 	if ((memf = open(core, O_RDONLY)) < 0) {
178 		perror(core);
179 		exit(2);
180 	}
181 	if (kflag) {
182 #ifdef NEWVM
183 		fputs("trpt: can't do core files yet\n", stderr);
184 		exit(1);
185 #else
186 		off_t off;
187 
188 		Sysmap = (struct pte *)
189 		   malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
190 		if (!Sysmap) {
191 			fputs("trpt: can't get memory for Sysmap.\n", stderr);
192 			exit(1);
193 		}
194 		off = nl[N_SYSMAP].n_value & ~KERNBASE;
195 		(void)lseek(memf, off, L_SET);
196 		(void)read(memf, (char *)Sysmap,
197 		    (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
198 #endif
199 	}
200 	(void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET);
201 	if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) !=
202 	    sizeof(tcp_debx)) {
203 		perror("trpt: tcp_debx");
204 		exit(3);
205 	}
206 	(void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
207 	if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) !=
208 	    sizeof(tcp_debug)) {
209 		perror("trpt: tcp_debug");
210 		exit(3);
211 	}
212 	/*
213 	 * If no control blocks have been specified, figure
214 	 * out how many distinct one we have and summarize
215 	 * them in tcp_pcbs for sorting the trace records
216 	 * below.
217 	 */
218 	if (!npcbs) {
219 		for (i = 0; i < TCP_NDEBUG; i++) {
220 			register struct tcp_debug *td = &tcp_debug[i];
221 			register int j;
222 
223 			if (td->td_tcb == 0)
224 				continue;
225 			for (j = 0; j < npcbs; j++)
226 				if (tcp_pcbs[j] == td->td_tcb)
227 					break;
228 			if (j >= npcbs)
229 				tcp_pcbs[npcbs++] = td->td_tcb;
230 		}
231 		if (!npcbs)
232 			exit(0);
233 	}
234 	qsort(tcp_pcbs, npcbs, sizeof(caddr_t), numeric);
235 	if (jflag) {
236 		for (i = 0;;) {
237 			printf("%lx", (long)tcp_pcbs[i]);
238 			if (++i == npcbs)
239 				break;
240 			fputs(", ", stdout);
241 		}
242 		putchar('\n');
243 	}
244 	else for (i = 0; i < npcbs; i++) {
245 		printf("\n%lx:\n", (long)tcp_pcbs[i]);
246 		dotrace(tcp_pcbs[i]);
247 	}
248 	exit(0);
249 }
250 
251 dotrace(tcpcb)
252 	register caddr_t tcpcb;
253 {
254 	register struct tcp_debug *td;
255 	register int i;
256 	int prev_debx = tcp_debx;
257 
258 again:	if (--tcp_debx < 0)
259 		tcp_debx = TCP_NDEBUG - 1;
260 	for (i = prev_debx % TCP_NDEBUG; i < TCP_NDEBUG; i++) {
261 		td = &tcp_debug[i];
262 		if (tcpcb && td->td_tcb != tcpcb)
263 			continue;
264 		ntime = ntohl(td->td_time);
265 		tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb,
266 		    &td->td_ti, td->td_req);
267 		if (i == tcp_debx)
268 			goto done;
269 	}
270 	for (i = 0; i <= tcp_debx % TCP_NDEBUG; i++) {
271 		td = &tcp_debug[i];
272 		if (tcpcb && td->td_tcb != tcpcb)
273 			continue;
274 		ntime = ntohl(td->td_time);
275 		tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb,
276 		    &td->td_ti, td->td_req);
277 	}
278 done:	if (follow) {
279 		prev_debx = tcp_debx + 1;
280 		if (prev_debx >= TCP_NDEBUG)
281 			prev_debx = 0;
282 		do {
283 			sleep(1);
284 			(void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET);
285 			if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) !=
286 			    sizeof(tcp_debx)) {
287 				perror("trpt: tcp_debx");
288 				exit(3);
289 			}
290 		} while (tcp_debx == prev_debx);
291 		(void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
292 		if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) !=
293 		    sizeof(tcp_debug)) {
294 			perror("trpt: tcp_debug");
295 			exit(3);
296 		}
297 		goto again;
298 	}
299 }
300 
301 /*
302  * Tcp debug routines
303  */
304 /*ARGSUSED*/
305 tcp_trace(act, ostate, atp, tp, ti, req)
306 	short act, ostate;
307 	struct tcpcb *atp, *tp;
308 	struct tcpiphdr *ti;
309 	int req;
310 {
311 	tcp_seq seq, ack;
312 	int flags, len, win, timer;
313 
314 	printf("%03ld %s:%s ",(ntime/10) % 1000, tcpstates[ostate],
315 	    tanames[act]);
316 	switch (act) {
317 	case TA_INPUT:
318 	case TA_OUTPUT:
319 	case TA_DROP:
320 		if (aflag) {
321 			printf("(src=%s,%u, ",
322 			    inet_ntoa(ti->ti_src), ntohs(ti->ti_sport));
323 			printf("dst=%s,%u)",
324 			    inet_ntoa(ti->ti_dst), ntohs(ti->ti_dport));
325 		}
326 		seq = ti->ti_seq;
327 		ack = ti->ti_ack;
328 		len = ti->ti_len;
329 		win = ti->ti_win;
330 		if (act == TA_OUTPUT) {
331 			seq = ntohl(seq);
332 			ack = ntohl(ack);
333 			len = ntohs(len);
334 			win = ntohs(win);
335 		}
336 		if (act == TA_OUTPUT)
337 			len -= sizeof(struct tcphdr);
338 		if (len)
339 			printf("[%lx..%lx)", seq, seq + len);
340 		else
341 			printf("%lx", seq);
342 		printf("@%lx", ack);
343 		if (win)
344 			printf("(win=%x)", win);
345 		flags = ti->ti_flags;
346 		if (flags) {
347 			register char *cp = "<";
348 #define	pf(flag, string) { \
349 	if (ti->ti_flags&flag) { \
350 		(void)printf("%s%s", cp, string); \
351 		cp = ","; \
352 	} \
353 }
354 			pf(TH_SYN, "SYN");
355 			pf(TH_ACK, "ACK");
356 			pf(TH_FIN, "FIN");
357 			pf(TH_RST, "RST");
358 			pf(TH_PUSH, "PUSH");
359 			pf(TH_URG, "URG");
360 			printf(">");
361 		}
362 		break;
363 	case TA_USER:
364 		timer = req >> 8;
365 		req &= 0xff;
366 		printf("%s", prurequests[req]);
367 		if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO)
368 			printf("<%s>", tcptimers[timer]);
369 		break;
370 	}
371 	printf(" -> %s", tcpstates[tp->t_state]);
372 	/* print out internal state of tp !?! */
373 	printf("\n");
374 	if (sflag) {
375 		printf("\trcv_nxt %lx rcv_wnd %x snd_una %lx snd_nxt %lx snd_max %lx\n",
376 		    tp->rcv_nxt, tp->rcv_wnd, tp->snd_una, tp->snd_nxt,
377 		    tp->snd_max);
378 		printf("\tsnd_wl1 %lx snd_wl2 %lx snd_wnd %x\n", tp->snd_wl1,
379 		    tp->snd_wl2, tp->snd_wnd);
380 	}
381 	/* print out timers? */
382 	if (tflag) {
383 		register char *cp = "\t";
384 		register int i;
385 
386 		for (i = 0; i < TCPT_NTIMERS; i++) {
387 			if (tp->t_timer[i] == 0)
388 				continue;
389 			printf("%s%s=%d", cp, tcptimers[i], tp->t_timer[i]);
390 			if (i == TCPT_REXMT)
391 				printf(" (t_rxtshft=%d)", tp->t_rxtshift);
392 			cp = ", ";
393 		}
394 		if (*cp != '\t')
395 			putchar('\n');
396 	}
397 }
398 
399 numeric(c1, c2)
400 	caddr_t *c1, *c2;
401 {
402 	return(*c1 - *c2);
403 }
404 
405 klseek(fd, base, off)
406 	int fd, off;
407 	off_t base;
408 {
409 	off_t lseek();
410 
411 #ifndef NEWVM
412 	if (kflag) {	/* get kernel pte */
413 		base &= ~KERNBASE;
414 		base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
415 	}
416 #endif
417 	(void)lseek(fd, base, off);
418 }
419