xref: /freebsd/cddl/usr.sbin/dwatch/libexec/tcp (revision 06c3fb27)
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#
8############################################################ DESCRIPTION
9#
10# Display local/remote TCP addresses/ports and bytes sent/received for TCP I/O
11#
12############################################################ PROBE
13
14case "$PROFILE" in
15tcp)
16	: ${PROBE:=$( echo \
17		tcp:::accept-established, \
18		tcp:::accept-refused, \
19		tcp:::connect-established, \
20		tcp:::connect-refused, \
21		tcp:::connect-request, \
22		tcp:::receive, \
23		tcp:::send, \
24		tcp:::state-change )} ;;
25tcp-accept)
26	: ${PROBE:=tcp:::accept-established, tcp:::accept-refused} ;;
27tcp-connect)
28	: ${PROBE:=$( echo \
29		tcp:::connect-established, \
30		tcp:::connect-refused, \
31		tcp:::connect-request )} ;;
32tcp-established)
33	: ${PROBE:=tcp:::accept-established, tcp:::connect-established} ;;
34tcp-init)
35	: ${PROBE:=$( echo \
36		tcp:::accept-established, \
37		tcp:::accept-refused, \
38		tcp:::connect-established, \
39		tcp:::connect-refused, \
40		tcp:::connect-request )} ;;
41tcp-io)
42	: ${PROBE:=tcp:::send, tcp:::receive} ;;
43tcp-refused)
44	: ${PROBE:=tcp:::accept-refused, tcp:::connect-refused} ;;
45tcp-status)
46	: ${PROBE:=$( echo \
47		tcp:::accept-established, \
48		tcp:::accept-refused, \
49		tcp:::connect-established, \
50		tcp:::connect-refused, \
51		tcp:::connect-request, \
52		tcp:::state-change )} ;;
53*)
54	: ${PROBE:=tcp:::${PROFILE#tcp-}}
55esac
56
57############################################################ ACTIONS
58
59exec 9<<EOF
60this int32_t	from_state;
61this int32_t	to_state;
62this string	details;
63this string	flow;
64this string	local;
65this string	remote;
66this u_char	local6;
67this u_char	remote6;
68this u_char	slocal;
69this uint16_t	lport;
70this uint16_t	rport;
71this uint32_t	length;
72
73inline string probeflow[string name] =
74	name == "accept-established" ?	"<-" :
75	name == "accept-refused" ?	"X-" :
76	name == "connect-refused" ?	"-X" :
77	name == "connect-request" ?	"-?" :
78	name == "receive" ?		"<-" :
79	"->";
80
81inline u_char srclocal[string name] =
82	name == "accept-refused" ?	1 :
83	name == "connect-request" ?	1 :
84	name == "send" ?		1 :
85	0;
86
87/*
88 * TCPSTATES from <sys/netinet/tcp_fsm.h> used by netstat(1)
89 */
90inline string tcpstate[int32_t state] =
91        state == TCPS_CLOSED ?		"CLOSED" :
92        state == TCPS_LISTEN ?		"LISTEN" :
93        state == TCPS_SYN_SENT ?	"SYN_SENT" :
94        state == TCPS_SYN_RECEIVED ?	"SYN_RCVD" :
95        state == TCPS_ESTABLISHED ?	"ESTABLISHED" :
96        state == TCPS_CLOSE_WAIT ?	"CLOSE_WAIT" :
97        state == TCPS_FIN_WAIT_1 ?	"FIN_WAIT_1" :
98        state == TCPS_CLOSING ?		"CLOSING" :
99        state == TCPS_LAST_ACK ?	"LAST_ACK" :
100        state == TCPS_FIN_WAIT_2 ?	"FIN_WAIT_2" :
101        state == TCPS_TIME_WAIT ?	"TIME_WAIT" :
102        strjoin("UNKNOWN(", strjoin(lltostr(state), ")"));
103
104$PROBE /* probe ID $ID */
105{${TRACE:+
106	printf("<$ID>");}
107	this->details = "";
108
109	/*
110	 * dtrace_tcp(4)
111	 */
112	this->flow = probeflow[probename];
113}
114
115tcp:::accept-established,
116tcp:::accept-refused,
117tcp:::connect-established,
118tcp:::connect-refused,
119tcp:::connect-request,
120tcp:::receive,
121tcp:::send /* probe ID $(( $ID + 1 )) */
122{${TRACE:+
123	printf("<$(( $ID + 1 ))>");
124}
125	/*
126	 * dtrace_tcp(4)
127	 */
128	this->slocal = srclocal[probename];
129
130	/*
131	 * ipinfo_t *
132	 */
133	this->local  = this->slocal ? args[2]->ip_saddr : args[2]->ip_daddr;
134	this->remote = this->slocal ? args[2]->ip_daddr : args[2]->ip_saddr;
135
136	/*
137	 * tcpinfo_t *
138	 */
139	this->lport = this->slocal ? args[4]->tcp_sport : args[4]->tcp_dport;
140	this->rport = this->slocal ? args[4]->tcp_dport : args[4]->tcp_sport;
141
142	/*
143	 * IPv6 support
144	 */
145	this->local6 = strstr(this->local, ":") != NULL ? 1 : 0;
146	this->remote6 = strstr(this->remote, ":") != NULL ? 1 : 0;
147	this->local = strjoin(strjoin(this->local6 ? "[" : "",
148		this->local), this->local6 ? "]" : "");
149	this->remote = strjoin(strjoin(this->remote6 ? "[" : "",
150		this->remote), this->remote6 ? "]" : "");
151}
152
153tcp:::state-change /* probe ID $(( $ID + 2 )) */
154{${TRACE:+
155	printf("<$(( $ID + 2 ))>");
156}
157	/*
158	 * tcpsinfo_t *
159	 */
160	this->local    = args[3]->tcps_laddr;
161	this->lport    = (uint16_t)args[3]->tcps_lport;
162	this->remote   = args[3]->tcps_raddr;
163	this->rport    = (uint16_t)args[3]->tcps_rport;
164	this->to_state = (int32_t)args[3]->tcps_state;
165
166	/*
167	 * tcplsinfo_t *
168	 */
169	this->from_state = (int32_t)args[5]->tcps_state;
170
171	/* flow = "[from state]->[to state]" */
172	this->flow = strjoin(tcpstate[this->from_state],
173		strjoin("->", tcpstate[this->to_state]));
174}
175
176tcp:::send, tcp:::receive /* pribe ID $(( $ID + 3 )) */
177{${TRACE:+
178	printf("<$(( $ID + 3 ))>");}
179	this->length = (uint32_t)args[2]->ip_plength -
180		(uint8_t)args[4]->tcp_offset;
181
182	/* details = " <length> byte<s>" */
183	this->details = strjoin(
184		strjoin(" ", lltostr(this->length)),
185		strjoin(" byte", this->length == 1 ? "" : "s"));
186}
187EOF
188ACTIONS=$( cat <&9 )
189ID=$(( $ID + 4 ))
190
191############################################################ EVENT DETAILS
192
193if [ ! "$CUSTOM_DETAILS" ]; then
194exec 9<<EOF
195	/*
196	 * Print details
197	 */
198	printf("%s:%u %s %s:%u%s",
199		this->local, this->lport,
200		this->flow,
201		this->remote, this->rport,
202		this->details);
203EOF
204EVENT_DETAILS=$( cat <&9 )
205fi
206
207################################################################################
208# END
209################################################################################
210