]>
Commit | Line | Data |
---|---|---|
fe8ab488 | 1 | /* |
5ba3f43e | 2 | * Copyright (c) 2013-2017 Apple Inc. All rights reserved. |
fe8ab488 A |
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> | |
3e170ce0 | 29 | #include <sys/_types/_timeval64.h> |
fe8ab488 A |
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 | ||
5ba3f43e A |
52 | /* |
53 | * Opaque socket identifier | |
54 | */ | |
55 | typedef uint64_t cfil_sock_id_t; | |
56 | ||
57 | #define CFIL_SOCK_ID_NONE UINT64_MAX | |
58 | ||
59 | ||
fe8ab488 A |
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 | ||
5ba3f43e A |
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 | */ | |
78 | struct 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 | ||
fe8ab488 A |
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 */ | |
5ba3f43e | 122 | #define CFM_OP_BLESS_CLIENT 18 /* mark a client flow as already filtered, passes a uuid */ |
fe8ab488 | 123 | |
fe8ab488 A |
124 | /* |
125 | * struct cfil_msg_hdr | |
126 | * | |
127 | * Header common to all messages | |
128 | */ | |
129 | struct 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 | */ | |
151 | struct 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 | */ | |
178 | struct 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 | ||
5ba3f43e A |
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 | */ | |
200 | struct 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 | ||
fe8ab488 A |
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 | */ | |
225 | struct 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 | ||
5ba3f43e A |
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 | */ | |
242 | struct cfil_msg_bless_client { | |
243 | struct cfil_msg_hdr cfb_msghdr; | |
244 | uuid_t cfb_client_uuid; | |
245 | }; | |
246 | ||
fe8ab488 A |
247 | #define CFM_MAX_OFFSET UINT64_MAX |
248 | ||
249 | /* | |
250 | * Statistics retrieved via sysctl(3) | |
251 | */ | |
252 | struct 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 | ||
260 | struct 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 | ||
278 | struct 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 | */ | |
301 | struct 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 | ||
392 | extern int cfil_log_level; | |
393 | ||
394 | #define CFIL_LOG(level, fmt, ...) \ | |
395 | do { \ | |
396 | if (cfil_log_level >= level) \ | |
397 | printf("%s:%d " fmt "\n",\ | |
398 | __FUNCTION__, __LINE__, ##__VA_ARGS__); \ | |
399 | } while (0) | |
400 | ||
401 | ||
402 | extern void cfil_init(void); | |
403 | ||
404 | extern errno_t cfil_sock_attach(struct socket *so); | |
405 | extern errno_t cfil_sock_detach(struct socket *so); | |
406 | ||
407 | extern int cfil_sock_data_out(struct socket *so, struct sockaddr *to, | |
408 | struct mbuf *data, struct mbuf *control, | |
409 | uint32_t flags); | |
410 | extern int cfil_sock_data_in(struct socket *so, struct sockaddr *from, | |
411 | struct mbuf *data, struct mbuf *control, | |
412 | uint32_t flags); | |
413 | ||
414 | extern int cfil_sock_shutdown(struct socket *so, int *how); | |
415 | extern void cfil_sock_is_closed(struct socket *so); | |
416 | extern void cfil_sock_notify_shutdown(struct socket *so, int how); | |
417 | extern void cfil_sock_close_wait(struct socket *so); | |
418 | ||
419 | extern boolean_t cfil_sock_data_pending(struct sockbuf *sb); | |
420 | extern int cfil_sock_data_space(struct sockbuf *sb); | |
421 | extern void cfil_sock_buf_update(struct sockbuf *sb); | |
422 | ||
423 | extern cfil_sock_id_t cfil_sock_id_from_socket(struct socket *so); | |
424 | ||
d9a64523 A |
425 | extern struct m_tag *cfil_udp_get_socket_state(struct mbuf *m, uint32_t *state_change_cnt, |
426 | short *options, struct sockaddr **faddr); | |
fe8ab488 A |
427 | #endif /* BSD_KERNEL_PRIVATE */ |
428 | ||
5ba3f43e A |
429 | __END_DECLS |
430 | ||
fe8ab488 | 431 | #endif /* __CONTENT_FILTER_H__ */ |