]>
Commit | Line | Data |
---|---|---|
fe8ab488 A |
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> | |
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 | ||
52 | /* | |
53 | * CFIL_OPT_NECP_CONTROL_UNIT | |
54 | * To set or get the NECP filter control unit for the kernel control socket | |
55 | * The option level is SYSPROTO_CONTROL | |
56 | */ | |
57 | #define CFIL_OPT_NECP_CONTROL_UNIT 1 /* uint32_t */ | |
58 | ||
59 | /* | |
60 | * How many filter may be active simultaneously | |
61 | */ | |
62 | #define CFIL_MAX_FILTER_COUNT 2 | |
63 | ||
64 | /* | |
65 | * Types of messages | |
66 | * | |
67 | * Event messages flow from kernel to user space while action | |
68 | * messages flow in the reverse direction. | |
69 | * A message in entirely represented by a packet sent or received | |
70 | * on a Content Filter kernel control socket. | |
71 | */ | |
72 | #define CFM_TYPE_EVENT 1 /* message from kernel */ | |
73 | #define CFM_TYPE_ACTION 2 /* message to kernel */ | |
74 | ||
75 | /* | |
76 | * Operations associated with events from kernel | |
77 | */ | |
78 | #define CFM_OP_SOCKET_ATTACHED 1 /* a socket has been attached */ | |
79 | #define CFM_OP_SOCKET_CLOSED 2 /* a socket is being closed */ | |
80 | #define CFM_OP_DATA_OUT 3 /* data being sent */ | |
81 | #define CFM_OP_DATA_IN 4 /* data being received */ | |
82 | #define CFM_OP_DISCONNECT_OUT 5 /* no more outgoing data */ | |
83 | #define CFM_OP_DISCONNECT_IN 6 /* no more incoming data */ | |
84 | ||
85 | /* | |
86 | * Operations associated with action from filter to kernel | |
87 | */ | |
88 | #define CFM_OP_DATA_UPDATE 16 /* update pass or peek offsets */ | |
89 | #define CFM_OP_DROP 17 /* shutdown socket, no more data */ | |
90 | ||
91 | /* | |
92 | * Opaque socket identifier | |
93 | */ | |
94 | typedef uint64_t cfil_sock_id_t; | |
95 | ||
96 | #define CFIL_SOCK_ID_NONE UINT64_MAX | |
97 | ||
fe8ab488 A |
98 | /* |
99 | * struct cfil_msg_hdr | |
100 | * | |
101 | * Header common to all messages | |
102 | */ | |
103 | struct cfil_msg_hdr { | |
104 | uint32_t cfm_len; /* total length */ | |
105 | uint32_t cfm_version; | |
106 | uint32_t cfm_type; | |
107 | uint32_t cfm_op; | |
108 | cfil_sock_id_t cfm_sock_id; | |
109 | }; | |
110 | ||
111 | #define CFM_VERSION_CURRENT 1 | |
112 | ||
113 | /* | |
114 | * struct cfil_msg_sock_attached | |
115 | * | |
116 | * Information about a new socket being attached to the content filter | |
117 | * | |
118 | * Action: No reply is expected as this does not block the creation of the | |
119 | * TCP/IP but timely action must be taken to avoid user noticeable delays. | |
120 | * | |
121 | * Valid Types: CFM_TYPE_EVENT | |
122 | * | |
123 | * Valid Op: CFM_OP_SOCKET_ATTACHED | |
124 | */ | |
125 | struct cfil_msg_sock_attached { | |
126 | struct cfil_msg_hdr cfs_msghdr; | |
127 | int cfs_sock_family; /* e.g. PF_INET */ | |
128 | int cfs_sock_type; /* e.g. SOCK_STREAM */ | |
129 | int cfs_sock_protocol; /* e.g. IPPROTO_TCP */ | |
130 | int cfs_unused; /* padding */ | |
131 | pid_t cfs_pid; | |
132 | pid_t cfs_e_pid; | |
133 | uuid_t cfs_uuid; | |
134 | uuid_t cfs_e_uuid; | |
135 | }; | |
136 | ||
137 | /* | |
138 | * struct cfil_msg_data_event | |
139 | * | |
140 | * Event for the content fiter to act on a span of data | |
141 | * A data span is described by a pair of offsets over the cumulative | |
142 | * number of bytes sent or received on the socket. | |
143 | * | |
144 | * Action: The event must be acted upon but the filter may buffer | |
145 | * data spans until it has enough content to make a decision. | |
146 | * The action must be timely to avoid user noticeable delays. | |
147 | * | |
148 | * Valid Type: CFM_TYPE_EVENT | |
149 | * | |
150 | * Valid Ops: CFM_OP_DATA_OUT, CFM_OP_DATA_IN | |
151 | */ | |
152 | struct cfil_msg_data_event { | |
153 | struct cfil_msg_hdr cfd_msghdr; | |
154 | union sockaddr_in_4_6 cfc_src; | |
155 | union sockaddr_in_4_6 cfc_dst; | |
156 | uint64_t cfd_start_offset; | |
157 | uint64_t cfd_end_offset; | |
158 | /* Actual content data immediatly follows */ | |
159 | }; | |
160 | ||
161 | /* | |
162 | * struct cfil_msg_action | |
163 | * | |
164 | * Valid Type: CFM_TYPE_ACTION | |
165 | * | |
166 | * Valid Ops: CFM_OP_DATA_UPDATE, CFM_OP_DROP | |
167 | * | |
168 | * For CFM_OP_DATA_UPDATE: | |
169 | * | |
170 | * cfa_in_pass_offset and cfa_out_pass_offset indicates how much data is | |
171 | * allowed to pass. A zero value does not modify the corresponding pass offset. | |
172 | * | |
173 | * cfa_in_peek_offset and cfa_out_peek_offset lets the filter specify how much | |
174 | * data it needs to make a decision: the kernel will deliver data up to that | |
175 | * offset (if less than cfa_pass_offset it is ignored). Use CFM_MAX_OFFSET | |
176 | * if you don't value the corresponding peek offset to be updated. | |
177 | */ | |
178 | struct cfil_msg_action { | |
179 | struct cfil_msg_hdr cfa_msghdr; | |
180 | uint64_t cfa_in_pass_offset; | |
181 | uint64_t cfa_in_peek_offset; | |
182 | uint64_t cfa_out_pass_offset; | |
183 | uint64_t cfa_out_peek_offset; | |
184 | }; | |
185 | ||
186 | #define CFM_MAX_OFFSET UINT64_MAX | |
187 | ||
188 | /* | |
189 | * Statistics retrieved via sysctl(3) | |
190 | */ | |
191 | struct cfil_filter_stat { | |
192 | uint32_t cfs_len; | |
193 | uint32_t cfs_filter_id; | |
194 | uint32_t cfs_flags; | |
195 | uint32_t cfs_sock_count; | |
196 | uint32_t cfs_necp_control_unit; | |
197 | }; | |
198 | ||
199 | struct cfil_entry_stat { | |
200 | uint32_t ces_len; | |
201 | uint32_t ces_filter_id; | |
202 | uint32_t ces_flags; | |
203 | uint32_t ces_necp_control_unit; | |
204 | struct timeval64 ces_last_event; | |
205 | struct timeval64 ces_last_action; | |
206 | struct cfe_buf_stat { | |
207 | uint64_t cbs_pending_first; | |
208 | uint64_t cbs_pending_last; | |
209 | uint64_t cbs_ctl_first; | |
210 | uint64_t cbs_ctl_last; | |
211 | uint64_t cbs_pass_offset; | |
212 | uint64_t cbs_peek_offset; | |
213 | uint64_t cbs_peeked; | |
214 | } ces_snd, ces_rcv; | |
215 | }; | |
216 | ||
217 | struct cfil_sock_stat { | |
218 | uint32_t cfs_len; | |
219 | int cfs_sock_family; | |
220 | int cfs_sock_type; | |
221 | int cfs_sock_protocol; | |
222 | cfil_sock_id_t cfs_sock_id; | |
223 | uint64_t cfs_flags; | |
224 | pid_t cfs_pid; | |
225 | pid_t cfs_e_pid; | |
226 | uuid_t cfs_uuid; | |
227 | uuid_t cfs_e_uuid; | |
228 | struct cfi_buf_stat { | |
229 | uint64_t cbs_pending_first; | |
230 | uint64_t cbs_pending_last; | |
231 | uint64_t cbs_pass_offset; | |
232 | uint64_t cbs_inject_q_len; | |
233 | } cfs_snd, cfs_rcv; | |
234 | struct cfil_entry_stat ces_entries[CFIL_MAX_FILTER_COUNT]; | |
235 | }; | |
236 | ||
237 | /* | |
238 | * Global statistics | |
239 | */ | |
240 | struct cfil_stats { | |
241 | int32_t cfs_ctl_connect_ok; | |
242 | int32_t cfs_ctl_connect_fail; | |
243 | int32_t cfs_ctl_disconnect_ok; | |
244 | int32_t cfs_ctl_disconnect_fail; | |
245 | int32_t cfs_ctl_send_ok; | |
246 | int32_t cfs_ctl_send_bad; | |
247 | int32_t cfs_ctl_rcvd_ok; | |
248 | int32_t cfs_ctl_rcvd_bad; | |
249 | int32_t cfs_ctl_rcvd_flow_lift; | |
250 | int32_t cfs_ctl_action_data_update; | |
251 | int32_t cfs_ctl_action_drop; | |
252 | int32_t cfs_ctl_action_bad_op; | |
253 | int32_t cfs_ctl_action_bad_len; | |
254 | ||
255 | int32_t cfs_sock_id_not_found; | |
256 | ||
257 | int32_t cfs_cfi_alloc_ok; | |
258 | int32_t cfs_cfi_alloc_fail; | |
259 | ||
260 | int32_t cfs_sock_userspace_only; | |
261 | int32_t cfs_sock_attach_in_vain; | |
262 | int32_t cfs_sock_attach_already; | |
263 | int32_t cfs_sock_attach_no_mem; | |
264 | int32_t cfs_sock_attach_failed; | |
265 | int32_t cfs_sock_attached; | |
266 | int32_t cfs_sock_detached; | |
267 | ||
268 | int32_t cfs_attach_event_ok; | |
269 | int32_t cfs_attach_event_flow_control; | |
270 | int32_t cfs_attach_event_fail; | |
271 | ||
272 | int32_t cfs_closed_event_ok; | |
273 | int32_t cfs_closed_event_flow_control; | |
274 | int32_t cfs_closed_event_fail; | |
275 | ||
276 | int32_t cfs_data_event_ok; | |
277 | int32_t cfs_data_event_flow_control; | |
278 | int32_t cfs_data_event_fail; | |
279 | ||
280 | int32_t cfs_disconnect_in_event_ok; | |
281 | int32_t cfs_disconnect_out_event_ok; | |
282 | int32_t cfs_disconnect_event_flow_control; | |
283 | int32_t cfs_disconnect_event_fail; | |
284 | ||
285 | int32_t cfs_ctl_q_not_started; | |
286 | ||
287 | int32_t cfs_close_wait; | |
288 | int32_t cfs_close_wait_timeout; | |
289 | ||
290 | int32_t cfs_flush_in_drop; | |
291 | int32_t cfs_flush_out_drop; | |
292 | int32_t cfs_flush_in_close; | |
293 | int32_t cfs_flush_out_close; | |
294 | int32_t cfs_flush_in_free; | |
295 | int32_t cfs_flush_out_free; | |
296 | ||
297 | int32_t cfs_inject_q_nomem; | |
298 | int32_t cfs_inject_q_nobufs; | |
299 | int32_t cfs_inject_q_detached; | |
300 | int32_t cfs_inject_q_in_fail; | |
301 | int32_t cfs_inject_q_out_fail; | |
302 | ||
303 | int32_t cfs_inject_q_in_retry; | |
304 | int32_t cfs_inject_q_out_retry; | |
305 | ||
306 | int32_t cfs_data_in_control; | |
307 | int32_t cfs_data_in_oob; | |
308 | int32_t cfs_data_out_control; | |
309 | int32_t cfs_data_out_oob; | |
310 | ||
311 | int64_t cfs_ctl_q_in_enqueued __attribute__((aligned(8))); | |
312 | int64_t cfs_ctl_q_out_enqueued __attribute__((aligned(8))); | |
313 | int64_t cfs_ctl_q_in_peeked __attribute__((aligned(8))); | |
314 | int64_t cfs_ctl_q_out_peeked __attribute__((aligned(8))); | |
315 | ||
316 | int64_t cfs_pending_q_in_enqueued __attribute__((aligned(8))); | |
317 | int64_t cfs_pending_q_out_enqueued __attribute__((aligned(8))); | |
318 | ||
319 | int64_t cfs_inject_q_in_enqueued __attribute__((aligned(8))); | |
320 | int64_t cfs_inject_q_out_enqueued __attribute__((aligned(8))); | |
321 | int64_t cfs_inject_q_in_passed __attribute__((aligned(8))); | |
322 | int64_t cfs_inject_q_out_passed __attribute__((aligned(8))); | |
323 | ||
324 | }; | |
325 | #endif /* PRIVATE */ | |
326 | ||
327 | #ifdef BSD_KERNEL_PRIVATE | |
328 | ||
329 | #define M_SKIPCFIL M_PROTO5 | |
330 | ||
331 | extern int cfil_log_level; | |
332 | ||
333 | #define CFIL_LOG(level, fmt, ...) \ | |
334 | do { \ | |
335 | if (cfil_log_level >= level) \ | |
336 | printf("%s:%d " fmt "\n",\ | |
337 | __FUNCTION__, __LINE__, ##__VA_ARGS__); \ | |
338 | } while (0) | |
339 | ||
340 | ||
341 | extern void cfil_init(void); | |
342 | ||
343 | extern errno_t cfil_sock_attach(struct socket *so); | |
344 | extern errno_t cfil_sock_detach(struct socket *so); | |
345 | ||
346 | extern int cfil_sock_data_out(struct socket *so, struct sockaddr *to, | |
347 | struct mbuf *data, struct mbuf *control, | |
348 | uint32_t flags); | |
349 | extern int cfil_sock_data_in(struct socket *so, struct sockaddr *from, | |
350 | struct mbuf *data, struct mbuf *control, | |
351 | uint32_t flags); | |
352 | ||
353 | extern int cfil_sock_shutdown(struct socket *so, int *how); | |
354 | extern void cfil_sock_is_closed(struct socket *so); | |
355 | extern void cfil_sock_notify_shutdown(struct socket *so, int how); | |
356 | extern void cfil_sock_close_wait(struct socket *so); | |
357 | ||
358 | extern boolean_t cfil_sock_data_pending(struct sockbuf *sb); | |
359 | extern int cfil_sock_data_space(struct sockbuf *sb); | |
360 | extern void cfil_sock_buf_update(struct sockbuf *sb); | |
361 | ||
362 | extern cfil_sock_id_t cfil_sock_id_from_socket(struct socket *so); | |
363 | ||
364 | __END_DECLS | |
365 | ||
366 | #endif /* BSD_KERNEL_PRIVATE */ | |
367 | ||
368 | #endif /* __CONTENT_FILTER_H__ */ |