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