xref: /freebsd/cddl/usr.sbin/dwatch/libexec/tcp (revision 5bf5ca772c6de2d53344a78cf461447cc322ccea)
1# -*- tab-width: 4 -*- ;; Emacs
2# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM
3############################################################ IDENT(1)
4#
5# $Title: dwatch(8) module for dtrace_tcp(4) connections $
6# $Copyright: 2014-2018 Devin Teske. All rights reserved. $
7# $FreeBSD$
8#
9############################################################ DESCRIPTION
10#
11# Display local/remote TCP addresses/ports and bytes sent/received for TCP I/O
12#
13############################################################ PROBE
14
15case "$PROFILE" in
16tcp)
17	: ${PROBE:=$( echo \
18		tcp:::accept-established, \
19		tcp:::accept-refused, \
20		tcp:::connect-established, \
21		tcp:::connect-refused, \
22		tcp:::connect-request, \
23		tcp:::receive, \
24		tcp:::send, \
25		tcp:::state-change )} ;;
26tcp-accept)
27	: ${PROBE:=tcp:::accept-established, tcp:::accept-refused} ;;
28tcp-connect)
29	: ${PROBE:=$( echo \
30		tcp:::connect-established, \
31		tcp:::connect-refused, \
32		tcp:::connect-request )} ;;
33tcp-established)
34	: ${PROBE:=tcp:::accept-established, tcp:::connect-established} ;;
35tcp-init)
36	: ${PROBE:=$( echo \
37		tcp:::accept-established, \
38		tcp:::accept-refused, \
39		tcp:::connect-established, \
40		tcp:::connect-refused, \
41		tcp:::connect-request )} ;;
42tcp-io)
43	: ${PROBE:=tcp:::send, tcp:::receive} ;;
44tcp-refused)
45	: ${PROBE:=tcp:::accept-refused, tcp:::connect-refused} ;;
46tcp-status)
47	: ${PROBE:=$( echo \
48		tcp:::accept-established, \
49		tcp:::accept-refused, \
50		tcp:::connect-established, \
51		tcp:::connect-refused, \
52		tcp:::connect-request, \
53		tcp:::state-change )} ;;
54*)
55	: ${PROBE:=tcp:::${PROFILE#tcp-}}
56esac
57
58############################################################ GLOBALS
59
60#
61# This profile does not support these dwatch features
62# NB: They are disabled here so they have no effect when profile is loaded
63#
64unset EXECNAME		# -k name
65unset EXECREGEX		# -z regex
66unset GROUP		# -g group
67unset PID		# -p pid
68unset PSARGS		# affects -d
69unset PSTREE		# -R
70unset USER		# -u user
71
72############################################################ ACTIONS
73
74exec 9<<EOF
75this int32_t	from_state;
76this int32_t	to_state;
77this string	details;
78this string	flow;
79this string	local;
80this string	remote;
81this u_char	local6;
82this u_char	remote6;
83this u_char	slocal;
84this uint16_t	lport;
85this uint16_t	rport;
86this uint32_t	length;
87
88inline string probeflow[string name] =
89	name == "accept-established" ?	"<-" :
90	name == "accept-refused" ?	"X-" :
91	name == "connect-refused" ?	"-X" :
92	name == "connect-request" ?	"-?" :
93	name == "receive" ?		"<-" :
94	"->";
95
96inline u_char srclocal[string name] =
97	name == "accept-refused" ?	1 :
98	name == "connect-request" ?	1 :
99	name == "send" ?		1 :
100	0;
101
102/*
103 * TCPSTATES from <sys/netinet/tcp_fsm.h> used by netstat(1)
104 */
105inline string tcpstate[int32_t state] =
106        state == TCPS_CLOSED ?		"CLOSED" :
107        state == TCPS_LISTEN ?		"LISTEN" :
108        state == TCPS_SYN_SENT ?	"SYN_SENT" :
109        state == TCPS_SYN_RECEIVED ?	"SYN_RCVD" :
110        state == TCPS_ESTABLISHED ?	"ESTABLISHED" :
111        state == TCPS_CLOSE_WAIT ?	"CLOSE_WAIT" :
112        state == TCPS_FIN_WAIT_1 ?	"FIN_WAIT_1" :
113        state == TCPS_CLOSING ?		"CLOSING" :
114        state == TCPS_LAST_ACK ?	"LAST_ACK" :
115        state == TCPS_FIN_WAIT_2 ?	"FIN_WAIT_2" :
116        state == TCPS_TIME_WAIT ?	"TIME_WAIT" :
117        strjoin("UNKNOWN(", strjoin(lltostr(state), ")"));
118
119$PROBE /* probe ID $ID */
120{${TRACE:+
121	printf("<$ID>");}
122	this->details = "";
123
124	/*
125	 * dtrace_tcp(4)
126	 */
127	this->flow = probeflow[probename];
128}
129
130tcp:::accept-established,
131tcp:::accept-refused,
132tcp:::connect-established,
133tcp:::connect-refused,
134tcp:::connect-request,
135tcp:::receive,
136tcp:::send /* probe ID $(( $ID + 1 )) */
137{${TRACE:+
138	printf("<$(( $ID + 1 ))>");
139}
140	/*
141	 * dtrace_tcp(4)
142	 */
143	this->slocal = srclocal[probename];
144
145	/*
146	 * ipinfo_t *
147	 */
148	this->local  = this->slocal ? args[2]->ip_saddr : args[2]->ip_daddr;
149	this->remote = this->slocal ? args[2]->ip_daddr : args[2]->ip_saddr;
150
151	/*
152	 * tcpinfo_t *
153	 */
154	this->lport = this->slocal ? args[4]->tcp_sport : args[4]->tcp_dport;
155	this->rport = this->slocal ? args[4]->tcp_dport : args[4]->tcp_sport;
156
157	/*
158	 * IPv6 support
159	 */
160	this->local6 = strstr(this->local, ":") != NULL ? 1 : 0;
161	this->remote6 = strstr(this->remote, ":") != NULL ? 1 : 0;
162	this->local = strjoin(strjoin(this->local6 ? "[" : "",
163		this->local), this->local6 ? "]" : "");
164	this->remote = strjoin(strjoin(this->remote6 ? "[" : "",
165		this->remote), this->remote6 ? "]" : "");
166}
167
168tcp:::state-change /* probe ID $(( $ID + 2 )) */
169{${TRACE:+
170	printf("<$(( $ID + 2 ))>");
171}
172	/*
173	 * tcpsinfo_t *
174	 */
175	this->local    = args[3]->tcps_laddr;
176	this->lport    = (uint16_t)args[3]->tcps_lport;
177	this->remote   = args[3]->tcps_raddr;
178	this->rport    = (uint16_t)args[3]->tcps_rport;
179	this->to_state = (int32_t)args[3]->tcps_state;
180
181	/*
182	 * tcplsinfo_t *
183	 */
184	this->from_state = (int32_t)args[5]->tcps_state;
185
186	/* flow = "[from state]->[to state]" */
187	this->flow = strjoin(tcpstate[this->from_state],
188		strjoin("->", tcpstate[this->to_state]));
189}
190
191tcp:::send, tcp:::receive /* pribe ID $(( $ID + 3 )) */
192{${TRACE:+
193	printf("<$(( $ID + 3 ))>");}
194	this->length = (uint32_t)args[2]->ip_plength -
195		(uint8_t)args[4]->tcp_offset;
196
197	/* details = " <length> byte<s>" */
198	this->details = strjoin(
199		strjoin(" ", lltostr(this->length)),
200		strjoin(" byte", this->length == 1 ? "" : "s"));
201}
202EOF
203ACTIONS=$( cat <&9 )
204ID=$(( $ID + 4 ))
205
206############################################################ EVENT TAG
207
208exec 9<<EOF
209	printf("%s: ", "$PROFILE");
210EOF
211EVENT_TAG=$( cat <&9 )
212
213############################################################ EVENT DETAILS
214
215exec 9<<EOF
216	/*
217	 * Print details
218	 */
219	printf("%s:%u %s %s:%u%s",
220		this->local, this->lport,
221		this->flow,
222		this->remote, this->rport,
223		this->details);
224EOF
225EVENT_DETAILS=$( cat <&9 )
226
227################################################################################
228# END
229################################################################################
230