2 * Copyright (c) 2013-2014 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 #ifndef __CONTENT_FILTER_H__
25 #define __CONTENT_FILTER_H__
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>
34 #ifdef BSD_KERNEL_PRIVATE
36 #include <sys/socketvar.h>
37 #endif /* BSD_KERNEL_PRIVATE */
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
49 #define CONTENT_FILTER_CONTROL_NAME "com.apple.content-filter"
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
56 #define CFIL_OPT_NECP_CONTROL_UNIT 1 /* uint32_t */
59 * How many filter may be active simultaneously
61 #define CFIL_MAX_FILTER_COUNT 2
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.
71 #define CFM_TYPE_EVENT 1 /* message from kernel */
72 #define CFM_TYPE_ACTION 2 /* message to kernel */
75 * Operations associated with events from kernel
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 */
85 * Operations associated with action from filter to kernel
87 #define CFM_OP_DATA_UPDATE 16 /* update pass or peek offsets */
88 #define CFM_OP_DROP 17 /* shutdown socket, no more data */
91 * Opaque socket identifier
93 typedef uint64_t cfil_sock_id_t
;
95 #define CFIL_SOCK_ID_NONE UINT64_MAX
98 * Invariant timeval structure definition across architectures
106 * struct cfil_msg_hdr
108 * Header common to all messages
110 struct cfil_msg_hdr
{
111 uint32_t cfm_len
; /* total length */
112 uint32_t cfm_version
;
115 cfil_sock_id_t cfm_sock_id
;
118 #define CFM_VERSION_CURRENT 1
121 * struct cfil_msg_sock_attached
123 * Information about a new socket being attached to the content filter
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.
128 * Valid Types: CFM_TYPE_EVENT
130 * Valid Op: CFM_OP_SOCKET_ATTACHED
132 struct 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 */
145 * struct cfil_msg_data_event
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.
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.
155 * Valid Type: CFM_TYPE_EVENT
157 * Valid Ops: CFM_OP_DATA_OUT, CFM_OP_DATA_IN
159 struct 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 */
169 * struct cfil_msg_action
171 * Valid Type: CFM_TYPE_ACTION
173 * Valid Ops: CFM_OP_DATA_UPDATE, CFM_OP_DROP
175 * For CFM_OP_DATA_UPDATE:
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.
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.
185 struct 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
;
193 #define CFM_MAX_OFFSET UINT64_MAX
196 * Statistics retrieved via sysctl(3)
198 struct cfil_filter_stat
{
200 uint32_t cfs_filter_id
;
202 uint32_t cfs_sock_count
;
203 uint32_t cfs_necp_control_unit
;
206 struct cfil_entry_stat
{
208 uint32_t ces_filter_id
;
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
;
224 struct cfil_sock_stat
{
228 int cfs_sock_protocol
;
229 cfil_sock_id_t cfs_sock_id
;
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
;
241 struct cfil_entry_stat ces_entries
[CFIL_MAX_FILTER_COUNT
];
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
;
262 int32_t cfs_sock_id_not_found
;
264 int32_t cfs_cfi_alloc_ok
;
265 int32_t cfs_cfi_alloc_fail
;
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
;
275 int32_t cfs_attach_event_ok
;
276 int32_t cfs_attach_event_flow_control
;
277 int32_t cfs_attach_event_fail
;
279 int32_t cfs_closed_event_ok
;
280 int32_t cfs_closed_event_flow_control
;
281 int32_t cfs_closed_event_fail
;
283 int32_t cfs_data_event_ok
;
284 int32_t cfs_data_event_flow_control
;
285 int32_t cfs_data_event_fail
;
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
;
292 int32_t cfs_ctl_q_not_started
;
294 int32_t cfs_close_wait
;
295 int32_t cfs_close_wait_timeout
;
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
;
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
;
310 int32_t cfs_inject_q_in_retry
;
311 int32_t cfs_inject_q_out_retry
;
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
;
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)));
323 int64_t cfs_pending_q_in_enqueued
__attribute__((aligned(8)));
324 int64_t cfs_pending_q_out_enqueued
__attribute__((aligned(8)));
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)));
334 #ifdef BSD_KERNEL_PRIVATE
336 #define M_SKIPCFIL M_PROTO5
338 extern int cfil_log_level
;
340 #define CFIL_LOG(level, fmt, ...) \
342 if (cfil_log_level >= level) \
343 printf("%s:%d " fmt "\n",\
344 __FUNCTION__, __LINE__, ##__VA_ARGS__); \
348 extern void cfil_init(void);
350 extern errno_t
cfil_sock_attach(struct socket
*so
);
351 extern errno_t
cfil_sock_detach(struct socket
*so
);
353 extern int cfil_sock_data_out(struct socket
*so
, struct sockaddr
*to
,
354 struct mbuf
*data
, struct mbuf
*control
,
356 extern int cfil_sock_data_in(struct socket
*so
, struct sockaddr
*from
,
357 struct mbuf
*data
, struct mbuf
*control
,
360 extern int cfil_sock_shutdown(struct socket
*so
, int *how
);
361 extern void cfil_sock_is_closed(struct socket
*so
);
362 extern void cfil_sock_notify_shutdown(struct socket
*so
, int how
);
363 extern void cfil_sock_close_wait(struct socket
*so
);
365 extern boolean_t
cfil_sock_data_pending(struct sockbuf
*sb
);
366 extern int cfil_sock_data_space(struct sockbuf
*sb
);
367 extern void cfil_sock_buf_update(struct sockbuf
*sb
);
369 extern cfil_sock_id_t
cfil_sock_id_from_socket(struct socket
*so
);
373 #endif /* BSD_KERNEL_PRIVATE */
375 #endif /* __CONTENT_FILTER_H__ */