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) JSON module for network activity $
6# $Copyright: 2014-2018 Devin Teske. All rights reserved. $
7# $FrauBSD: dwatch-json/json-net-config-raw 2018-10-01 16:20:48 -0700 freebsdfrau $
8#
9############################################################ DESCRIPTION
10#
11# Produce JSON custom log format for network activity
12#
13############################################################ PROBE
14
15: ${PROBE:=profile-10s}
16
17############################################################ CONFIG
18
19# Defaults
20: ${REPORT_TYPE:=${PROFILE%-raw}}
21: ${HOSTNAME:=$( hostname )}
22
23# Configured variables before loading config
24vars="$( set | awk 'match($0,
25	/^[a-zA-Z_][a-zA-Z0-9_]*=/) { print substr($0, 1, RLENGTH - 1) }'
26) vars"
27
28# Config
29. /usr/local/etc/dwatch-${PROFILE%-config*}.conf || exit
30
31# Variables found in config
32export vars
33conf=$( set | awk '
34BEGIN {
35	conf = ""
36	delete env
37	nvars = split(ENVIRON["vars"], vars)
38	for (n = 1; n <= nvars; n++) env[vars[n]]
39}
40match($0, /^[a-zA-Z_][a-zA-Z0-9_]*=/) {
41	name = substr($0, 1, RLENGTH - 1)
42	if (name in env) next
43	conf = conf " " name
44}
45END { print substr(conf, 2) }' )
46
47############################################################ OVERRIDES
48
49MAX_ARGS=0		# -B num
50MAX_DEPTH=0		# -K num
51
52#
53# Unsupported features
54#
55unset EXECREGEX		# -z regex
56unset GROUP		# -g group
57unset PID		# -p pid
58unset PROBE_COALESCE	# -F
59unset PSTREE		# -R
60unset USER		# -u user
61
62############################################################ EVENT ACTION
63
64_EVENT_TEST="${EVENT_TEST:+($EVENT_TEST)}"
65_EVENT_TEST="${CUSTOM_TEST:+$CUSTOM_TEST${EVENT_TEST:+ && }}$_EVENT_TEST"
66if [ "$JID" ]; then
67	pr_id="curthread->td_proc->p_ucred->cr_prison->pr_id"
68	_EVENT_TEST="$pr_id == $JID${_EVENT_TEST:+ && ($_EVENT_TEST)}"
69	unset JID
70fi
71EVENT_TEST="cpu == 0"
72CUSTOM_TEST=
73
74_CONF_OTHER=
75IFS=" "
76nconf=0
77for var in $conf; do
78	nconf=$(( $nconf + 1 ))
79	eval val=\"\$$var\"
80	_CONF_OTHER="$_CONF_OTHER || ($val)"
81done
82[ "$_CONF_OTHER" ] && _CONF_OTHER="!(${_CONF_OTHER# || })"
83
84############################################################ ACTIONS
85
86exec 9<<EOF
87this string	event;
88this string	family;
89this string	local;
90this string	remote;
91this u_char	local6;
92this u_char	remote6;
93this uint16_t	lport;
94this uint16_t	rport;
95this uint32_t	length;
96
97uint32_t	tcp_rcvd;
98uint32_t	tcp_sent;
99uint32_t	udp_rcvd;
100uint32_t	udp_sent;
101
102$( IFS=" "
103	for var in $conf; do
104		printf "uint32_t\t%s_tcp_rcvd;\n" $var
105		printf "uint32_t\t%s_tcp_sent;\n" $var
106		printf "uint32_t\t%s_udp_rcvd;\n" $var
107		printf "uint32_t\t%s_udp_sent;\n" $var
108	done
109)
110
111struct socket *	urecv_socket;
112struct inpcb *	urecv_inpcb;
113string		urecv_local;
114string		urecv_remote;
115u_char		urecv_local6;
116u_char		urecv_remote6;
117uint16_t	urecv_lport;
118uint16_t	urecv_rport;
119uint32_t	urecv_length;
120
121BEGIN /* probe ID $ID */
122{${TRACE:+
123	printf("<$ID>");}
124	tcp_rcvd = tcp_sent = 0;
125	udp_rcvd = udp_sent = 0;$( IFS=" "
126	for var in $conf; do
127		printf "\n\t%s_tcp_rcvd = %s_tcp_sent = 0;" $var $var
128		printf "\n\t%s_udp_rcvd = %s_udp_sent = 0;" $var $var
129	done
130)
131}
132
133/****************************** TCP ******************************/
134
135tcp:::send,
136tcp:::receive /* probe ID $(( $ID + 1 )) */
137{${TRACE:+
138	printf("<$(( $ID + 1 ))>");}
139	this->length = (uint32_t)args[2]->ip_plength -
140                (uint8_t)args[4]->tcp_offset;
141}
142
143tcp:::debug-user /* probe ID $(( $ID + 2 )) */
144{${TRACE:+
145	printf("<$(( $ID + 2 ))>");
146}
147	/*
148	 * tcpsinfo_t *
149	 */
150	this->local  = args[0]->tcps_laddr;
151	this->lport  = args[0]->tcps_lport;
152	this->remote = args[0]->tcps_raddr;
153	this->rport  = args[0]->tcps_rport;
154
155	/*
156	 * IPv6 support
157	 */
158	this->local6 = strstr(this->local, ":") != NULL ? 1 : 0;
159	this->remote6 = strstr(this->remote, ":") != NULL ? 1 : 0;
160	this->local = strjoin(strjoin(this->local6 ? "[" : "",
161		this->local), this->local6 ? "]" : "");
162	this->remote = strjoin(strjoin(this->remote6 ? "[" : "",
163		this->remote), this->remote6 ? "]" : "");
164
165	this->family = "tcp";
166	this->event = prureq_string[arg1];
167}
168
169$( IFS=" "
170	id=$(( $ID + 3 ))
171	for var in $conf; do
172		eval val=\"\$$var\"
173		printf "tcp:::debug-user\n"
174		printf "\t/this->event == \"RCVD\""
175		[ "$_EVENT_TEST" ] && printf " && %s" "$_EVENT_TEST"
176		printf " && (%s)/\n" "$val"
177		printf "\t/* probe ID %u */\n" $id
178		printf "{${TRACE:+\n\tprintf(\"<$id>\");}\n"
179		printf "\t%s_tcp_rcvd += this->length;\n" $var
180		printf "\tthis->length = 0;\n"
181		printf "}\n\n"
182		id=$(( $id + 1 ))
183	done
184)
185
186tcp:::debug-user
187	/this->event == "RCVD"${_EVENT_TEST:+ &&
188		$_EVENT_TEST}${_CONF_OTHER:+ &&
189		$_CONF_OTHER}/
190	/* probe ID $(( $ID + 3 + $nconf )) */
191{${TRACE:+
192	printf("<$(( $ID + 3 + $nconf ))>");}
193	tcp_rcvd += this->length;
194	this->length = 0;
195}
196
197$( IFS=" "
198	id=$(( $ID + 4 + $nconf ))
199	for var in $conf; do
200		eval val=\"\$$var\"
201		printf "tcp:::send\n"
202		printf "\t/"
203		[ "$_EVENT_TEST" ] && printf "%s && " "$_EVENT_TEST"
204		printf "(%s)/\n" "$val"
205		printf "\t/* probe ID %u */\n" $id
206		printf "{${TRACE:+\n\tprintf(\"<$id>\");}\n"
207		printf "\t%s_tcp_sent += this->length;\n" $var
208		printf "\tthis->length = 0;\n"
209		printf "}\n\n"
210		id=$(( $id + 1 ))
211	done
212)
213
214tcp:::send /1${_EVENT_TEST:+ && $_EVENT_TEST}${_CONF_OTHER:+ &&
215		$_CONF_OTHER}/ /* probe ID $(( $ID + 4 + $nconf * 2 )) */
216{${TRACE:+
217	printf("<$(( $ID + 4 + $nconf * 2 ))>");}
218	tcp_sent += this->length;
219	this->length = 0;
220}
221
222/****************************** UDP ******************************/
223
224udp:::send /* probe ID $(( $ID + 5 + $nconf * 2 )) */
225{${TRACE:+
226	printf("<$(( $ID + 5 + $nconf * 2 ))");
227}
228	/*
229	 * ipinfo_t *
230	 */
231	this->local  = args[2]->ip_saddr;
232	this->remote = args[2]->ip_daddr;
233
234	/*
235	 * udpinfo_t *
236	 */
237	this->length = (uint16_t)args[4]->udp_length;
238	this->lport  = args[4]->udp_sport;
239	this->rport  = args[4]->udp_dport;
240
241	/*
242	 * IPv6 support
243	 */
244	this->local6 = strstr(this->local, ":") != NULL ? 1 : 0;
245	this->remote6 = strstr(this->remote, ":") != NULL ? 1 : 0;
246	this->local = strjoin(strjoin(this->local6 ? "[" : "",
247		this->local), this->local6 ? "]" : "");
248	this->remote = strjoin(strjoin(this->remote6 ? "[" : "",
249		this->remote), this->remote6 ? "]" : "");
250
251	this->family = "udp";
252	this->event = "SEND";
253}
254
255$( IFS=" "
256	id=$(( $ID + 6 + $nconf * 2 ))
257	for var in $conf; do
258		eval val=\"\$$var\"
259		printf "udp:::send\n"
260		printf "\t/"
261		[ "$_EVENT_TEST" ] && printf "%s && " "$_EVENT_TEST"
262		printf "(%s)/\n" "$val"
263		printf "\t/* probe ID %u */\n" $id
264		printf "{${TRACE:+\n\tprintf(\"<$id>\");}\n"
265		printf "\t%s_udp_sent += this->length;\n" $var
266		printf "\tthis->length = 0;\n"
267		printf "}\n\n"
268		id=$(( $id + 1 ))
269	done
270)
271
272udp:::send /1${_EVENT_TEST:+ && $_EVENT_TEST}${_CONF_OTHER:+ &&
273		$_CONF_OTHER}/ /* probe ID $(( $ID + 6 + $nconf * 3 )) */
274{${TRACE:+
275	printf("<$(( $ID + 6 + $nconf * 3 ))>");}
276	udp_sent += this->length;
277	this->length = 0;
278}
279
280udp:::receive /* probe ID $(( $ID + 7 + $nconf * 3 )) */
281{${TRACE:+
282	printf("<$(( $ID + 7 + $nconf * 3 ))>");
283}
284	/*
285	 * csinfo_t *
286	 */
287	urecv_inpcb = (struct inpcb *)args[1]->cs_cid;
288	urecv_socket = urecv_inpcb->inp_socket;
289
290	/*
291	 * ipinfo_t *
292	 */
293	urecv_local  = args[2]->ip_daddr;
294	urecv_remote = args[2]->ip_saddr;
295
296	/*
297	 * udpinfo_t *
298	 */
299	urecv_length = (uint16_t)args[4]->udp_length;
300	urecv_lport  = args[4]->udp_dport;
301	urecv_rport  = args[4]->udp_sport;
302
303	/*
304	 * IPv6 support
305	 */
306	urecv_local6 = strstr(urecv_local, ":") != NULL ? 1 : 0;
307	urecv_remote6 = strstr(urecv_remote, ":") != NULL ? 1 : 0;
308	urecv_local = strjoin(strjoin(urecv_local6 ? "[" : "",
309		urecv_local), urecv_local6 ? "]" : "");
310	urecv_remote = strjoin(strjoin(urecv_remote6 ? "[" : "",
311		urecv_remote), urecv_remote6 ? "]" : "");
312}
313
314fbt::soreceive_dgram:entry
315	/args[0] == urecv_socket/
316	/* probe ID $(( $ID + 8 + $nconf * 3 )) */
317{${TRACE:+
318	printf("<$(( $ID + 8 + $nconf * 3 ))>");}
319	this->local = urecv_local;
320	this->remote = urecv_remote;
321	this->length = urecv_length;
322	this->lport = urecv_lport;
323	this->rport = urecv_rport;
324	this->local6 = urecv_local6;
325	this->remote6 = urecv_remote6;
326
327	this->family = "udp";
328	this->event = "RCVD";
329}
330
331$( IFS=" "
332	id=$(( $ID + 9 + $nconf * 3 ))
333	for var in $conf; do
334		eval val=\"\$$var\"
335		printf "fbt::soreceive_dgram:entry\n"
336		printf "\t/args[0] == urecv_socket"
337		[ "$_EVENT_TEST" ] && printf " && %s" "$_EVENT_TEST"
338		printf " && (%s)/\n" "$val"
339		printf "\t/* probe ID %u */\n" $id
340		printf "{${TRACE:+\n\tprintf(\"<$id>\");}\n"
341		printf "\t%s_udp_rcvd += this->length;\n" $var
342		printf "\tthis->length = 0;\n"
343		printf "}\n\n"
344		id=$(( $id + 1 ))
345	done
346)
347
348fbt::soreceive_dgram:entry
349	/args[0] == urecv_socket${_EVENT_TEST:+ &&
350		$_EVENT_TEST}${_CONF_OTHER:+ &&
351		$_CONF_OTHER}/
352	/* probe ID $(( $ID + 9 + $nconf * 4 )) */
353{${TRACE:+
354	printf("<$(( $ID + 9 + $nconf * 4 ))>");}
355	udp_rcvd += this->length;
356	this->length = 0;
357}
358EOF
359ACTIONS=$( cat <&9 )
360ID=$(( $ID + 10 + $nconf * 4 ))
361
362############################################################ EVENT TAG
363
364# The EVENT_TAG is run inside the print action after the timestamp has been
365# printed. By default, `UID.GID CMD[PID]: ' of the process is printed.
366
367EVENT_TAG="printf(\"${PROFILE%-raw}: \")"
368
369############################################################ EVENT DETAILS
370
371exec 9<<EOF
372	/*
373	 * Print path details
374	 */
375	printf("{\"report_type\":\"$REPORT_TYPE\",\"hostname\":\"$HOSTNAME\",\"epoch\":%u,\"tcp_rcvd\":%u,\"tcp_sent\":%u,\"udp_rcvd\":%u,\"udp_sent\":%u$( IFS=" "
376			for var in $conf; do
377				printf ",\\\\\"%s_tcp_rcvd\\\\\":%%u" $var
378				printf ",\\\\\"%s_tcp_sent\\\\\":%%u" $var
379				printf ",\\\\\"%s_udp_rcvd\\\\\":%%u" $var
380				printf ",\\\\\"%s_udp_sent\\\\\":%%u" $var
381			done
382		)}",
383		walltimestamp / 1000000000,
384			tcp_rcvd, tcp_sent,
385			udp_rcvd, udp_sent$( IFS=" "
386			for var in $conf; do
387				printf ",\n\t\t\t%s_tcp_rcvd" $var
388				printf ", %s_tcp_sent" $var
389				printf ",\n\t\t\t%s_udp_rcvd" $var
390				printf ", %s_udp_sent" $var
391			done
392		));
393
394	/*
395	 * Reset counters
396	 */
397	tcp_rcvd = tcp_sent = 0;
398	udp_rcvd = udp_sent = 0;
399$( IFS=" "
400	for var in $conf; do
401		printf "\t%s_tcp_rcvd = %s_tcp_sent = 0;\n" $var $var
402		printf "\t%s_udp_rcvd = %s_udp_sent = 0;\n" $var $var
403	done
404)
405EOF
406EVENT_DETAILS=$( cat <&9 )
407
408################################################################################
409# END
410################################################################################
411