1/*
2 * Copyright (c) 2013-2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <sys/errno.h>
30#include <sys/sysctl.h>
31#include <net/content_filter.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <err.h>
35#include <unistd.h>
36#include <string.h>
37
38void
39print_filter_list()
40{
41	size_t total_len, curr_len;
42	void *buffer = NULL;
43	void *ptr;
44	uint32_t line = 0;
45
46	if (sysctlbyname("net.cfil.filter_list", NULL, &total_len, NULL, 0) == -1)
47		err(1, "sysctlbyname(net.cfil.filter_list)");
48
49	buffer = malloc(total_len);
50	if (buffer == NULL)
51		err(1, "malloc()");
52	if (sysctlbyname("net.cfil.filter_list", buffer, &total_len, NULL, 0) == -1)
53		err(1, "sysctlbyname(net.cfil.filter_list)");
54
55	ptr = buffer;
56	curr_len = 0;
57	do {
58		struct cfil_filter_stat *filter_stat;
59
60		filter_stat = (struct cfil_filter_stat *)ptr;
61
62		if (curr_len + filter_stat->cfs_len > total_len ||
63		    filter_stat->cfs_len < sizeof(struct cfil_filter_stat))
64			break;
65
66		if (line % 16 == 0)
67			printf("%10s %10s %10s %10s\n",
68			       "filter", "flags", "count", "necpunit");
69
70		printf("%10u 0x%08x %10u %10u\n",
71		       filter_stat->cfs_filter_id,
72		       filter_stat->cfs_flags,
73		       filter_stat->cfs_sock_count,
74		       filter_stat->cfs_necp_control_unit);
75
76		ptr += filter_stat->cfs_len;
77		curr_len += filter_stat->cfs_len;
78	} while (1);
79
80	free(buffer);
81}
82
83void
84sprint_offset(char *str, size_t len, const char *fmt, uint64_t offset)
85{
86	if (offset == CFM_MAX_OFFSET)
87		snprintf(str, len, "%s", "MAX");
88	else
89		snprintf(str, len, fmt, offset);
90}
91
92void
93print_socket_list()
94{
95	size_t total_len, curr_len;
96	void *buffer = NULL;
97	void *ptr;
98	int i;
99
100	if (sysctlbyname("net.cfil.sock_list", NULL, &total_len, NULL, 0) == -1)
101		err(1, "sysctlbyname(net.cfil.sock_list)");
102
103	buffer = malloc(total_len);
104	if (buffer == NULL)
105		err(1, "malloc()");
106	if (sysctlbyname("net.cfil.sock_list", buffer, &total_len, NULL, 0) == -1)
107		err(1, "sysctlbyname(net.cfil.sock_list)");
108
109	ptr = buffer;
110	curr_len = 0;
111	do {
112		struct cfil_sock_stat *sock_stat;
113		char opass[32];
114		char ipass[32];
115
116		sock_stat = (struct cfil_sock_stat *)ptr;
117
118		if (curr_len + sock_stat->cfs_len > total_len ||
119		    sock_stat->cfs_len < sizeof(struct cfil_sock_stat))
120			break;
121
122		sprint_offset(opass, 32, "%8llu", sock_stat->cfs_snd.cbs_pass_offset);
123		sprint_offset(ipass, 32, "%8llu", sock_stat->cfs_rcv.cbs_pass_offset);
124
125		printf("%18s %10s "
126		       "%8s %8s %8s %8s %8s %8s %8s "
127		       "%8s %8s %8s %8s %8s %8s %8s "
128		       "%8s %8s\n",
129		       "sockid", "flags",
130		       "ofirst", "olast", "oqlen", " ", "opass", " ", " ",
131		       "ifirst", "ilast", "iqlen", " ", "ipass", " ", " ",
132		       "pid", "epid");
133
134		printf("0x%016llx 0x%08llx "
135		       "%8llu %8llu %8llu %8s %8s %8s %8s "
136		       "%8llu %8llu %8llu %8s %8s %8s %8s "
137		       "%8u %8u\n",
138
139		       sock_stat->cfs_sock_id,
140		       sock_stat->cfs_flags,
141
142		       sock_stat->cfs_snd.cbs_pending_first,
143		       sock_stat->cfs_snd.cbs_pending_last,
144		       sock_stat->cfs_snd.cbs_inject_q_len,
145		       " ",
146		       opass,
147		       " ",
148		       " ",
149
150		       sock_stat->cfs_rcv.cbs_pending_first,
151		       sock_stat->cfs_rcv.cbs_pending_last,
152		       sock_stat->cfs_rcv.cbs_inject_q_len,
153		       " ",
154		       ipass,
155		       " ",
156		       " ",
157		       sock_stat->cfs_pid,
158		       sock_stat->cfs_e_pid);
159
160		printf("%7s %10s %10s "
161		       "%8s %8s %8s %8s %8s %8s %8s "
162		       "%8s %8s %8s %8s %8s %8s %8s\n",
163		       " ",
164		       "filter", "flags",
165		       "octlfrst", "octllast", "opndfrst", "opndlast", "opass", "opked", "opeek",
166		       "ictlfrst", "ictllast", "ipndfrst", "ipndlast", "ipass", "ipked", "ipeek");
167		for (i = 0; i < CFIL_MAX_FILTER_COUNT; i++) {
168			struct cfil_entry_stat *estat;
169			char spass[32];
170			char speek[32];
171			char spked[32];
172			char rpass[32];
173			char rpeek[32];
174			char rpked[32];
175
176			estat = &sock_stat->ces_entries[i];
177
178			sprint_offset(spass, 32, "%8llu", estat->ces_snd.cbs_pass_offset);
179			sprint_offset(speek, 32, "%8llu", estat->ces_snd.cbs_peek_offset);
180			sprint_offset(spked, 32, "%8llu", estat->ces_snd.cbs_peeked);
181
182			sprint_offset(rpass, 32, "%8llu", estat->ces_rcv.cbs_pass_offset);
183			sprint_offset(rpeek, 32, "%8llu", estat->ces_rcv.cbs_peek_offset);
184			sprint_offset(rpked, 32, "%8llu", estat->ces_rcv.cbs_peeked);
185
186			printf("%7s %10u 0x%08x "
187			       "%8llu %8llu %8llu %8llu %8s %8s %8s "
188			       "%8llu %8llu %8llu %8llu %8s %8s %8s\n",
189
190			       " ",
191			       estat->ces_filter_id,
192			       estat->ces_flags,
193
194			       estat->ces_snd.cbs_ctl_first,
195			       estat->ces_snd.cbs_ctl_last,
196			       estat->ces_snd.cbs_pending_first,
197			       estat->ces_snd.cbs_pending_last,
198			       spass,
199			       spked,
200			       speek,
201
202			       estat->ces_rcv.cbs_ctl_first,
203			       estat->ces_rcv.cbs_ctl_last,
204			       estat->ces_rcv.cbs_pending_first,
205			       estat->ces_rcv.cbs_pending_last,
206			       rpass,
207			       rpked,
208			       rpeek);
209		}
210
211
212		ptr += sock_stat->cfs_len;
213		curr_len += sock_stat->cfs_len;
214	} while (1);
215
216	free(buffer);
217}
218
219
220#define PR32(x) printf(#x " %u\n", stats-> x)
221#define PR64(x) printf(#x " %llu\n", stats-> x)
222void
223print_cfil_stats()
224{
225	size_t len, alloc_len;
226	void *buffer = NULL;
227	struct cfil_stats *stats;
228
229	if (sysctlbyname("net.cfil.stats", NULL, &len, NULL, 0) == -1)
230		err(1, "sysctlbyname(net.cfil.stats)");
231
232	if (len < sizeof(struct cfil_stats))
233		alloc_len = sizeof(struct cfil_stats);
234	else
235		alloc_len = len;
236
237	buffer = malloc(alloc_len);
238	if (buffer == NULL)
239		err(1, "malloc()");
240	if (sysctlbyname("net.cfil.stats", buffer, &len, NULL, 0) == -1)
241		err(1, "sysctlbyname(net.cfil.stats)");
242	stats = (struct cfil_stats *)buffer;
243
244	PR32(cfs_ctl_connect_ok);
245	PR32(cfs_ctl_connect_fail);
246	PR32(cfs_ctl_connect_ok);
247	PR32(cfs_ctl_connect_fail);
248	PR32(cfs_ctl_disconnect_ok);
249	PR32(cfs_ctl_disconnect_fail);
250	PR32(cfs_ctl_send_ok);
251	PR32(cfs_ctl_send_bad);
252	PR32(cfs_ctl_rcvd_ok);
253	PR32(cfs_ctl_rcvd_bad);
254	PR32(cfs_ctl_rcvd_flow_lift);
255	PR32(cfs_ctl_action_data_update);
256	PR32(cfs_ctl_action_drop);
257	PR32(cfs_ctl_action_bad_op);
258	PR32(cfs_ctl_action_bad_len);
259
260	PR32(cfs_sock_id_not_found);
261
262	PR32(cfs_cfi_alloc_ok);
263	PR32(cfs_cfi_alloc_fail);
264
265	PR32(cfs_sock_userspace_only);
266	PR32(cfs_sock_attach_in_vain);
267	PR32(cfs_sock_attach_already);
268	PR32(cfs_sock_attach_no_mem);
269	PR32(cfs_sock_attach_failed);
270	PR32(cfs_sock_attached);
271	PR32(cfs_sock_detached);
272
273	PR32(cfs_attach_event_ok);
274	PR32(cfs_attach_event_flow_control);
275	PR32(cfs_attach_event_fail);
276
277	PR32(cfs_closed_event_ok);
278	PR32(cfs_closed_event_flow_control);
279	PR32(cfs_closed_event_fail);
280
281	PR32(cfs_data_event_ok);
282	PR32(cfs_data_event_flow_control);
283	PR32(cfs_data_event_fail);
284
285	PR32(cfs_disconnect_in_event_ok);
286	PR32(cfs_disconnect_out_event_ok);
287	PR32(cfs_disconnect_event_flow_control);
288	PR32(cfs_disconnect_event_fail);
289
290	PR32(cfs_ctl_q_not_started);
291
292	PR32(cfs_close_wait);
293	PR32(cfs_close_wait_timeout);
294
295	PR32(cfs_flush_in_drop);
296	PR32(cfs_flush_out_drop);
297	PR32(cfs_flush_in_close);
298	PR32(cfs_flush_out_close);
299	PR32(cfs_flush_in_free);
300	PR32(cfs_flush_out_free);
301
302	PR32(cfs_inject_q_nomem);
303	PR32(cfs_inject_q_nobufs);
304	PR32(cfs_inject_q_detached);
305	PR32(cfs_inject_q_in_fail);
306	PR32(cfs_inject_q_out_fail);
307
308	PR32(cfs_inject_q_in_retry);
309	PR32(cfs_inject_q_out_retry);
310
311	PR32(cfs_data_in_control);
312	PR32(cfs_data_in_oob);
313	PR32(cfs_data_out_control);
314	PR32(cfs_data_out_oob);
315
316	PR64(cfs_ctl_q_in_enqueued);
317	PR64(cfs_ctl_q_out_enqueued);
318	PR64(cfs_ctl_q_in_peeked);
319	PR64(cfs_ctl_q_out_peeked);
320
321	PR64(cfs_pending_q_in_enqueued);
322	PR64(cfs_pending_q_out_enqueued);
323
324	PR64(cfs_inject_q_in_enqueued);
325	PR64(cfs_inject_q_out_enqueued);
326	PR64(cfs_inject_q_in_passed);
327	PR64(cfs_inject_q_out_passed);
328}
329