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