2 * Copyright (c) 2013-2019 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/_types/_timeval64.h>
30 #include <sys/socket.h>
31 #include <sys/syslog.h>
32 #include <netinet/in.h>
34 #include <corecrypto/ccsha2.h>
36 #ifdef BSD_KERNEL_PRIVATE
38 #include <sys/socketvar.h>
39 #endif /* BSD_KERNEL_PRIVATE */
46 * Kernel control name for an instance of a Content Filter
47 * Use CTLIOCGINFO to find out the corresponding kernel control id
48 * to be set in the sc_id field of sockaddr_ctl for connect(2)
49 * Note: the sc_unit is ephemeral
51 #define CONTENT_FILTER_CONTROL_NAME "com.apple.content-filter"
54 * Opaque socket identifier
56 typedef uint64_t cfil_sock_id_t
;
58 #define CFIL_SOCK_ID_NONE UINT64_MAX
62 * CFIL_OPT_NECP_CONTROL_UNIT
63 * To set or get the NECP filter control unit for the kernel control socket
64 * The option level is SYSPROTO_CONTROL
66 #define CFIL_OPT_NECP_CONTROL_UNIT 1 /* uint32_t */
69 * CFIL_OPT_GET_SOCKET_INFO
70 * To get information about a given socket that is being filtered.
72 #define CFIL_OPT_GET_SOCKET_INFO 2 /* uint32_t */
75 * struct cfil_opt_sock_info
77 * Contains information about a socket that is being filtered.
79 struct cfil_opt_sock_info
{
80 cfil_sock_id_t cfs_sock_id
;
81 int cfs_sock_family
; /* e.g. PF_INET */
82 int cfs_sock_type
; /* e.g. SOCK_STREAM */
83 int cfs_sock_protocol
; /* e.g. IPPROTO_TCP */
84 union sockaddr_in_4_6 cfs_local
;
85 union sockaddr_in_4_6 cfs_remote
;
93 * How many filter may be active simultaneously
95 #if !TARGET_OS_OSX && !defined(XNU_TARGET_OS_OSX)
96 #define CFIL_MAX_FILTER_COUNT 2
98 #define CFIL_MAX_FILTER_COUNT 8
105 #define CFIL_CRYPTO 1
106 #define CFIL_CRYPTO_SIGNATURE_SIZE 32
107 #define CFIL_CRYPTO_DATA_EVENT 1
109 typedef uint8_t cfil_crypto_key
[CCSHA256_OUTPUT_SIZE
];
110 typedef uint8_t cfil_crypto_signature
[CFIL_CRYPTO_SIGNATURE_SIZE
];
112 typedef struct cfil_crypto_state
{
113 const struct ccdigest_info
*digest_info
;
115 } *cfil_crypto_state_t
;
117 typedef struct cfil_crypto_data
{
121 union sockaddr_in_4_6 remote
;
122 union sockaddr_in_4_6 local
;
123 u_int32_t socketProtocol
;
127 uuid_t effective_uuid
;
128 u_int64_t byte_count_in
;
129 u_int64_t byte_count_out
;
130 } *cfil_crypto_data_t
;
135 * Event messages flow from kernel to user space while action
136 * messages flow in the reverse direction.
137 * A message in entirely represented by a packet sent or received
138 * on a Content Filter kernel control socket.
140 #define CFM_TYPE_EVENT 1 /* message from kernel */
141 #define CFM_TYPE_ACTION 2 /* message to kernel */
144 * Operations associated with events from kernel
146 #define CFM_OP_SOCKET_ATTACHED 1 /* a socket has been attached */
147 #define CFM_OP_SOCKET_CLOSED 2 /* a socket is being closed */
148 #define CFM_OP_DATA_OUT 3 /* data being sent */
149 #define CFM_OP_DATA_IN 4 /* data being received */
150 #define CFM_OP_DISCONNECT_OUT 5 /* no more outgoing data */
151 #define CFM_OP_DISCONNECT_IN 6 /* no more incoming data */
152 #define CFM_OP_STATS 7 /* periodic stats report(s) */
155 * Operations associated with action from filter to kernel
157 #define CFM_OP_DATA_UPDATE 16 /* update pass or peek offsets */
158 #define CFM_OP_DROP 17 /* shutdown socket, no more data */
159 #define CFM_OP_BLESS_CLIENT 18 /* mark a client flow as already filtered, passes a uuid */
160 #define CFM_OP_SET_CRYPTO_KEY 19 /* assign client crypto key for message signing */
163 * struct cfil_msg_hdr
165 * Header common to all messages
167 struct cfil_msg_hdr
{
168 uint32_t cfm_len
; /* total length */
169 uint32_t cfm_version
;
172 cfil_sock_id_t cfm_sock_id
;
175 #define CFM_VERSION_CURRENT 1
178 * Connection Direction
180 #define CFS_CONNECTION_DIR_IN 0
181 #define CFS_CONNECTION_DIR_OUT 1
183 #define CFS_AUDIT_TOKEN 1
186 * struct cfil_msg_sock_attached
188 * Information about a new socket being attached to the content filter
190 * Action: No reply is expected as this does not block the creation of the
191 * TCP/IP but timely action must be taken to avoid user noticeable delays.
193 * Valid Types: CFM_TYPE_EVENT
195 * Valid Op: CFM_OP_SOCKET_ATTACHED
197 struct cfil_msg_sock_attached
{
198 struct cfil_msg_hdr cfs_msghdr
;
199 int cfs_sock_family
; /* e.g. PF_INET */
200 int cfs_sock_type
; /* e.g. SOCK_STREAM */
201 int cfs_sock_protocol
; /* e.g. IPPROTO_TCP */
202 int cfs_unused
; /* padding */
207 union sockaddr_in_4_6 cfs_src
;
208 union sockaddr_in_4_6 cfs_dst
;
210 unsigned int cfs_audit_token
[8]; /* Must match audit_token_t */
211 cfil_crypto_signature cfs_signature
;
212 uint32_t cfs_signature_length
;
218 #define CFD_DATA_FLAG_IP_HEADER 0x00000001 /* Data includes IP header */
221 * struct cfil_msg_data_event
223 * Event for the content fiter to act on a span of data
224 * A data span is described by a pair of offsets over the cumulative
225 * number of bytes sent or received on the socket.
227 * Action: The event must be acted upon but the filter may buffer
228 * data spans until it has enough content to make a decision.
229 * The action must be timely to avoid user noticeable delays.
231 * Valid Type: CFM_TYPE_EVENT
233 * Valid Ops: CFM_OP_DATA_OUT, CFM_OP_DATA_IN
235 struct cfil_msg_data_event
{
236 struct cfil_msg_hdr cfd_msghdr
;
237 union sockaddr_in_4_6 cfc_src
;
238 union sockaddr_in_4_6 cfc_dst
;
239 uint64_t cfd_start_offset
;
240 uint64_t cfd_end_offset
;
241 cfil_crypto_signature cfd_signature
;
242 uint32_t cfd_signature_length
;
244 /* Actual content data immediatly follows */
247 #define CFI_MAX_TIME_LOG_ENTRY 6
249 * struct cfil_msg_sock_closed
251 * Information about a socket being closed to the content filter
253 * Action: No reply is expected as this does not block the closing of the
256 * Valid Types: CFM_TYPE_EVENT
258 * Valid Op: CFM_OP_SOCKET_CLOSED
260 struct cfil_msg_sock_closed
{
261 struct cfil_msg_hdr cfc_msghdr
;
262 struct timeval64 cfc_first_event
;
263 uint32_t cfc_op_list_ctr
;
264 uint32_t cfc_op_time
[CFI_MAX_TIME_LOG_ENTRY
]; /* time interval in microseconds since first event */
265 unsigned char cfc_op_list
[CFI_MAX_TIME_LOG_ENTRY
];
266 uint64_t cfc_byte_inbound_count
;
267 uint64_t cfc_byte_outbound_count
;
268 cfil_crypto_signature cfc_signature
;
269 uint32_t cfc_signature_length
;
270 } __attribute__((aligned(8)));
273 * struct cfil_msg_stats_report
275 * Statistics report for flow(s).
277 * Action: No reply is expected.
279 * Valid Types: CFM_TYPE_EVENT
281 * Valid Op: CFM_OP_STATS
283 struct cfil_msg_sock_stats
{
284 cfil_sock_id_t cfs_sock_id
;
285 uint64_t cfs_byte_inbound_count
;
286 uint64_t cfs_byte_outbound_count
;
287 union sockaddr_in_4_6 cfs_laddr
;
288 } __attribute__((aligned(8)));
290 struct cfil_msg_stats_report
{
291 struct cfil_msg_hdr cfr_msghdr
;
293 struct cfil_msg_sock_stats cfr_stats
[];
294 } __attribute__((aligned(8)));
297 * struct cfil_msg_action
299 * Valid Type: CFM_TYPE_ACTION
301 * Valid Ops: CFM_OP_DATA_UPDATE, CFM_OP_DROP
303 * For CFM_OP_DATA_UPDATE:
305 * cfa_in_pass_offset and cfa_out_pass_offset indicates how much data is
306 * allowed to pass. A zero value does not modify the corresponding pass offset.
308 * cfa_in_peek_offset and cfa_out_peek_offset lets the filter specify how much
309 * data it needs to make a decision: the kernel will deliver data up to that
310 * offset (if less than cfa_pass_offset it is ignored). Use CFM_MAX_OFFSET
311 * if you don't value the corresponding peek offset to be updated.
313 struct cfil_msg_action
{
314 struct cfil_msg_hdr cfa_msghdr
;
315 uint64_t cfa_in_pass_offset
;
316 uint64_t cfa_in_peek_offset
;
317 uint64_t cfa_out_pass_offset
;
318 uint64_t cfa_out_peek_offset
;
319 uint32_t cfa_stats_frequency
; // Statistics frequency in milliseconds
323 * struct cfil_msg_bless_client
325 * Marks a client UUID as already filtered at a higher level.
327 * Valid Type: CFM_TYPE_ACTION
329 * Valid Ops: CFM_OP_BLESS_CLIENT
331 struct cfil_msg_bless_client
{
332 struct cfil_msg_hdr cfb_msghdr
;
333 uuid_t cfb_client_uuid
;
337 * struct cfil_msg_set_crypto_key
339 * Filter assigning client crypto key to CFIL for message signing
341 * Valid Type: CFM_TYPE_ACTION
343 * Valid Ops: CFM_OP_SET_CRYPTO_KEY
345 struct cfil_msg_set_crypto_key
{
346 struct cfil_msg_hdr cfb_msghdr
;
347 cfil_crypto_key crypto_key
;
350 #define CFM_MAX_OFFSET UINT64_MAX
353 * Statistics retrieved via sysctl(3)
355 struct cfil_filter_stat
{
357 uint32_t cfs_filter_id
;
359 uint32_t cfs_sock_count
;
360 uint32_t cfs_necp_control_unit
;
363 struct cfil_entry_stat
{
365 uint32_t ces_filter_id
;
367 uint32_t ces_necp_control_unit
;
368 struct timeval64 ces_last_event
;
369 struct timeval64 ces_last_action
;
370 struct cfe_buf_stat
{
371 uint64_t cbs_pending_first
;
372 uint64_t cbs_pending_last
;
373 uint64_t cbs_ctl_first
;
374 uint64_t cbs_ctl_last
;
375 uint64_t cbs_pass_offset
;
376 uint64_t cbs_peek_offset
;
381 struct cfil_sock_stat
{
385 int cfs_sock_protocol
;
386 cfil_sock_id_t cfs_sock_id
;
392 struct cfi_buf_stat
{
393 uint64_t cbs_pending_first
;
394 uint64_t cbs_pending_last
;
395 uint64_t cbs_pass_offset
;
396 uint64_t cbs_inject_q_len
;
398 struct cfil_entry_stat ces_entries
[CFIL_MAX_FILTER_COUNT
];
405 int32_t cfs_ctl_connect_ok
;
406 int32_t cfs_ctl_connect_fail
;
407 int32_t cfs_ctl_disconnect_ok
;
408 int32_t cfs_ctl_disconnect_fail
;
409 int32_t cfs_ctl_send_ok
;
410 int32_t cfs_ctl_send_bad
;
411 int32_t cfs_ctl_rcvd_ok
;
412 int32_t cfs_ctl_rcvd_bad
;
413 int32_t cfs_ctl_rcvd_flow_lift
;
414 int32_t cfs_ctl_action_data_update
;
415 int32_t cfs_ctl_action_drop
;
416 int32_t cfs_ctl_action_bad_op
;
417 int32_t cfs_ctl_action_bad_len
;
419 int32_t cfs_sock_id_not_found
;
421 int32_t cfs_cfi_alloc_ok
;
422 int32_t cfs_cfi_alloc_fail
;
424 int32_t cfs_sock_userspace_only
;
425 int32_t cfs_sock_attach_in_vain
;
426 int32_t cfs_sock_attach_already
;
427 int32_t cfs_sock_attach_no_mem
;
428 int32_t cfs_sock_attach_failed
;
429 int32_t cfs_sock_attached
;
430 int32_t cfs_sock_detached
;
432 int32_t cfs_attach_event_ok
;
433 int32_t cfs_attach_event_flow_control
;
434 int32_t cfs_attach_event_fail
;
436 int32_t cfs_closed_event_ok
;
437 int32_t cfs_closed_event_flow_control
;
438 int32_t cfs_closed_event_fail
;
440 int32_t cfs_data_event_ok
;
441 int32_t cfs_data_event_flow_control
;
442 int32_t cfs_data_event_fail
;
444 int32_t cfs_stats_event_ok
;
445 int32_t cfs_stats_event_flow_control
;
446 int32_t cfs_stats_event_fail
;
448 int32_t cfs_disconnect_in_event_ok
;
449 int32_t cfs_disconnect_out_event_ok
;
450 int32_t cfs_disconnect_event_flow_control
;
451 int32_t cfs_disconnect_event_fail
;
453 int32_t cfs_ctl_q_not_started
;
455 int32_t cfs_close_wait
;
456 int32_t cfs_close_wait_timeout
;
458 int32_t cfs_flush_in_drop
;
459 int32_t cfs_flush_out_drop
;
460 int32_t cfs_flush_in_close
;
461 int32_t cfs_flush_out_close
;
462 int32_t cfs_flush_in_free
;
463 int32_t cfs_flush_out_free
;
465 int32_t cfs_inject_q_nomem
;
466 int32_t cfs_inject_q_nobufs
;
467 int32_t cfs_inject_q_detached
;
468 int32_t cfs_inject_q_in_fail
;
469 int32_t cfs_inject_q_out_fail
;
471 int32_t cfs_inject_q_in_retry
;
472 int32_t cfs_inject_q_out_retry
;
474 int32_t cfs_data_in_control
;
475 int32_t cfs_data_in_oob
;
476 int32_t cfs_data_out_control
;
477 int32_t cfs_data_out_oob
;
479 int64_t cfs_ctl_q_in_enqueued
__attribute__((aligned(8)));
480 int64_t cfs_ctl_q_out_enqueued
__attribute__((aligned(8)));
481 int64_t cfs_ctl_q_in_peeked
__attribute__((aligned(8)));
482 int64_t cfs_ctl_q_out_peeked
__attribute__((aligned(8)));
484 int64_t cfs_pending_q_in_enqueued
__attribute__((aligned(8)));
485 int64_t cfs_pending_q_out_enqueued
__attribute__((aligned(8)));
487 int64_t cfs_inject_q_in_enqueued
__attribute__((aligned(8)));
488 int64_t cfs_inject_q_out_enqueued
__attribute__((aligned(8)));
489 int64_t cfs_inject_q_in_passed
__attribute__((aligned(8)));
490 int64_t cfs_inject_q_out_passed
__attribute__((aligned(8)));
494 #ifdef BSD_KERNEL_PRIVATE
496 #define M_SKIPCFIL M_PROTO5
498 extern int cfil_log_level
;
500 #define CFIL_LOG(level, fmt, ...) \
502 if (cfil_log_level >= level) \
503 printf("%s:%d " fmt "\n",\
504 __FUNCTION__, __LINE__, ##__VA_ARGS__); \
508 extern void cfil_init(void);
510 extern boolean_t
cfil_filter_present(void);
511 extern boolean_t
cfil_sock_connected_pending_verdict(struct socket
*so
);
512 extern errno_t
cfil_sock_attach(struct socket
*so
,
513 struct sockaddr
*local
, struct sockaddr
*remote
, int dir
);
514 extern errno_t
cfil_sock_detach(struct socket
*so
);
516 extern int cfil_sock_data_out(struct socket
*so
, struct sockaddr
*to
,
517 struct mbuf
*data
, struct mbuf
*control
,
519 extern int cfil_sock_data_in(struct socket
*so
, struct sockaddr
*from
,
520 struct mbuf
*data
, struct mbuf
*control
,
523 extern int cfil_sock_shutdown(struct socket
*so
, int *how
);
524 extern void cfil_sock_is_closed(struct socket
*so
);
525 extern void cfil_sock_notify_shutdown(struct socket
*so
, int how
);
526 extern void cfil_sock_close_wait(struct socket
*so
);
528 extern boolean_t
cfil_sock_data_pending(struct sockbuf
*sb
);
529 extern int cfil_sock_data_space(struct sockbuf
*sb
);
530 extern void cfil_sock_buf_update(struct sockbuf
*sb
);
532 extern cfil_sock_id_t
cfil_sock_id_from_socket(struct socket
*so
);
533 extern cfil_sock_id_t
cfil_sock_id_from_datagram_socket(struct socket
*so
, struct sockaddr
*local
, struct sockaddr
*remote
);
535 extern struct m_tag
*cfil_dgram_get_socket_state(struct mbuf
*m
, uint32_t *state_change_cnt
,
536 uint32_t *options
, struct sockaddr
**faddr
, int *inp_flags
);
537 extern boolean_t
cfil_dgram_peek_socket_state(struct mbuf
*m
, int *inp_flags
);
539 #endif /* BSD_KERNEL_PRIVATE */
543 #endif /* __CONTENT_FILTER_H__ */