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 | */ |
55 | typedef 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 | */ |
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 | |
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 | */ |
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 | |
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 | |
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 | |
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 | |
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 | |
425 | extern 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 | |