]>
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> | |
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 | */ | |
93 | typedef 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 | */ | |
100 | struct 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 | */ | |
110 | struct 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 | */ | |
132 | struct 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 | */ | |
159 | struct 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 | */ | |
185 | struct 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 | */ | |
198 | struct 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 | ||
206 | struct 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 | ||
224 | struct 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 | */ | |
247 | struct 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 | ||
338 | extern int cfil_log_level; | |
339 | ||
340 | #define CFIL_LOG(level, fmt, ...) \ | |
341 | do { \ | |
342 | if (cfil_log_level >= level) \ | |
343 | printf("%s:%d " fmt "\n",\ | |
344 | __FUNCTION__, __LINE__, ##__VA_ARGS__); \ | |
345 | } while (0) | |
346 | ||
347 | ||
348 | extern void cfil_init(void); | |
349 | ||
350 | extern errno_t cfil_sock_attach(struct socket *so); | |
351 | extern errno_t cfil_sock_detach(struct socket *so); | |
352 | ||
353 | extern int cfil_sock_data_out(struct socket *so, struct sockaddr *to, | |
354 | struct mbuf *data, struct mbuf *control, | |
355 | uint32_t flags); | |
356 | extern int cfil_sock_data_in(struct socket *so, struct sockaddr *from, | |
357 | struct mbuf *data, struct mbuf *control, | |
358 | uint32_t flags); | |
359 | ||
360 | extern int cfil_sock_shutdown(struct socket *so, int *how); | |
361 | extern void cfil_sock_is_closed(struct socket *so); | |
362 | extern void cfil_sock_notify_shutdown(struct socket *so, int how); | |
363 | extern void cfil_sock_close_wait(struct socket *so); | |
364 | ||
365 | extern boolean_t cfil_sock_data_pending(struct sockbuf *sb); | |
366 | extern int cfil_sock_data_space(struct sockbuf *sb); | |
367 | extern void cfil_sock_buf_update(struct sockbuf *sb); | |
368 | ||
369 | extern 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__ */ |