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