1/*
2 * Copyright (c) 2013-2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#ifndef __CONTENT_FILTER_H__
25#define	__CONTENT_FILTER_H__
26
27#include <sys/param.h>
28#include <sys/types.h>
29#include <sys/socket.h>
30#include <sys/syslog.h>
31#include <netinet/in.h>
32#include <stdint.h>
33
34#ifdef BSD_KERNEL_PRIVATE
35#include <sys/mbuf.h>
36#include <sys/socketvar.h>
37#endif /* BSD_KERNEL_PRIVATE */
38
39__BEGIN_DECLS
40
41#ifdef PRIVATE
42
43/*
44 * Kernel control name for an instance of a Content Filter
45 * Use CTLIOCGINFO to find out the corresponding kernel control id
46 * to be set in the sc_id field of sockaddr_ctl for connect(2)
47 * Note: the sc_unit is ephemeral
48 */
49#define	CONTENT_FILTER_CONTROL_NAME "com.apple.content-filter"
50
51/*
52 * CFIL_OPT_NECP_CONTROL_UNIT
53 * To set or get the NECP filter control unit for the kernel control socket
54 * The option level is SYSPROTO_CONTROL
55 */
56#define	CFIL_OPT_NECP_CONTROL_UNIT	1	/* uint32_t */
57
58/*
59 * How many filter may be active simultaneously
60 */
61#define	CFIL_MAX_FILTER_COUNT	2
62
63/*
64 * Types of messages
65 *
66 * Event messages flow from kernel to user space while action
67 * messages flow in the reverse direction.
68 * A message in entirely represented by a packet sent or received
69 * on a Content Filter kernel control socket.
70 */
71#define	CFM_TYPE_EVENT 1	/* message from kernel */
72#define	CFM_TYPE_ACTION 2	/* message to kernel */
73
74/*
75 * Operations associated with events from kernel
76 */
77#define	CFM_OP_SOCKET_ATTACHED 1	/* a socket has been attached */
78#define	CFM_OP_SOCKET_CLOSED 2		/* a socket is being closed */
79#define	CFM_OP_DATA_OUT 3		/* data being sent */
80#define	CFM_OP_DATA_IN 4		/* data being received */
81#define	CFM_OP_DISCONNECT_OUT 5		/* no more outgoing data */
82#define	CFM_OP_DISCONNECT_IN 6		/* no more incoming data */
83
84/*
85 * Operations associated with action from filter to kernel
86 */
87#define	CFM_OP_DATA_UPDATE 16		/* update pass or peek offsets */
88#define	CFM_OP_DROP 17			/* shutdown socket, no more data */
89
90/*
91 * Opaque socket identifier
92 */
93typedef uint64_t cfil_sock_id_t;
94
95#define	CFIL_SOCK_ID_NONE UINT64_MAX
96
97/*
98 * Invariant timeval structure definition across architectures
99 */
100struct timeval64 {
101	int64_t tv_sec;
102	int64_t tv_usec;
103};
104
105/*
106 * struct cfil_msg_hdr
107 *
108 * Header common to all messages
109 */
110struct cfil_msg_hdr {
111	uint32_t	cfm_len;	/* total length */
112	uint32_t	cfm_version;
113	uint32_t	cfm_type;
114	uint32_t	cfm_op;
115	cfil_sock_id_t	cfm_sock_id;
116};
117
118#define	CFM_VERSION_CURRENT 1
119
120/*
121 * struct cfil_msg_sock_attached
122 *
123 * Information about a new socket being attached to the content filter
124 *
125 * Action: No reply is expected as this does not block the creation of the
126 * TCP/IP but timely action must be taken to avoid user noticeable delays.
127 *
128 * Valid Types: CFM_TYPE_EVENT
129 *
130 * Valid Op: CFM_OP_SOCKET_ATTACHED
131 */
132struct cfil_msg_sock_attached {
133	struct cfil_msg_hdr	cfs_msghdr;
134	int			cfs_sock_family;	/* e.g. PF_INET */
135	int			cfs_sock_type;		/* e.g. SOCK_STREAM */
136	int			cfs_sock_protocol;	/* e.g. IPPROTO_TCP */
137	int			cfs_unused;		/* padding */
138	pid_t			cfs_pid;
139	pid_t			cfs_e_pid;
140	uuid_t			cfs_uuid;
141	uuid_t			cfs_e_uuid;
142};
143
144/*
145 * struct cfil_msg_data_event
146 *
147 * Event for the content fiter to act on a span of data
148 * A data span is described by a pair of offsets over the cumulative
149 * number of bytes sent or received on the socket.
150 *
151 * Action: The event must be acted upon but the filter may buffer
152 * data spans until it has enough content to make a decision.
153 * The action must be timely to avoid user noticeable delays.
154 *
155 * Valid Type: CFM_TYPE_EVENT
156 *
157 * Valid Ops: CFM_OP_DATA_OUT, CFM_OP_DATA_IN
158 */
159struct cfil_msg_data_event {
160	struct cfil_msg_hdr	cfd_msghdr;
161	union sockaddr_in_4_6	cfc_src;
162	union sockaddr_in_4_6	cfc_dst;
163	uint64_t		cfd_start_offset;
164	uint64_t		cfd_end_offset;
165	/* Actual content data immediatly follows */
166};
167
168/*
169 * struct cfil_msg_action
170 *
171 * Valid Type: CFM_TYPE_ACTION
172 *
173 * Valid Ops: CFM_OP_DATA_UPDATE, CFM_OP_DROP
174 *
175 * For CFM_OP_DATA_UPDATE:
176 *
177 * cfa_in_pass_offset and cfa_out_pass_offset indicates how much data is
178 * allowed to pass. A zero value does not modify the corresponding pass offset.
179 *
180 * cfa_in_peek_offset and cfa_out_peek_offset lets the filter specify how much
181 * data it needs to make a decision: the kernel will deliver data up to that
182 * offset (if less than cfa_pass_offset it is ignored). Use CFM_MAX_OFFSET
183 * if you don't value the corresponding peek offset to be updated.
184 */
185struct cfil_msg_action {
186	struct cfil_msg_hdr	cfa_msghdr;
187	uint64_t		cfa_in_pass_offset;
188	uint64_t		cfa_in_peek_offset;
189	uint64_t		cfa_out_pass_offset;
190	uint64_t		cfa_out_peek_offset;
191};
192
193#define	CFM_MAX_OFFSET	UINT64_MAX
194
195/*
196 * Statistics retrieved via sysctl(3)
197 */
198struct cfil_filter_stat {
199	uint32_t	cfs_len;
200	uint32_t	cfs_filter_id;
201	uint32_t	cfs_flags;
202	uint32_t	cfs_sock_count;
203	uint32_t	cfs_necp_control_unit;
204};
205
206struct cfil_entry_stat {
207	uint32_t		ces_len;
208	uint32_t		ces_filter_id;
209	uint32_t		ces_flags;
210	uint32_t		ces_necp_control_unit;
211	struct timeval64	ces_last_event;
212	struct timeval64	ces_last_action;
213	struct cfe_buf_stat {
214		uint64_t	cbs_pending_first;
215		uint64_t	cbs_pending_last;
216		uint64_t	cbs_ctl_first;
217		uint64_t	cbs_ctl_last;
218		uint64_t	cbs_pass_offset;
219		uint64_t	cbs_peek_offset;
220		uint64_t	cbs_peeked;
221	} ces_snd, ces_rcv;
222};
223
224struct cfil_sock_stat {
225	uint32_t	cfs_len;
226	int		cfs_sock_family;
227	int		cfs_sock_type;
228	int		cfs_sock_protocol;
229	cfil_sock_id_t	cfs_sock_id;
230	uint64_t	cfs_flags;
231	pid_t		cfs_pid;
232	pid_t		cfs_e_pid;
233	uuid_t		cfs_uuid;
234	uuid_t		cfs_e_uuid;
235	struct cfi_buf_stat {
236		uint64_t	cbs_pending_first;
237		uint64_t	cbs_pending_last;
238		uint64_t	cbs_pass_offset;
239		uint64_t	cbs_inject_q_len;
240	} cfs_snd, cfs_rcv;
241	struct cfil_entry_stat	ces_entries[CFIL_MAX_FILTER_COUNT];
242};
243
244/*
245 * Global statistics
246 */
247struct cfil_stats {
248	int32_t	cfs_ctl_connect_ok;
249	int32_t	cfs_ctl_connect_fail;
250	int32_t	cfs_ctl_disconnect_ok;
251	int32_t	cfs_ctl_disconnect_fail;
252	int32_t	cfs_ctl_send_ok;
253	int32_t	cfs_ctl_send_bad;
254	int32_t	cfs_ctl_rcvd_ok;
255	int32_t	cfs_ctl_rcvd_bad;
256	int32_t	cfs_ctl_rcvd_flow_lift;
257	int32_t	cfs_ctl_action_data_update;
258	int32_t	cfs_ctl_action_drop;
259	int32_t	cfs_ctl_action_bad_op;
260	int32_t	cfs_ctl_action_bad_len;
261
262	int32_t	cfs_sock_id_not_found;
263
264	int32_t	cfs_cfi_alloc_ok;
265	int32_t	cfs_cfi_alloc_fail;
266
267	int32_t	cfs_sock_userspace_only;
268	int32_t	cfs_sock_attach_in_vain;
269	int32_t	cfs_sock_attach_already;
270	int32_t	cfs_sock_attach_no_mem;
271	int32_t	cfs_sock_attach_failed;
272	int32_t	cfs_sock_attached;
273	int32_t	cfs_sock_detached;
274
275	int32_t	cfs_attach_event_ok;
276	int32_t	cfs_attach_event_flow_control;
277	int32_t	cfs_attach_event_fail;
278
279	int32_t	cfs_closed_event_ok;
280	int32_t	cfs_closed_event_flow_control;
281	int32_t	cfs_closed_event_fail;
282
283	int32_t	cfs_data_event_ok;
284	int32_t	cfs_data_event_flow_control;
285	int32_t	cfs_data_event_fail;
286
287	int32_t	cfs_disconnect_in_event_ok;
288	int32_t	cfs_disconnect_out_event_ok;
289	int32_t	cfs_disconnect_event_flow_control;
290	int32_t	cfs_disconnect_event_fail;
291
292	int32_t	cfs_ctl_q_not_started;
293
294	int32_t cfs_close_wait;
295	int32_t cfs_close_wait_timeout;
296
297	int32_t cfs_flush_in_drop;
298	int32_t cfs_flush_out_drop;
299	int32_t cfs_flush_in_close;
300	int32_t cfs_flush_out_close;
301	int32_t cfs_flush_in_free;
302	int32_t cfs_flush_out_free;
303
304	int32_t	cfs_inject_q_nomem;
305	int32_t	cfs_inject_q_nobufs;
306	int32_t	cfs_inject_q_detached;
307	int32_t	cfs_inject_q_in_fail;
308	int32_t	cfs_inject_q_out_fail;
309
310	int32_t	cfs_inject_q_in_retry;
311	int32_t	cfs_inject_q_out_retry;
312
313	int32_t cfs_data_in_control;
314	int32_t cfs_data_in_oob;
315	int32_t cfs_data_out_control;
316	int32_t cfs_data_out_oob;
317
318	int64_t	cfs_ctl_q_in_enqueued __attribute__((aligned(8)));
319	int64_t	cfs_ctl_q_out_enqueued __attribute__((aligned(8)));
320	int64_t	cfs_ctl_q_in_peeked __attribute__((aligned(8)));
321	int64_t	cfs_ctl_q_out_peeked __attribute__((aligned(8)));
322
323	int64_t	cfs_pending_q_in_enqueued __attribute__((aligned(8)));
324	int64_t	cfs_pending_q_out_enqueued __attribute__((aligned(8)));
325
326	int64_t	cfs_inject_q_in_enqueued __attribute__((aligned(8)));
327	int64_t	cfs_inject_q_out_enqueued __attribute__((aligned(8)));
328	int64_t	cfs_inject_q_in_passed __attribute__((aligned(8)));
329	int64_t	cfs_inject_q_out_passed __attribute__((aligned(8)));
330
331};
332#endif /* PRIVATE */
333
334#ifdef BSD_KERNEL_PRIVATE
335
336#define	M_SKIPCFIL	M_PROTO5
337
338extern int cfil_log_level;
339
340#define	CFIL_LOG(level, fmt, ...) \
341do { \
342	if (cfil_log_level >= level) \
343		printf("%s:%d " fmt "\n",\
344			__FUNCTION__, __LINE__, ##__VA_ARGS__); \
345} while (0)
346
347
348extern void cfil_init(void);
349
350extern errno_t cfil_sock_attach(struct socket *so);
351extern errno_t cfil_sock_detach(struct socket *so);
352
353extern int cfil_sock_data_out(struct socket *so, struct sockaddr  *to,
354			struct mbuf *data, struct mbuf *control,
355			uint32_t flags);
356extern int cfil_sock_data_in(struct socket *so, struct sockaddr *from,
357			struct mbuf *data, struct mbuf *control,
358			uint32_t flags);
359
360extern int cfil_sock_shutdown(struct socket *so, int *how);
361extern void cfil_sock_is_closed(struct socket *so);
362extern void cfil_sock_notify_shutdown(struct socket *so, int how);
363extern void cfil_sock_close_wait(struct socket *so);
364
365extern boolean_t cfil_sock_data_pending(struct sockbuf *sb);
366extern int cfil_sock_data_space(struct sockbuf *sb);
367extern void cfil_sock_buf_update(struct sockbuf *sb);
368
369extern cfil_sock_id_t cfil_sock_id_from_socket(struct socket *so);
370
371__END_DECLS
372
373#endif /* BSD_KERNEL_PRIVATE */
374
375#endif /* __CONTENT_FILTER_H__ */
376