2 * Copyright (c) 2013-2014 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 #include <sys/systm.h>
31 #include <sys/types.h>
32 #include <sys/syslog.h>
33 #include <sys/queue.h>
34 #include <sys/malloc.h>
35 #include <libkern/OSMalloc.h>
36 #include <sys/kernel.h>
37 #include <sys/kern_control.h>
39 #include <sys/kpi_mbuf.h>
40 #include <sys/proc_uuid_policy.h>
42 #include <sys/protosw.h>
43 #include <sys/socket.h>
44 #include <sys/socketvar.h>
45 #include <netinet/ip.h>
46 #include <netinet/ip6.h>
47 #include <netinet/tcp.h>
48 #include <netinet/udp.h>
49 #include <netinet/in_pcb.h>
50 #include <net/flowhash.h>
51 #include <net/if_var.h>
52 #include <sys/kauth.h>
53 #include <sys/sysctl.h>
54 #include <sys/sysproto.h>
59 * NECP - Network Extension Control Policy database
60 * ------------------------------------------------
61 * The goal of this module is to allow clients connecting via a
62 * kernel control socket to create high-level policy sessions, which
63 * are ingested into low-level kernel policies that control and tag
64 * traffic at the application, socket, and IP layers.
66 * ------------------------------------------------
68 * ------------------------------------------------
69 * Each session owns a list of session policies, each of which can
70 * specify any combination of conditions and a single result. Each
71 * session also has a priority level (such as High, Default, or Low)
72 * which is requested by the client. Based on the requested level,
73 * a session order value is assigned to the session, which will be used
74 * to sort kernel policies generated by the session. The session client
75 * can specify the sub-order for each policy it creates which will be
76 * used to further sort the kernel policies.
78 * Kernel Control Socket --> 1 necp_session --> list of necp_session_policy structs
80 * ------------------------------------------------
82 * ------------------------------------------------
83 * Whenever a session send the Apply command, its policies are ingested
84 * and generate kernel policies. There are two phases of kernel policy
87 * 1. The session policy is parsed to create kernel policies at the socket
88 * and IP layers, when applicable. For example, a policy that requires
89 * all traffic from App1 to Pass will generate a socket kernel policy to
90 * match App1 and mark packets with ID1, and also an IP policy to match
91 * ID1 and let the packet pass. This is handled in necp_apply_policy. The
92 * resulting kernel policies are added to the global socket and IP layer
94 * necp_session_policy --> necp_kernel_socket_policy and necp_kernel_ip_output_policy
97 * necp_kernel_socket_policies necp_kernel_ip_output_policies
99 * 2. Once the global lists of kernel policies have been filled out, each
100 * list is traversed to create optimized sub-lists ("Maps") which are used during
101 * data-path evaluation. IP policies are sent into necp_kernel_ip_output_policies_map,
102 * which hashes incoming packets based on marked socket-layer policies, and removes
103 * duplicate or overlapping polcies. Socket policies are sent into two maps,
104 * necp_kernel_socket_policies_map and necp_kernel_socket_policies_app_layer_map.
105 * The app layer map is used for policy checks coming in from user space, and is one
106 * list with duplicate and overlapping policies removed. The socket map hashes based
107 * on app UUID, and removes duplicate and overlapping policies.
108 * necp_kernel_socket_policy --> necp_kernel_socket_policies_app_layer_map
109 * |-> necp_kernel_socket_policies_map
111 * necp_kernel_ip_output_policies --> necp_kernel_ip_output_policies_map
113 * ------------------------------------------------
115 * ------------------------------------------------
116 * The Drop All Level is a sysctl that controls the level at which policies are allowed
117 * to override a global drop rule. If the value is 0, no drop rule is applied. If the value
118 * is 1, all traffic is dropped. If the value is greater than 1, all kernel policies created
119 * by a session with a priority level better than (numerically less than) the
120 * Drop All Level will allow matching traffic to not be dropped. The Drop All Level is
121 * dynamically interpreted into necp_drop_all_order, which specifies the equivalent assigned
122 * session orders to be dropped.
125 u_int32_t necp_drop_all_order
= 0;
126 u_int32_t necp_drop_all_level
= 0;
128 u_int32_t necp_pass_loopback
= 1; // 0=Off, 1=On
129 u_int32_t necp_pass_keepalives
= 1; // 0=Off, 1=On
131 u_int32_t necp_debug
= 0; // 0=None, 1=Basic, 2=EveryMatch
133 static int sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
;
135 SYSCTL_NODE(_net
, OID_AUTO
, necp
, CTLFLAG_RW
| CTLFLAG_LOCKED
, 0, "NECP");
136 SYSCTL_INT(_net_necp
, NECPCTL_PASS_LOOPBACK
, pass_loopback
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_pass_loopback
, 0, "");
137 SYSCTL_INT(_net_necp
, NECPCTL_PASS_KEEPALIVES
, pass_keepalives
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_pass_keepalives
, 0, "");
138 SYSCTL_INT(_net_necp
, NECPCTL_DEBUG
, debug
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_debug
, 0, "");
139 SYSCTL_PROC(_net_necp
, NECPCTL_DROP_ALL_LEVEL
, drop_all_level
, CTLTYPE_INT
| CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_drop_all_level
, 0, &sysctl_handle_necp_level
, "IU", "");
141 #define NECPLOG(level, format, ...) do { \
142 log((level > LOG_NOTICE ? LOG_NOTICE : level), "%s: " format "\n", __FUNCTION__, __VA_ARGS__); \
145 #define NECPLOG0(level, msg) do { \
146 log((level > LOG_NOTICE ? LOG_NOTICE : level), "%s: %s\n", __FUNCTION__, msg); \
149 #define LIST_INSERT_SORTED_ASCENDING(head, elm, field, sortfield, tmpelm) do { \
150 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->sortfield >= (elm)->sortfield)) { \
151 LIST_INSERT_HEAD((head), elm, field); \
153 LIST_FOREACH(tmpelm, head, field) { \
154 if (LIST_NEXT(tmpelm, field) == NULL || LIST_NEXT(tmpelm, field)->sortfield >= (elm)->sortfield) { \
155 LIST_INSERT_AFTER(tmpelm, elm, field); \
162 #define LIST_INSERT_SORTED_TWICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, tmpelm) do { \
163 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield))) { \
164 LIST_INSERT_HEAD((head), elm, field); \
166 LIST_FOREACH(tmpelm, head, field) { \
167 if (LIST_NEXT(tmpelm, field) == NULL || (LIST_NEXT(tmpelm, field)->firstsortfield > (elm)->firstsortfield) || ((LIST_NEXT(tmpelm, field)->firstsortfield == (elm)->firstsortfield) && (LIST_NEXT(tmpelm, field)->secondsortfield >= (elm)->secondsortfield))) { \
168 LIST_INSERT_AFTER(tmpelm, elm, field); \
175 #define LIST_INSERT_SORTED_THRICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, thirdsortfield, tmpelm) do { \
176 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield)) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield == (elm)->secondsortfield) && (LIST_FIRST(head)->thirdsortfield >= (elm)->thirdsortfield))) { \
177 LIST_INSERT_HEAD((head), elm, field); \
179 LIST_FOREACH(tmpelm, head, field) { \
180 if (LIST_NEXT(tmpelm, field) == NULL || (LIST_NEXT(tmpelm, field)->firstsortfield > (elm)->firstsortfield) || ((LIST_NEXT(tmpelm, field)->firstsortfield == (elm)->firstsortfield) && (LIST_NEXT(tmpelm, field)->secondsortfield >= (elm)->secondsortfield)) || ((LIST_NEXT(tmpelm, field)->firstsortfield == (elm)->firstsortfield) && (LIST_NEXT(tmpelm, field)->secondsortfield == (elm)->secondsortfield) && (LIST_NEXT(tmpelm, field)->thirdsortfield >= (elm)->thirdsortfield))) { \
181 LIST_INSERT_AFTER(tmpelm, elm, field); \
188 #define NECP_KERNEL_CONDITION_ALL_INTERFACES 0x00001
189 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE 0x00002
190 #define NECP_KERNEL_CONDITION_PROTOCOL 0x00004
191 #define NECP_KERNEL_CONDITION_LOCAL_START 0x00008
192 #define NECP_KERNEL_CONDITION_LOCAL_END 0x00010
193 #define NECP_KERNEL_CONDITION_LOCAL_PREFIX 0x00020
194 #define NECP_KERNEL_CONDITION_REMOTE_START 0x00040
195 #define NECP_KERNEL_CONDITION_REMOTE_END 0x00080
196 #define NECP_KERNEL_CONDITION_REMOTE_PREFIX 0x00100
197 #define NECP_KERNEL_CONDITION_APP_ID 0x00200
198 #define NECP_KERNEL_CONDITION_REAL_APP_ID 0x00400
199 #define NECP_KERNEL_CONDITION_DOMAIN 0x00800
200 #define NECP_KERNEL_CONDITION_ACCOUNT_ID 0x01000
201 #define NECP_KERNEL_CONDITION_POLICY_ID 0x02000
202 #define NECP_KERNEL_CONDITION_PID 0x04000
203 #define NECP_KERNEL_CONDITION_UID 0x08000
204 #define NECP_KERNEL_CONDITION_LAST_INTERFACE 0x10000 // Only set from packets looping between interfaces
205 #define NECP_KERNEL_CONDITION_TRAFFIC_CLASS 0x20000
206 #define NECP_KERNEL_CONDITION_ENTITLEMENT 0x40000
208 struct necp_service_registration
{
209 LIST_ENTRY(necp_service_registration
) session_chain
;
210 LIST_ENTRY(necp_service_registration
) kernel_chain
;
211 u_int32_t service_id
;
214 struct necp_session
{
215 u_int32_t control_unit
;
216 u_int32_t session_priority
; // Descriptive priority rating
217 u_int32_t session_order
;
219 bool proc_locked
; // Messages must come from proc_uuid
223 LIST_HEAD(_policies
, necp_session_policy
) policies
;
225 LIST_HEAD(_services
, necp_service_registration
) services
;
228 struct necp_socket_info
{
231 union necp_sockaddr_union local_addr
;
232 union necp_sockaddr_union remote_addr
;
233 u_int32_t bound_interface_index
;
234 u_int32_t traffic_class
;
236 u_int32_t application_id
;
237 u_int32_t real_application_id
;
238 u_int32_t account_id
;
243 static kern_ctl_ref necp_kctlref
;
244 static u_int32_t necp_family
;
245 static OSMallocTag necp_malloc_tag
;
246 static lck_grp_attr_t
*necp_kernel_policy_grp_attr
= NULL
;
247 static lck_attr_t
*necp_kernel_policy_mtx_attr
= NULL
;
248 static lck_grp_t
*necp_kernel_policy_mtx_grp
= NULL
;
249 decl_lck_rw_data(static, necp_kernel_policy_lock
);
251 static necp_policy_id necp_last_policy_id
= 0;
252 static necp_kernel_policy_id necp_last_kernel_policy_id
= 0;
253 static u_int32_t necp_last_uuid_id
= 0;
254 static u_int32_t necp_last_string_id
= 0;
257 * On modification, invalidate cached lookups by bumping the generation count.
258 * Other calls will need to take the slowpath of taking
259 * the subsystem lock.
261 static volatile int32_t necp_kernel_socket_policies_gencount
;
262 #define BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT() do { \
263 if (OSIncrementAtomic(&necp_kernel_socket_policies_gencount) == (INT32_MAX - 1)) { \
264 necp_kernel_socket_policies_gencount = 1; \
268 static u_int32_t necp_kernel_application_policies_condition_mask
;
269 static size_t necp_kernel_application_policies_count
;
270 static u_int32_t necp_kernel_socket_policies_condition_mask
;
271 static size_t necp_kernel_socket_policies_count
;
272 static size_t necp_kernel_socket_policies_non_app_count
;
273 static LIST_HEAD(_necpkernelsocketconnectpolicies
, necp_kernel_socket_policy
) necp_kernel_socket_policies
;
274 #define NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS 5
275 #define NECP_SOCKET_MAP_APP_ID_TO_BUCKET(appid) (appid ? (appid%(NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS - 1) + 1) : 0)
276 static struct necp_kernel_socket_policy
**necp_kernel_socket_policies_map
[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
];
277 static struct necp_kernel_socket_policy
**necp_kernel_socket_policies_app_layer_map
;
279 * A note on policy 'maps': these are used for boosting efficiency when matching policies. For each dimension of the map,
280 * such as an ID, the 0 bucket is reserved for sockets/packets that do not have this parameter, while the other
281 * buckets lead to an array of policy pointers that form the list applicable when the (parameter%(NUM_BUCKETS - 1) + 1) == bucket_index.
283 * For example, a packet with policy ID of 7, when there are 4 ID buckets, will map to bucket (7%3 + 1) = 2.
286 static u_int32_t necp_kernel_ip_output_policies_condition_mask
;
287 static size_t necp_kernel_ip_output_policies_count
;
288 static size_t necp_kernel_ip_output_policies_non_id_count
;
289 static LIST_HEAD(_necpkernelipoutputpolicies
, necp_kernel_ip_output_policy
) necp_kernel_ip_output_policies
;
290 #define NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS 5
291 #define NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(id) (id ? (id%(NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS - 1) + 1) : 0)
292 static struct necp_kernel_ip_output_policy
**necp_kernel_ip_output_policies_map
[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
];
294 static struct necp_session
*necp_create_session(u_int32_t control_unit
);
295 static void necp_delete_session(struct necp_session
*session
);
297 static void necp_handle_policy_add(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
);
298 static void necp_handle_policy_get(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
);
299 static void necp_handle_policy_delete(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
);
300 static void necp_handle_policy_apply_all(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
);
301 static void necp_handle_policy_list_all(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
);
302 static void necp_handle_policy_delete_all(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
);
303 static void necp_handle_set_session_priority(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
);
304 static void necp_handle_lock_session_to_proc(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
);
305 static void necp_handle_register_service(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
);
306 static void necp_handle_unregister_service(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
);
308 static struct necp_session_policy
*necp_policy_create(struct necp_session
*session
, necp_policy_order order
, u_int8_t
*conditions_array
, size_t conditions_array_size
, u_int8_t
*result
, size_t result_size
);
309 static struct necp_session_policy
*necp_policy_find(struct necp_session
*session
, necp_policy_id policy_id
);
310 static bool necp_policy_mark_for_deletion(struct necp_session
*session
, struct necp_session_policy
*policy
);
311 static bool necp_policy_mark_all_for_deletion(struct necp_session
*session
);
312 static bool necp_policy_delete(struct necp_session
*session
, struct necp_session_policy
*policy
);
313 static void necp_policy_apply_all(struct necp_session
*session
);
315 static necp_kernel_policy_id
necp_kernel_socket_policy_add(necp_policy_id parent_policy_id
, necp_policy_order order
, u_int32_t session_order
, u_int32_t condition_mask
, u_int32_t condition_negated_mask
, necp_app_id cond_app_id
, necp_app_id cond_real_app_id
, u_int32_t cond_account_id
, char *domain
, pid_t cond_pid
, uid_t cond_uid
, ifnet_t cond_bound_interface
, struct necp_policy_condition_tc_range cond_traffic_class
, u_int16_t cond_protocol
, union necp_sockaddr_union
*cond_local_start
, union necp_sockaddr_union
*cond_local_end
, u_int8_t cond_local_prefix
, union necp_sockaddr_union
*cond_remote_start
, union necp_sockaddr_union
*cond_remote_end
, u_int8_t cond_remote_prefix
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
);
316 static bool necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id
);
317 static bool necp_kernel_socket_policies_reprocess(void);
318 static bool necp_kernel_socket_policies_update_uuid_table(void);
319 static inline struct necp_kernel_socket_policy
*necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy
**policy_search_array
, struct necp_socket_info
*info
, necp_kernel_policy_filter
*return_filter
, necp_kernel_policy_result
*return_service_action
, necp_kernel_policy_service
*return_service
);
321 static necp_kernel_policy_id
necp_kernel_ip_output_policy_add(necp_policy_id parent_policy_id
, necp_policy_order order
, necp_policy_order suborder
, u_int32_t session_order
, u_int32_t condition_mask
, u_int32_t condition_negated_mask
, necp_kernel_policy_id cond_policy_id
, ifnet_t cond_bound_interface
, u_int32_t cond_last_interface_index
, u_int16_t cond_protocol
, union necp_sockaddr_union
*cond_local_start
, union necp_sockaddr_union
*cond_local_end
, u_int8_t cond_local_prefix
, union necp_sockaddr_union
*cond_remote_start
, union necp_sockaddr_union
*cond_remote_end
, u_int8_t cond_remote_prefix
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
);
322 static bool necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id
);
323 static bool necp_kernel_ip_output_policies_reprocess(void);
325 static bool necp_is_addr_in_range(struct sockaddr
*addr
, struct sockaddr
*range_start
, struct sockaddr
*range_end
);
326 static bool necp_is_range_in_range(struct sockaddr
*inner_range_start
, struct sockaddr
*inner_range_end
, struct sockaddr
*range_start
, struct sockaddr
*range_end
);
327 static bool necp_is_addr_in_subnet(struct sockaddr
*addr
, struct sockaddr
*subnet_addr
, u_int8_t subnet_prefix
);
328 static int necp_addr_compare(struct sockaddr
*sa1
, struct sockaddr
*sa2
, int check_port
);
329 static bool necp_buffer_compare_with_bit_prefix(u_int8_t
*p1
, u_int8_t
*p2
, u_int32_t bits
);
330 static bool necp_is_loopback(struct sockaddr
*local_addr
, struct sockaddr
*remote_addr
, struct inpcb
*inp
, struct mbuf
*packet
);
332 struct necp_uuid_id_mapping
{
333 LIST_ENTRY(necp_uuid_id_mapping
) chain
;
337 u_int32_t table_refcount
; // Add to UUID policy table count
339 static size_t necp_num_uuid_app_id_mappings
;
340 static bool necp_uuid_app_id_mappings_dirty
;
341 #define NECP_UUID_APP_ID_HASH_SIZE 64
342 static u_long necp_uuid_app_id_hash_mask
;
343 static u_long necp_uuid_app_id_hash_num_buckets
;
344 static LIST_HEAD(necp_uuid_id_mapping_head
, necp_uuid_id_mapping
) *necp_uuid_app_id_hashtbl
, necp_uuid_service_id_list
; // App map is real hash table, service map is just mapping
345 #define APPUUIDHASH(uuid) (&necp_uuid_app_id_hashtbl[uuid[0] & necp_uuid_app_id_hash_mask]) // Assume first byte of UUIDs are evenly distributed
346 static u_int32_t
necp_create_uuid_app_id_mapping(uuid_t uuid
, bool *allocated_mapping
, bool uuid_policy_table
);
347 static bool necp_remove_uuid_app_id_mapping(uuid_t uuid
, bool *removed_mapping
, bool uuid_policy_table
);
349 static struct necp_uuid_id_mapping
*necp_uuid_lookup_service_id_locked(uuid_t uuid
);
350 static struct necp_uuid_id_mapping
*necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id
);
351 static u_int32_t
necp_create_uuid_service_id_mapping(uuid_t uuid
);
352 static bool necp_remove_uuid_service_id_mapping(uuid_t uuid
);
354 struct necp_string_id_mapping
{
355 LIST_ENTRY(necp_string_id_mapping
) chain
;
360 static LIST_HEAD(necp_string_id_mapping_list
, necp_string_id_mapping
) necp_account_id_list
;
361 static u_int32_t
necp_create_string_to_id_mapping(struct necp_string_id_mapping_list
*list
, char *domain
);
362 static bool necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list
*list
, char *domain
);
364 static LIST_HEAD(_necp_kernel_service_list
, necp_service_registration
) necp_registered_service_list
;
366 static char *necp_create_trimmed_domain(char *string
, size_t length
);
367 static inline int necp_count_dots(char *string
, size_t length
);
369 // Session order allocation
371 necp_allocate_new_session_order(u_int32_t priority
, u_int32_t control_unit
)
373 u_int32_t new_order
= 0;
375 // For now, just allocate 1000 orders for each priority
376 if (priority
== NECP_SESSION_PRIORITY_UNKNOWN
|| priority
> NECP_SESSION_NUM_PRIORITIES
) {
377 priority
= NECP_SESSION_PRIORITY_DEFAULT
;
380 // Use the control unit to decide the offset into the priority list
381 new_order
= (control_unit
) + ((priority
- 1) * 1000);
386 static inline u_int32_t
387 necp_get_first_order_for_priority(u_int32_t priority
)
389 return (((priority
- 1) * 1000) + 1);
394 sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
396 #pragma unused(arg1, arg2)
397 int error
= sysctl_handle_int(oidp
, oidp
->oid_arg1
, oidp
->oid_arg2
, req
);
398 if (necp_drop_all_level
== 0) {
399 necp_drop_all_order
= 0;
401 necp_drop_all_order
= necp_get_first_order_for_priority(necp_drop_all_level
);
407 // Kernel Control functions
408 static errno_t
necp_register_control(void);
409 static errno_t
necp_ctl_connect(kern_ctl_ref kctlref
, struct sockaddr_ctl
*sac
, void **unitinfo
);
410 static errno_t
necp_ctl_disconnect(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
);
411 static errno_t
necp_ctl_send(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, mbuf_t m
, int flags
);
412 static void necp_ctl_rcvd(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, int flags
);
413 static errno_t
necp_ctl_getopt(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, int opt
, void *data
, size_t *len
);
414 static errno_t
necp_ctl_setopt(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, int opt
, void *data
, size_t len
);
416 static bool necp_send_ctl_data(struct necp_session
*session
, u_int8_t
*buffer
, size_t buffer_size
);
423 result
= necp_register_control();
428 necp_kernel_policy_grp_attr
= lck_grp_attr_alloc_init();
429 if (necp_kernel_policy_grp_attr
== NULL
) {
430 NECPLOG0(LOG_ERR
, "lck_grp_attr_alloc_init failed");
435 necp_kernel_policy_mtx_grp
= lck_grp_alloc_init(NECP_CONTROL_NAME
, necp_kernel_policy_grp_attr
);
436 if (necp_kernel_policy_mtx_grp
== NULL
) {
437 NECPLOG0(LOG_ERR
, "lck_grp_alloc_init failed");
442 necp_kernel_policy_mtx_attr
= lck_attr_alloc_init();
443 if (necp_kernel_policy_mtx_attr
== NULL
) {
444 NECPLOG0(LOG_ERR
, "lck_attr_alloc_init failed");
449 lck_rw_init(&necp_kernel_policy_lock
, necp_kernel_policy_mtx_grp
, necp_kernel_policy_mtx_attr
);
451 LIST_INIT(&necp_kernel_socket_policies
);
452 LIST_INIT(&necp_kernel_ip_output_policies
);
454 LIST_INIT(&necp_account_id_list
);
456 LIST_INIT(&necp_uuid_service_id_list
);
458 LIST_INIT(&necp_registered_service_list
);
460 necp_uuid_app_id_hashtbl
= hashinit(NECP_UUID_APP_ID_HASH_SIZE
, M_NECP
, &necp_uuid_app_id_hash_mask
);
461 necp_uuid_app_id_hash_num_buckets
= necp_uuid_app_id_hash_mask
+ 1;
462 necp_num_uuid_app_id_mappings
= 0;
463 necp_uuid_app_id_mappings_dirty
= FALSE
;
465 necp_kernel_application_policies_condition_mask
= 0;
466 necp_kernel_socket_policies_condition_mask
= 0;
467 necp_kernel_ip_output_policies_condition_mask
= 0;
469 necp_kernel_application_policies_count
= 0;
470 necp_kernel_socket_policies_count
= 0;
471 necp_kernel_socket_policies_non_app_count
= 0;
472 necp_kernel_ip_output_policies_count
= 0;
473 necp_kernel_ip_output_policies_non_id_count
= 0;
475 necp_last_policy_id
= 0;
476 necp_last_kernel_policy_id
= 0;
478 necp_kernel_socket_policies_gencount
= 1;
480 memset(&necp_kernel_socket_policies_map
, 0, sizeof(necp_kernel_socket_policies_map
));
481 memset(&necp_kernel_ip_output_policies_map
, 0, sizeof(necp_kernel_ip_output_policies_map
));
482 necp_kernel_socket_policies_app_layer_map
= NULL
;
486 if (necp_kernel_policy_mtx_attr
!= NULL
) {
487 lck_attr_free(necp_kernel_policy_mtx_attr
);
488 necp_kernel_policy_mtx_attr
= NULL
;
490 if (necp_kernel_policy_mtx_grp
!= NULL
) {
491 lck_grp_free(necp_kernel_policy_mtx_grp
);
492 necp_kernel_policy_mtx_grp
= NULL
;
494 if (necp_kernel_policy_grp_attr
!= NULL
) {
495 lck_grp_attr_free(necp_kernel_policy_grp_attr
);
496 necp_kernel_policy_grp_attr
= NULL
;
498 if (necp_kctlref
!= NULL
) {
499 ctl_deregister(necp_kctlref
);
507 necp_register_control(void)
509 struct kern_ctl_reg kern_ctl
;
512 // Create a tag to allocate memory
513 necp_malloc_tag
= OSMalloc_Tagalloc(NECP_CONTROL_NAME
, OSMT_DEFAULT
);
515 // Find a unique value for our interface family
516 result
= mbuf_tag_id_find(NECP_CONTROL_NAME
, &necp_family
);
518 NECPLOG(LOG_ERR
, "mbuf_tag_id_find_internal failed: %d", result
);
522 bzero(&kern_ctl
, sizeof(kern_ctl
));
523 strlcpy(kern_ctl
.ctl_name
, NECP_CONTROL_NAME
, sizeof(kern_ctl
.ctl_name
));
524 kern_ctl
.ctl_name
[sizeof(kern_ctl
.ctl_name
) - 1] = 0;
525 kern_ctl
.ctl_flags
= CTL_FLAG_PRIVILEGED
; // Require root
526 kern_ctl
.ctl_sendsize
= 64 * 1024;
527 kern_ctl
.ctl_recvsize
= 64 * 1024;
528 kern_ctl
.ctl_connect
= necp_ctl_connect
;
529 kern_ctl
.ctl_disconnect
= necp_ctl_disconnect
;
530 kern_ctl
.ctl_send
= necp_ctl_send
;
531 kern_ctl
.ctl_rcvd
= necp_ctl_rcvd
;
532 kern_ctl
.ctl_setopt
= necp_ctl_setopt
;
533 kern_ctl
.ctl_getopt
= necp_ctl_getopt
;
535 result
= ctl_register(&kern_ctl
, &necp_kctlref
);
537 NECPLOG(LOG_ERR
, "ctl_register failed: %d", result
);
545 necp_ctl_connect(kern_ctl_ref kctlref
, struct sockaddr_ctl
*sac
, void **unitinfo
)
547 #pragma unused(kctlref)
548 *unitinfo
= necp_create_session(sac
->sc_unit
);
549 if (*unitinfo
== NULL
) {
550 // Could not allocate session
558 necp_ctl_disconnect(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
)
560 #pragma unused(kctlref, unit)
561 struct necp_session
*session
= (struct necp_session
*)unitinfo
;
562 if (session
!= NULL
) {
563 necp_policy_mark_all_for_deletion(session
);
564 necp_policy_apply_all(session
);
565 necp_delete_session((struct necp_session
*)unitinfo
);
574 necp_packet_find_tlv(mbuf_t packet
, int offset
, u_int8_t type
, int *err
, int next
)
576 size_t cursor
= offset
;
585 error
= mbuf_copydata(packet
, cursor
, sizeof(curr_type
), &curr_type
);
592 curr_type
= NECP_TLV_NIL
;
595 if (curr_type
!= type
) {
596 cursor
+= sizeof(curr_type
);
597 error
= mbuf_copydata(packet
, cursor
, sizeof(curr_length
), &curr_length
);
602 cursor
+= (sizeof(curr_length
) + curr_length
);
604 } while (curr_type
!= type
);
610 necp_packet_get_tlv_at_offset(mbuf_t packet
, int tlv_offset
, size_t buff_len
, void *buff
, size_t *value_size
)
615 if (tlv_offset
< 0) {
619 error
= mbuf_copydata(packet
, tlv_offset
+ sizeof(u_int8_t
), sizeof(length
), &length
);
624 if (value_size
!= NULL
) {
625 *value_size
= length
;
628 if (buff
!= NULL
&& buff_len
> 0) {
629 size_t to_copy
= (length
< buff_len
) ? length
: buff_len
;
630 error
= mbuf_copydata(packet
, tlv_offset
+ sizeof(u_int8_t
) + sizeof(length
), to_copy
, buff
);
640 necp_packet_get_tlv(mbuf_t packet
, int offset
, u_int8_t type
, size_t buff_len
, void *buff
, size_t *value_size
)
645 tlv_offset
= necp_packet_find_tlv(packet
, offset
, type
, &error
, 0);
646 if (tlv_offset
< 0) {
650 return (necp_packet_get_tlv_at_offset(packet
, tlv_offset
, buff_len
, buff
, value_size
));
654 necp_buffer_write_packet_header(u_int8_t
*buffer
, u_int8_t packet_type
, u_int8_t flags
, u_int32_t message_id
)
656 ((struct necp_packet_header
*)(void *)buffer
)->packet_type
= packet_type
;
657 ((struct necp_packet_header
*)(void *)buffer
)->flags
= flags
;
658 ((struct necp_packet_header
*)(void *)buffer
)->message_id
= message_id
;
659 return (buffer
+ sizeof(struct necp_packet_header
));
663 necp_buffer_write_tlv(u_int8_t
*buffer
, u_int8_t type
, size_t length
, const void *value
)
665 *(u_int8_t
*)(buffer
) = type
;
666 *(size_t *)(void *)(buffer
+ sizeof(type
)) = length
;
668 memcpy((u_int8_t
*)(buffer
+ sizeof(type
) + sizeof(length
)), value
, length
);
671 return ((u_int8_t
*)(buffer
+ sizeof(type
) + sizeof(length
) + length
));
675 necp_buffer_get_tlv_type(u_int8_t
*buffer
, int tlv_offset
)
677 u_int8_t
*type
= NULL
;
679 if (buffer
== NULL
) {
683 type
= (u_int8_t
*)((u_int8_t
*)buffer
+ tlv_offset
);
684 return (type
? *type
: 0);
688 necp_buffer_get_tlv_length(u_int8_t
*buffer
, int tlv_offset
)
690 size_t *length
= NULL
;
692 if (buffer
== NULL
) {
696 length
= (size_t *)(void *)((u_int8_t
*)buffer
+ tlv_offset
+ sizeof(u_int8_t
));
697 return (length
? *length
: 0);
701 necp_buffer_get_tlv_value(u_int8_t
*buffer
, int tlv_offset
, size_t *value_size
)
703 u_int8_t
*value
= NULL
;
704 size_t length
= necp_buffer_get_tlv_length(buffer
, tlv_offset
);
710 *value_size
= length
;
713 value
= (u_int8_t
*)((u_int8_t
*)buffer
+ tlv_offset
+ sizeof(u_int8_t
) + sizeof(size_t));
718 necp_buffer_find_tlv(u_int8_t
*buffer
, size_t buffer_length
, int offset
, u_int8_t type
, int next
)
720 size_t cursor
= offset
;
725 if (cursor
>= buffer_length
) {
729 curr_type
= necp_buffer_get_tlv_type(buffer
, cursor
);
732 curr_type
= NECP_TLV_NIL
;
734 if (curr_type
!= type
) {
735 curr_length
= necp_buffer_get_tlv_length(buffer
, cursor
);
736 cursor
+= (sizeof(curr_type
) + sizeof(curr_length
) + curr_length
);
738 } while (curr_type
!= type
);
744 necp_send_ctl_data(struct necp_session
*session
, u_int8_t
*buffer
, size_t buffer_size
)
748 if (necp_kctlref
== NULL
|| session
== NULL
|| buffer
== NULL
|| buffer_size
== 0) {
752 error
= ctl_enqueuedata(necp_kctlref
, session
->control_unit
, buffer
, buffer_size
, CTL_DATA_EOR
);
758 necp_send_success_response(struct necp_session
*session
, u_int8_t packet_type
, u_int32_t message_id
)
761 u_int8_t
*response
= NULL
;
762 u_int8_t
*cursor
= NULL
;
763 size_t response_size
= sizeof(struct necp_packet_header
) + sizeof(u_int8_t
) + sizeof(size_t);
764 MALLOC(response
, u_int8_t
*, response_size
, M_NECP
, M_WAITOK
);
765 if (response
== NULL
) {
769 cursor
= necp_buffer_write_packet_header(cursor
, packet_type
, NECP_PACKET_FLAGS_RESPONSE
, message_id
);
770 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_NIL
, 0, NULL
);
772 if (!(success
= necp_send_ctl_data(session
, (u_int8_t
*)response
, response_size
))) {
773 NECPLOG0(LOG_ERR
, "Failed to send response");
776 FREE(response
, M_NECP
);
781 necp_send_error_response(struct necp_session
*session
, u_int8_t packet_type
, u_int32_t message_id
, u_int32_t error
)
784 u_int8_t
*response
= NULL
;
785 u_int8_t
*cursor
= NULL
;
786 size_t response_size
= sizeof(struct necp_packet_header
) + sizeof(u_int8_t
) + sizeof(size_t) + sizeof(u_int32_t
);
787 MALLOC(response
, u_int8_t
*, response_size
, M_NECP
, M_WAITOK
);
788 if (response
== NULL
) {
792 cursor
= necp_buffer_write_packet_header(cursor
, packet_type
, NECP_PACKET_FLAGS_RESPONSE
, message_id
);
793 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_ERROR
, sizeof(error
), &error
);
795 if (!(success
= necp_send_ctl_data(session
, (u_int8_t
*)response
, response_size
))) {
796 NECPLOG0(LOG_ERR
, "Failed to send response");
799 FREE(response
, M_NECP
);
804 necp_send_policy_id_response(struct necp_session
*session
, u_int8_t packet_type
, u_int32_t message_id
, necp_policy_id policy_id
)
807 u_int8_t
*response
= NULL
;
808 u_int8_t
*cursor
= NULL
;
809 size_t response_size
= sizeof(struct necp_packet_header
) + sizeof(u_int8_t
) + sizeof(size_t) + sizeof(u_int32_t
);
810 MALLOC(response
, u_int8_t
*, response_size
, M_NECP
, M_WAITOK
);
811 if (response
== NULL
) {
815 cursor
= necp_buffer_write_packet_header(cursor
, packet_type
, NECP_PACKET_FLAGS_RESPONSE
, message_id
);
816 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ID
, sizeof(policy_id
), &policy_id
);
818 if (!(success
= necp_send_ctl_data(session
, (u_int8_t
*)response
, response_size
))) {
819 NECPLOG0(LOG_ERR
, "Failed to send response");
822 FREE(response
, M_NECP
);
827 necp_ctl_send(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, mbuf_t packet
, int flags
)
829 #pragma unused(kctlref, unit, flags)
830 struct necp_session
*session
= (struct necp_session
*)unitinfo
;
831 struct necp_packet_header header
;
834 if (session
== NULL
) {
835 NECPLOG0(LOG_ERR
, "Got a NULL session");
840 if (mbuf_pkthdr_len(packet
) < sizeof(header
)) {
841 NECPLOG(LOG_ERR
, "Got a bad packet, length (%lu) < sizeof header (%lu)", mbuf_pkthdr_len(packet
), sizeof(header
));
846 error
= mbuf_copydata(packet
, 0, sizeof(header
), &header
);
848 NECPLOG(LOG_ERR
, "mbuf_copydata failed for the header: %d", error
);
853 if (session
->proc_locked
) {
854 // Verify that the calling process is allowed to send messages
856 proc_getexecutableuuid(current_proc(), proc_uuid
, sizeof(proc_uuid
));
857 if (uuid_compare(proc_uuid
, session
->proc_uuid
) != 0) {
858 necp_send_error_response(session
, header
.packet_type
, header
.message_id
, NECP_ERROR_INVALID_PROCESS
);
863 switch (header
.packet_type
) {
864 case NECP_PACKET_TYPE_POLICY_ADD
: {
865 necp_handle_policy_add(session
, header
.message_id
, packet
, sizeof(header
));
868 case NECP_PACKET_TYPE_POLICY_GET
: {
869 necp_handle_policy_get(session
, header
.message_id
, packet
, sizeof(header
));
872 case NECP_PACKET_TYPE_POLICY_DELETE
: {
873 necp_handle_policy_delete(session
, header
.message_id
, packet
, sizeof(header
));
876 case NECP_PACKET_TYPE_POLICY_APPLY_ALL
: {
877 necp_handle_policy_apply_all(session
, header
.message_id
, packet
, sizeof(header
));
880 case NECP_PACKET_TYPE_POLICY_LIST_ALL
: {
881 necp_handle_policy_list_all(session
, header
.message_id
, packet
, sizeof(header
));
884 case NECP_PACKET_TYPE_POLICY_DELETE_ALL
: {
885 necp_handle_policy_delete_all(session
, header
.message_id
, packet
, sizeof(header
));
888 case NECP_PACKET_TYPE_SET_SESSION_PRIORITY
: {
889 necp_handle_set_session_priority(session
, header
.message_id
, packet
, sizeof(header
));
892 case NECP_PACKET_TYPE_LOCK_SESSION_TO_PROC
: {
893 necp_handle_lock_session_to_proc(session
, header
.message_id
, packet
, sizeof(header
));
896 case NECP_PACKET_TYPE_REGISTER_SERVICE
: {
897 necp_handle_register_service(session
, header
.message_id
, packet
, sizeof(header
));
900 case NECP_PACKET_TYPE_UNREGISTER_SERVICE
: {
901 necp_handle_unregister_service(session
, header
.message_id
, packet
, sizeof(header
));
905 NECPLOG(LOG_ERR
, "Received unknown message type %d", header
.packet_type
);
906 necp_send_error_response(session
, header
.packet_type
, header
.message_id
, NECP_ERROR_UNKNOWN_PACKET_TYPE
);
917 necp_ctl_rcvd(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, int flags
)
919 #pragma unused(kctlref, unit, unitinfo, flags)
924 necp_ctl_getopt(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, int opt
, void *data
, size_t *len
)
926 #pragma unused(kctlref, unit, unitinfo, opt, data, len)
931 necp_ctl_setopt(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, int opt
, void *data
, size_t len
)
933 #pragma unused(kctlref, unit, unitinfo, opt, data, len)
937 // Session Management
938 static struct necp_session
*
939 necp_create_session(u_int32_t control_unit
)
941 struct necp_session
*new_session
= NULL
;
943 MALLOC(new_session
, struct necp_session
*, sizeof(*new_session
), M_NECP
, M_WAITOK
);
944 if (new_session
== NULL
) {
948 NECPLOG(LOG_DEBUG
, "Create NECP session, control unit %d", control_unit
);
950 memset(new_session
, 0, sizeof(*new_session
));
951 new_session
->session_priority
= NECP_SESSION_PRIORITY_UNKNOWN
;
952 new_session
->session_order
= necp_allocate_new_session_order(new_session
->session_priority
, control_unit
);
953 new_session
->control_unit
= control_unit
;
954 new_session
->dirty
= FALSE
;
955 LIST_INIT(&new_session
->policies
);
958 return (new_session
);
962 necp_delete_session(struct necp_session
*session
)
964 if (session
!= NULL
) {
965 struct necp_service_registration
*service
= NULL
;
966 struct necp_service_registration
*temp_service
= NULL
;
967 LIST_FOREACH_SAFE(service
, &session
->services
, session_chain
, temp_service
) {
968 LIST_REMOVE(service
, session_chain
);
969 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
970 LIST_REMOVE(service
, kernel_chain
);
971 lck_rw_done(&necp_kernel_policy_lock
);
972 FREE(service
, M_NECP
);
975 NECPLOG0(LOG_DEBUG
, "Deleted NECP session");
977 FREE(session
, M_NECP
);
981 // Session Policy Management
982 static inline u_int8_t
983 necp_policy_result_get_type_from_buffer(u_int8_t
*buffer
, size_t length
)
985 return ((buffer
&& length
>= sizeof(u_int8_t
)) ? buffer
[0] : 0);
989 necp_policy_result_get_parameter_length_from_buffer(u_int8_t
*buffer
, size_t length
)
991 return ((buffer
&& length
> sizeof(u_int8_t
)) ? (length
- sizeof(u_int8_t
)) : 0);
994 static inline u_int8_t
*
995 necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t
*buffer
, size_t length
)
997 return ((buffer
&& length
> sizeof(u_int8_t
)) ? (buffer
+ sizeof(u_int8_t
)) : NULL
);
1001 necp_policy_result_is_valid(u_int8_t
*buffer
, size_t length
)
1003 bool validated
= FALSE
;
1004 u_int8_t type
= necp_policy_result_get_type_from_buffer(buffer
, length
);
1005 size_t parameter_length
= necp_policy_result_get_parameter_length_from_buffer(buffer
, length
);
1007 case NECP_POLICY_RESULT_PASS
: {
1011 case NECP_POLICY_RESULT_SKIP
: {
1012 if (parameter_length
>= sizeof(u_int32_t
)) {
1017 case NECP_POLICY_RESULT_DROP
: {
1021 case NECP_POLICY_RESULT_SOCKET_DIVERT
: {
1022 if (parameter_length
>= sizeof(u_int32_t
)) {
1027 case NECP_POLICY_RESULT_SOCKET_SCOPED
: {
1028 if (parameter_length
> 0) {
1033 case NECP_POLICY_RESULT_IP_TUNNEL
: {
1034 if (parameter_length
> sizeof(u_int32_t
)) {
1039 case NECP_POLICY_RESULT_SOCKET_FILTER
: {
1040 if (parameter_length
>= sizeof(u_int32_t
)) {
1045 case NECP_POLICY_RESULT_TRIGGER
:
1046 case NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
:
1047 case NECP_POLICY_RESULT_TRIGGER_SCOPED
:
1048 case NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
: {
1049 if (parameter_length
>= sizeof(uuid_t
)) {
1061 NECPLOG(LOG_DEBUG
, "Policy result type %d, valid %d", type
, validated
);
1067 static inline u_int8_t
1068 necp_policy_condition_get_type_from_buffer(u_int8_t
*buffer
, size_t length
)
1070 return ((buffer
&& length
>= sizeof(u_int8_t
)) ? buffer
[0] : 0);
1073 static inline u_int8_t
1074 necp_policy_condition_get_flags_from_buffer(u_int8_t
*buffer
, size_t length
)
1076 return ((buffer
&& length
>= (2 * sizeof(u_int8_t
))) ? buffer
[1] : 0);
1079 static inline size_t
1080 necp_policy_condition_get_value_length_from_buffer(u_int8_t
*buffer
, size_t length
)
1082 return ((buffer
&& length
>= (2 * sizeof(u_int8_t
))) ? (length
- (2 * sizeof(u_int8_t
))) : 0);
1085 static inline u_int8_t
*
1086 necp_policy_condition_get_value_pointer_from_buffer(u_int8_t
*buffer
, size_t length
)
1088 return ((buffer
&& length
> (2 * sizeof(u_int8_t
))) ? (buffer
+ (2 * sizeof(u_int8_t
))) : NULL
);
1092 necp_policy_condition_is_default(u_int8_t
*buffer
, size_t length
)
1094 return (necp_policy_condition_get_type_from_buffer(buffer
, length
) == NECP_POLICY_CONDITION_DEFAULT
);
1098 necp_policy_condition_is_application(u_int8_t
*buffer
, size_t length
)
1100 return (necp_policy_condition_get_type_from_buffer(buffer
, length
) == NECP_POLICY_CONDITION_APPLICATION
);
1104 necp_policy_condition_requires_application(u_int8_t
*buffer
, size_t length
)
1106 u_int8_t type
= necp_policy_condition_get_type_from_buffer(buffer
, length
);
1107 return (type
== NECP_POLICY_CONDITION_REAL_APPLICATION
||
1108 type
== NECP_POLICY_CONDITION_ENTITLEMENT
);
1112 necp_policy_condition_is_valid(u_int8_t
*buffer
, size_t length
, u_int8_t policy_result_type
)
1114 bool validated
= FALSE
;
1115 bool result_cannot_have_ip_layer
= (policy_result_type
== NECP_POLICY_RESULT_SOCKET_DIVERT
||
1116 policy_result_type
== NECP_POLICY_RESULT_SOCKET_FILTER
||
1117 policy_result_type
== NECP_POLICY_RESULT_TRIGGER
||
1118 policy_result_type
== NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
||
1119 policy_result_type
== NECP_POLICY_RESULT_TRIGGER_SCOPED
||
1120 policy_result_type
== NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
||
1121 policy_result_type
== NECP_POLICY_RESULT_SOCKET_SCOPED
) ? TRUE
: FALSE
;
1122 size_t condition_length
= necp_policy_condition_get_value_length_from_buffer(buffer
, length
);
1123 u_int8_t
*condition_value
= necp_policy_condition_get_value_pointer_from_buffer(buffer
, length
);
1124 u_int8_t type
= necp_policy_condition_get_type_from_buffer(buffer
, length
);
1125 u_int8_t flags
= necp_policy_condition_get_flags_from_buffer(buffer
, length
);
1127 case NECP_POLICY_CONDITION_APPLICATION
:
1128 case NECP_POLICY_CONDITION_REAL_APPLICATION
: {
1129 if (!(flags
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
) &&
1130 condition_length
>= sizeof(uuid_t
) &&
1131 condition_value
!= NULL
&&
1132 !uuid_is_null(condition_value
)) {
1137 case NECP_POLICY_CONDITION_DOMAIN
:
1138 case NECP_POLICY_CONDITION_ACCOUNT
:
1139 case NECP_POLICY_CONDITION_BOUND_INTERFACE
: {
1140 if (condition_length
> 0) {
1145 case NECP_POLICY_CONDITION_TRAFFIC_CLASS
: {
1146 if (condition_length
>= sizeof(struct necp_policy_condition_tc_range
)) {
1151 case NECP_POLICY_CONDITION_DEFAULT
:
1152 case NECP_POLICY_CONDITION_ALL_INTERFACES
:
1153 case NECP_POLICY_CONDITION_ENTITLEMENT
: {
1154 if (!(flags
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
)) {
1159 case NECP_POLICY_CONDITION_IP_PROTOCOL
: {
1160 if (condition_length
>= sizeof(u_int16_t
)) {
1165 case NECP_POLICY_CONDITION_PID
: {
1166 if (condition_length
>= sizeof(pid_t
) &&
1167 condition_value
!= NULL
&&
1168 *((pid_t
*)(void *)condition_value
) != 0) {
1173 case NECP_POLICY_CONDITION_UID
: {
1174 if (condition_length
>= sizeof(uid_t
)) {
1179 case NECP_POLICY_CONDITION_LOCAL_ADDR
:
1180 case NECP_POLICY_CONDITION_REMOTE_ADDR
: {
1181 if (!result_cannot_have_ip_layer
&& condition_length
>= sizeof(struct necp_policy_condition_addr
)) {
1186 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE
:
1187 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE
: {
1188 if (!result_cannot_have_ip_layer
&& condition_length
>= sizeof(struct necp_policy_condition_addr_range
)) {
1200 NECPLOG(LOG_DEBUG
, "Policy condition type %d, valid %d", type
, validated
);
1207 necp_handle_set_session_priority(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1210 struct necp_session_policy
*policy
= NULL
;
1211 struct necp_session_policy
*temp_policy
= NULL
;
1212 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
1213 u_int32_t requested_session_priority
= NECP_SESSION_PRIORITY_UNKNOWN
;
1216 error
= necp_packet_get_tlv(packet
, offset
, NECP_TLV_SESSION_PRIORITY
, sizeof(requested_session_priority
), &requested_session_priority
, NULL
);
1218 NECPLOG(LOG_ERR
, "Failed to get session priority: %d", error
);
1219 response_error
= NECP_ERROR_INVALID_TLV
;
1223 if (session
== NULL
) {
1224 NECPLOG0(LOG_ERR
, "Failed to find session");
1225 response_error
= NECP_ERROR_INTERNAL
;
1229 // Enforce special session priorities with entitlements
1230 if (requested_session_priority
== NECP_SESSION_PRIORITY_CONTROL
||
1231 requested_session_priority
== NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL
) {
1232 errno_t cred_result
= priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES
, 0);
1233 if (cred_result
!= 0) {
1234 NECPLOG(LOG_ERR
, "Session does not hold necessary entitlement to claim priority level %d", requested_session_priority
);
1239 if (session
->session_priority
!= requested_session_priority
) {
1240 session
->session_priority
= requested_session_priority
;
1241 session
->session_order
= necp_allocate_new_session_order(session
->session_priority
, session
->control_unit
);
1242 session
->dirty
= TRUE
;
1244 // Mark all policies as needing updates
1245 LIST_FOREACH_SAFE(policy
, &session
->policies
, chain
, temp_policy
) {
1246 policy
->pending_update
= TRUE
;
1250 necp_send_success_response(session
, NECP_PACKET_TYPE_SET_SESSION_PRIORITY
, message_id
);
1254 necp_send_error_response(session
, NECP_PACKET_TYPE_SET_SESSION_PRIORITY
, message_id
, response_error
);
1258 necp_handle_lock_session_to_proc(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1260 #pragma unused(packet, offset)
1261 proc_getexecutableuuid(current_proc(), session
->proc_uuid
, sizeof(session
->proc_uuid
));
1262 session
->proc_locked
= TRUE
;
1263 necp_send_success_response(session
, NECP_PACKET_TYPE_LOCK_SESSION_TO_PROC
, message_id
);
1267 necp_handle_register_service(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1270 struct necp_service_registration
*new_service
= NULL
;
1271 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
1272 uuid_t service_uuid
;
1273 uuid_clear(service_uuid
);
1275 if (session
== NULL
) {
1276 NECPLOG0(LOG_ERR
, "Failed to find session");
1277 response_error
= NECP_ERROR_INTERNAL
;
1281 // Enforce entitlements
1282 errno_t cred_result
= priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES
, 0);
1283 if (cred_result
!= 0) {
1284 NECPLOG0(LOG_ERR
, "Session does not hold necessary entitlement to register service");
1288 // Read service uuid
1289 error
= necp_packet_get_tlv(packet
, offset
, NECP_TLV_SERVICE_UUID
, sizeof(uuid_t
), service_uuid
, NULL
);
1291 NECPLOG(LOG_ERR
, "Failed to get service UUID: %d", error
);
1292 response_error
= NECP_ERROR_INVALID_TLV
;
1296 MALLOC(new_service
, struct necp_service_registration
*, sizeof(*new_service
), M_NECP
, M_WAITOK
);
1297 if (new_service
== NULL
) {
1298 NECPLOG0(LOG_ERR
, "Failed to allocate service registration");
1299 response_error
= NECP_ERROR_INTERNAL
;
1303 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1304 memset(new_service
, 0, sizeof(*new_service
));
1305 new_service
->service_id
= necp_create_uuid_service_id_mapping(service_uuid
);
1306 LIST_INSERT_HEAD(&session
->services
, new_service
, session_chain
);
1307 LIST_INSERT_HEAD(&necp_registered_service_list
, new_service
, kernel_chain
);
1308 lck_rw_done(&necp_kernel_policy_lock
);
1310 necp_send_success_response(session
, NECP_PACKET_TYPE_REGISTER_SERVICE
, message_id
);
1313 necp_send_error_response(session
, NECP_PACKET_TYPE_REGISTER_SERVICE
, message_id
, response_error
);
1317 necp_handle_unregister_service(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1320 struct necp_service_registration
*service
= NULL
;
1321 struct necp_service_registration
*temp_service
= NULL
;
1322 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
1323 struct necp_uuid_id_mapping
*mapping
= NULL
;
1324 uuid_t service_uuid
;
1325 uuid_clear(service_uuid
);
1327 if (session
== NULL
) {
1328 NECPLOG0(LOG_ERR
, "Failed to find session");
1329 response_error
= NECP_ERROR_INTERNAL
;
1333 // Read service uuid
1334 error
= necp_packet_get_tlv(packet
, offset
, NECP_TLV_SERVICE_UUID
, sizeof(uuid_t
), service_uuid
, NULL
);
1336 NECPLOG(LOG_ERR
, "Failed to get service UUID: %d", error
);
1337 response_error
= NECP_ERROR_INVALID_TLV
;
1341 // Mark remove all matching services for this session
1342 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1343 mapping
= necp_uuid_lookup_service_id_locked(service_uuid
);
1344 if (mapping
!= NULL
) {
1345 LIST_FOREACH_SAFE(service
, &session
->services
, session_chain
, temp_service
) {
1346 if (service
->service_id
== mapping
->id
) {
1347 LIST_REMOVE(service
, session_chain
);
1348 LIST_REMOVE(service
, kernel_chain
);
1349 FREE(service
, M_NECP
);
1352 necp_remove_uuid_service_id_mapping(service_uuid
);
1354 lck_rw_done(&necp_kernel_policy_lock
);
1356 necp_send_success_response(session
, NECP_PACKET_TYPE_REGISTER_SERVICE
, message_id
);
1359 necp_send_error_response(session
, NECP_PACKET_TYPE_REGISTER_SERVICE
, message_id
, response_error
);
1363 necp_handle_policy_add(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1365 bool has_default_condition
= FALSE
;
1366 bool has_non_default_condition
= FALSE
;
1367 bool has_application_condition
= FALSE
;
1368 bool requires_application_condition
= FALSE
;
1369 u_int8_t
*conditions_array
= NULL
;
1370 size_t conditions_array_size
= 0;
1371 int conditions_array_cursor
;
1375 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
1377 necp_policy_order order
= 0;
1378 struct necp_session_policy
*policy
= NULL
;
1379 u_int8_t
*policy_result
= NULL
;
1380 size_t policy_result_size
= 0;
1382 // Read policy order
1383 error
= necp_packet_get_tlv(packet
, offset
, NECP_TLV_POLICY_ORDER
, sizeof(order
), &order
, NULL
);
1385 NECPLOG(LOG_ERR
, "Failed to get policy order: %d", error
);
1386 response_error
= NECP_ERROR_INVALID_TLV
;
1390 // Read policy result
1391 cursor
= necp_packet_find_tlv(packet
, offset
, NECP_TLV_POLICY_RESULT
, &error
, 0);
1392 error
= necp_packet_get_tlv_at_offset(packet
, cursor
, 0, NULL
, &policy_result_size
);
1393 if (error
|| policy_result_size
== 0) {
1394 NECPLOG(LOG_ERR
, "Failed to get policy result length: %d", error
);
1395 response_error
= NECP_ERROR_INVALID_TLV
;
1398 MALLOC(policy_result
, u_int8_t
*, policy_result_size
, M_NECP
, M_WAITOK
);
1399 if (policy_result
== NULL
) {
1400 NECPLOG(LOG_ERR
, "Failed to allocate a policy result buffer (size %d)", policy_result_size
);
1401 response_error
= NECP_ERROR_INTERNAL
;
1404 error
= necp_packet_get_tlv_at_offset(packet
, cursor
, policy_result_size
, policy_result
, NULL
);
1406 NECPLOG(LOG_ERR
, "Failed to get policy result: %d", error
);
1407 response_error
= NECP_ERROR_POLICY_RESULT_INVALID
;
1410 if (!necp_policy_result_is_valid(policy_result
, policy_result_size
)) {
1411 NECPLOG0(LOG_ERR
, "Failed to validate policy result");
1412 response_error
= NECP_ERROR_POLICY_RESULT_INVALID
;
1416 // Read policy conditions
1417 for (cursor
= necp_packet_find_tlv(packet
, offset
, NECP_TLV_POLICY_CONDITION
, &error
, 0);
1419 cursor
= necp_packet_find_tlv(packet
, cursor
, NECP_TLV_POLICY_CONDITION
, &error
, 1)) {
1420 size_t condition_size
= 0;
1421 necp_packet_get_tlv_at_offset(packet
, cursor
, 0, NULL
, &condition_size
);
1423 if (condition_size
> 0) {
1424 conditions_array_size
+= (sizeof(u_int8_t
) + sizeof(size_t) + condition_size
);
1428 if (conditions_array_size
== 0) {
1429 NECPLOG0(LOG_ERR
, "Failed to get policy conditions");
1430 response_error
= NECP_ERROR_INVALID_TLV
;
1433 MALLOC(conditions_array
, u_int8_t
*, conditions_array_size
, M_NECP
, M_WAITOK
);
1434 if (conditions_array
== NULL
) {
1435 NECPLOG(LOG_ERR
, "Failed to allocate a policy conditions array (size %d)", conditions_array_size
);
1436 response_error
= NECP_ERROR_INTERNAL
;
1440 conditions_array_cursor
= 0;
1441 for (cursor
= necp_packet_find_tlv(packet
, offset
, NECP_TLV_POLICY_CONDITION
, &error
, 0);
1443 cursor
= necp_packet_find_tlv(packet
, cursor
, NECP_TLV_POLICY_CONDITION
, &error
, 1)) {
1444 u_int8_t condition_type
= NECP_TLV_POLICY_CONDITION
;
1445 size_t condition_size
= 0;
1446 necp_packet_get_tlv_at_offset(packet
, cursor
, 0, NULL
, &condition_size
);
1447 if (condition_size
> 0 && condition_size
<= (conditions_array_size
- conditions_array_cursor
)) {
1449 memcpy((conditions_array
+ conditions_array_cursor
), &condition_type
, sizeof(condition_type
));
1450 conditions_array_cursor
+= sizeof(condition_type
);
1453 memcpy((conditions_array
+ conditions_array_cursor
), &condition_size
, sizeof(condition_size
));
1454 conditions_array_cursor
+= sizeof(condition_size
);
1457 necp_packet_get_tlv_at_offset(packet
, cursor
, condition_size
, (conditions_array
+ conditions_array_cursor
), NULL
);
1458 if (!necp_policy_condition_is_valid((conditions_array
+ conditions_array_cursor
), condition_size
, necp_policy_result_get_type_from_buffer(policy_result
, policy_result_size
))) {
1459 NECPLOG0(LOG_ERR
, "Failed to validate policy condition");
1460 response_error
= NECP_ERROR_POLICY_CONDITIONS_INVALID
;
1464 if (necp_policy_condition_is_default((conditions_array
+ conditions_array_cursor
), condition_size
)) {
1465 has_default_condition
= TRUE
;
1467 has_non_default_condition
= TRUE
;
1469 if (has_default_condition
&& has_non_default_condition
) {
1470 NECPLOG0(LOG_ERR
, "Failed to validate conditions; contained default and non-default conditions");
1471 response_error
= NECP_ERROR_POLICY_CONDITIONS_INVALID
;
1475 if (necp_policy_condition_is_application((conditions_array
+ conditions_array_cursor
), condition_size
)) {
1476 has_application_condition
= TRUE
;
1479 if (necp_policy_condition_requires_application((conditions_array
+ conditions_array_cursor
), condition_size
)) {
1480 requires_application_condition
= TRUE
;
1483 conditions_array_cursor
+= condition_size
;
1487 if (requires_application_condition
&& !has_application_condition
) {
1488 NECPLOG0(LOG_ERR
, "Failed to validate conditions; did not contain application condition");
1489 response_error
= NECP_ERROR_POLICY_CONDITIONS_INVALID
;
1493 if ((policy
= necp_policy_create(session
, order
, conditions_array
, conditions_array_size
, policy_result
, policy_result_size
)) == NULL
) {
1494 response_error
= NECP_ERROR_INTERNAL
;
1498 necp_send_policy_id_response(session
, NECP_PACKET_TYPE_POLICY_ADD
, message_id
, policy
->id
);
1502 if (policy_result
!= NULL
) {
1503 FREE(policy_result
, M_NECP
);
1505 if (conditions_array
!= NULL
) {
1506 FREE(conditions_array
, M_NECP
);
1509 necp_send_error_response(session
, NECP_PACKET_TYPE_POLICY_ADD
, message_id
, response_error
);
1513 necp_handle_policy_get(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1515 #pragma unused(offset)
1517 u_int8_t
*response
= NULL
;
1518 u_int8_t
*cursor
= NULL
;
1519 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
1520 necp_policy_id policy_id
= 0;
1521 size_t order_tlv_size
= 0;
1522 size_t result_tlv_size
= 0;
1523 size_t response_size
= 0;
1525 struct necp_session_policy
*policy
= NULL
;
1528 error
= necp_packet_get_tlv(packet
, offset
, NECP_TLV_POLICY_ID
, sizeof(policy_id
), &policy_id
, NULL
);
1530 NECPLOG(LOG_ERR
, "Failed to get policy id: %d", error
);
1531 response_error
= NECP_ERROR_INVALID_TLV
;
1535 policy
= necp_policy_find(session
, policy_id
);
1536 if (policy
== NULL
|| policy
->pending_deletion
) {
1537 NECPLOG(LOG_ERR
, "Failed to find policy with id %d", policy_id
);
1538 response_error
= NECP_ERROR_POLICY_ID_NOT_FOUND
;
1542 order_tlv_size
= sizeof(u_int8_t
) + sizeof(size_t) + sizeof(necp_policy_order
);
1543 result_tlv_size
= (policy
->result_size
? (sizeof(u_int8_t
) + sizeof(size_t) + policy
->result_size
) : 0);
1544 response_size
= sizeof(struct necp_packet_header
) + order_tlv_size
+ result_tlv_size
+ policy
->conditions_size
;
1545 MALLOC(response
, u_int8_t
*, response_size
, M_NECP
, M_WAITOK
);
1546 if (response
== NULL
) {
1547 necp_send_error_response(session
, NECP_PACKET_TYPE_POLICY_LIST_ALL
, message_id
, NECP_ERROR_INTERNAL
);
1552 cursor
= necp_buffer_write_packet_header(cursor
, NECP_PACKET_TYPE_POLICY_GET
, NECP_PACKET_FLAGS_RESPONSE
, message_id
);
1553 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ORDER
, sizeof(necp_policy_order
), &policy
->order
);
1555 if (result_tlv_size
) {
1556 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_RESULT
, policy
->result_size
, &policy
->result
);
1558 if (policy
->conditions_size
) {
1559 memcpy(((u_int8_t
*)(void *)(cursor
)), policy
->conditions
, policy
->conditions_size
);
1562 if (!necp_send_ctl_data(session
, (u_int8_t
*)response
, response_size
)) {
1563 NECPLOG0(LOG_ERR
, "Failed to send response");
1566 FREE(response
, M_NECP
);
1570 necp_send_error_response(session
, NECP_PACKET_TYPE_POLICY_GET
, message_id
, response_error
);
1574 necp_handle_policy_delete(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1577 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
1578 necp_policy_id policy_id
= 0;
1580 struct necp_session_policy
*policy
= NULL
;
1583 error
= necp_packet_get_tlv(packet
, offset
, NECP_TLV_POLICY_ID
, sizeof(policy_id
), &policy_id
, NULL
);
1585 NECPLOG(LOG_ERR
, "Failed to get policy id: %d", error
);
1586 response_error
= NECP_ERROR_INVALID_TLV
;
1590 policy
= necp_policy_find(session
, policy_id
);
1591 if (policy
== NULL
|| policy
->pending_deletion
) {
1592 NECPLOG(LOG_ERR
, "Failed to find policy with id %d", policy_id
);
1593 response_error
= NECP_ERROR_POLICY_ID_NOT_FOUND
;
1597 necp_policy_mark_for_deletion(session
, policy
);
1599 necp_send_success_response(session
, NECP_PACKET_TYPE_POLICY_DELETE
, message_id
);
1603 necp_send_error_response(session
, NECP_PACKET_TYPE_POLICY_DELETE
, message_id
, response_error
);
1607 necp_handle_policy_apply_all(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1609 #pragma unused(packet, offset)
1610 necp_policy_apply_all(session
);
1611 necp_send_success_response(session
, NECP_PACKET_TYPE_POLICY_APPLY_ALL
, message_id
);
1615 necp_handle_policy_list_all(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1617 #pragma unused(packet, offset)
1618 size_t tlv_size
= (sizeof(u_int8_t
) + sizeof(size_t) + sizeof(u_int32_t
));
1619 size_t response_size
= 0;
1620 u_int8_t
*response
= NULL
;
1621 u_int8_t
*cursor
= NULL
;
1622 int num_policies
= 0;
1623 int cur_policy_index
= 0;
1624 struct necp_session_policy
*policy
;
1626 LIST_FOREACH(policy
, &session
->policies
, chain
) {
1627 if (!policy
->pending_deletion
) {
1632 // Create a response with one Policy ID TLV for each policy
1633 response_size
= sizeof(struct necp_packet_header
) + num_policies
* tlv_size
;
1634 MALLOC(response
, u_int8_t
*, response_size
, M_NECP
, M_WAITOK
);
1635 if (response
== NULL
) {
1636 necp_send_error_response(session
, NECP_PACKET_TYPE_POLICY_LIST_ALL
, message_id
, NECP_ERROR_INTERNAL
);
1641 cursor
= necp_buffer_write_packet_header(cursor
, NECP_PACKET_TYPE_POLICY_LIST_ALL
, NECP_PACKET_FLAGS_RESPONSE
, message_id
);
1643 LIST_FOREACH(policy
, &session
->policies
, chain
) {
1644 if (!policy
->pending_deletion
&& cur_policy_index
< num_policies
) {
1645 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ID
, sizeof(u_int32_t
), &policy
->id
);
1650 if (!necp_send_ctl_data(session
, (u_int8_t
*)response
, response_size
)) {
1651 NECPLOG0(LOG_ERR
, "Failed to send response");
1654 FREE(response
, M_NECP
);
1658 necp_handle_policy_delete_all(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1660 #pragma unused(packet, offset)
1661 necp_policy_mark_all_for_deletion(session
);
1662 necp_send_success_response(session
, NECP_PACKET_TYPE_POLICY_DELETE_ALL
, message_id
);
1665 static necp_policy_id
1666 necp_policy_get_new_id(void)
1668 necp_policy_id newid
= 0;
1670 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1672 necp_last_policy_id
++;
1673 if (necp_last_policy_id
< 1) {
1674 necp_last_policy_id
= 1;
1677 newid
= necp_last_policy_id
;
1678 lck_rw_done(&necp_kernel_policy_lock
);
1681 NECPLOG0(LOG_DEBUG
, "Allocate policy id failed.\n");
1688 static struct necp_session_policy
*
1689 necp_policy_create(struct necp_session
*session
, necp_policy_order order
, u_int8_t
*conditions_array
, size_t conditions_array_size
, u_int8_t
*result
, size_t result_size
)
1691 struct necp_session_policy
*new_policy
= NULL
;
1692 struct necp_session_policy
*tmp_policy
= NULL
;
1694 if (session
== NULL
|| conditions_array
== NULL
|| result
== NULL
|| result_size
== 0) {
1698 MALLOC_ZONE(new_policy
, struct necp_session_policy
*, sizeof(*new_policy
), M_NECP_SESSION_POLICY
, M_WAITOK
);
1699 if (new_policy
== NULL
) {
1703 memset(new_policy
, 0, sizeof(*new_policy
));
1704 new_policy
->applied
= FALSE
;
1705 new_policy
->pending_deletion
= FALSE
;
1706 new_policy
->pending_update
= FALSE
;
1707 new_policy
->order
= order
;
1708 new_policy
->conditions
= conditions_array
;
1709 new_policy
->conditions_size
= conditions_array_size
;
1710 new_policy
->result
= result
;
1711 new_policy
->result_size
= result_size
;
1712 new_policy
->id
= necp_policy_get_new_id();
1714 LIST_INSERT_SORTED_ASCENDING(&session
->policies
, new_policy
, chain
, order
, tmp_policy
);
1716 session
->dirty
= TRUE
;
1719 NECPLOG(LOG_DEBUG
, "Created NECP policy, order %d", order
);
1722 return (new_policy
);
1725 static struct necp_session_policy
*
1726 necp_policy_find(struct necp_session
*session
, necp_policy_id policy_id
)
1728 struct necp_session_policy
*policy
= NULL
;
1729 if (policy_id
== 0) {
1733 LIST_FOREACH(policy
, &session
->policies
, chain
) {
1734 if (policy
->id
== policy_id
) {
1742 static inline u_int8_t
1743 necp_policy_get_result_type(struct necp_session_policy
*policy
)
1745 return (policy
? necp_policy_result_get_type_from_buffer(policy
->result
, policy
->result_size
) : 0);
1748 static inline size_t
1749 necp_policy_get_result_parameter_length(struct necp_session_policy
*policy
)
1751 return (policy
? necp_policy_result_get_parameter_length_from_buffer(policy
->result
, policy
->result_size
) : 0);
1755 necp_policy_get_result_parameter(struct necp_session_policy
*policy
, u_int8_t
*parameter_buffer
, size_t parameter_buffer_length
)
1758 size_t parameter_length
= necp_policy_result_get_parameter_length_from_buffer(policy
->result
, policy
->result_size
);
1759 if (parameter_buffer_length
>= parameter_length
) {
1760 u_int8_t
*parameter
= necp_policy_result_get_parameter_pointer_from_buffer(policy
->result
, policy
->result_size
);
1761 if (parameter
&& parameter_buffer
) {
1762 memcpy(parameter_buffer
, parameter
, parameter_length
);
1772 necp_policy_mark_for_deletion(struct necp_session
*session
, struct necp_session_policy
*policy
)
1774 if (session
== NULL
|| policy
== NULL
) {
1778 policy
->pending_deletion
= TRUE
;
1779 session
->dirty
= TRUE
;
1782 NECPLOG0(LOG_DEBUG
, "Marked NECP policy for removal");
1788 necp_policy_mark_all_for_deletion(struct necp_session
*session
)
1790 struct necp_session_policy
*policy
= NULL
;
1791 struct necp_session_policy
*temp_policy
= NULL
;
1793 LIST_FOREACH_SAFE(policy
, &session
->policies
, chain
, temp_policy
) {
1794 necp_policy_mark_for_deletion(session
, policy
);
1801 necp_policy_delete(struct necp_session
*session
, struct necp_session_policy
*policy
)
1803 if (session
== NULL
|| policy
== NULL
) {
1807 LIST_REMOVE(policy
, chain
);
1809 if (policy
->result
) {
1810 FREE(policy
->result
, M_NECP
);
1811 policy
->result
= NULL
;
1814 if (policy
->conditions
) {
1815 FREE(policy
->conditions
, M_NECP
);
1816 policy
->conditions
= NULL
;
1819 FREE_ZONE(policy
, sizeof(*policy
), M_NECP_SESSION_POLICY
);
1822 NECPLOG0(LOG_DEBUG
, "Removed NECP policy");
1828 necp_policy_unapply(struct necp_session_policy
*policy
)
1831 if (policy
== NULL
) {
1835 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
1837 // Release local uuid mappings
1838 if (!uuid_is_null(policy
->applied_app_uuid
)) {
1839 bool removed_mapping
= FALSE
;
1840 if (necp_remove_uuid_app_id_mapping(policy
->applied_app_uuid
, &removed_mapping
, TRUE
) && removed_mapping
) {
1841 necp_uuid_app_id_mappings_dirty
= TRUE
;
1842 necp_num_uuid_app_id_mappings
--;
1844 uuid_clear(policy
->applied_app_uuid
);
1846 if (!uuid_is_null(policy
->applied_real_app_uuid
)) {
1847 necp_remove_uuid_app_id_mapping(policy
->applied_real_app_uuid
, NULL
, FALSE
);
1848 uuid_clear(policy
->applied_real_app_uuid
);
1850 if (!uuid_is_null(policy
->applied_service_uuid
)) {
1851 necp_remove_uuid_service_id_mapping(policy
->applied_service_uuid
);
1852 uuid_clear(policy
->applied_service_uuid
);
1855 // Release string mappings
1856 if (policy
->applied_account
!= NULL
) {
1857 necp_remove_string_to_id_mapping(&necp_account_id_list
, policy
->applied_account
);
1858 FREE(policy
->applied_account
, M_NECP
);
1859 policy
->applied_account
= NULL
;
1862 // Remove socket policies
1863 for (i
= 0; i
< MAX_KERNEL_SOCKET_POLICIES
; i
++) {
1864 if (policy
->kernel_socket_policies
[i
] != 0) {
1865 necp_kernel_socket_policy_delete(policy
->kernel_socket_policies
[i
]);
1866 policy
->kernel_socket_policies
[i
] = 0;
1870 // Remove IP output policies
1871 for (i
= 0; i
< MAX_KERNEL_IP_OUTPUT_POLICIES
; i
++) {
1872 if (policy
->kernel_ip_output_policies
[i
] != 0) {
1873 necp_kernel_ip_output_policy_delete(policy
->kernel_ip_output_policies
[i
]);
1874 policy
->kernel_ip_output_policies
[i
] = 0;
1878 policy
->applied
= FALSE
;
1883 #define NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION 0
1884 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION 1
1885 #define NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION 2
1886 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS 3
1887 struct necp_policy_result_ip_tunnel
{
1888 u_int32_t secondary_result
;
1889 char interface_name
[IFXNAMSIZ
];
1890 } __attribute__((__packed__
));
1892 struct necp_policy_result_service
{
1895 } __attribute__((__packed__
));
1898 necp_policy_apply(struct necp_session
*session
, struct necp_session_policy
*policy
)
1900 bool socket_only_conditions
= FALSE
;
1901 bool socket_ip_conditions
= FALSE
;
1903 bool socket_layer_non_id_conditions
= FALSE
;
1904 bool ip_output_layer_non_id_conditions
= FALSE
;
1905 bool ip_output_layer_id_condition
= FALSE
;
1906 bool ip_output_layer_tunnel_condition_from_id
= FALSE
;
1907 bool ip_output_layer_tunnel_condition_from_non_id
= FALSE
;
1908 necp_kernel_policy_id cond_ip_output_layer_id
= NECP_KERNEL_POLICY_ID_NONE
;
1910 u_int32_t master_condition_mask
= 0;
1911 u_int32_t master_condition_negated_mask
= 0;
1912 ifnet_t cond_bound_interface
= NULL
;
1913 u_int32_t cond_account_id
= 0;
1914 char *cond_domain
= NULL
;
1917 necp_app_id cond_app_id
= 0;
1918 necp_app_id cond_real_app_id
= 0;
1919 struct necp_policy_condition_tc_range cond_traffic_class
;
1920 cond_traffic_class
.start_tc
= 0;
1921 cond_traffic_class
.end_tc
= 0;
1922 u_int16_t cond_protocol
= 0;
1923 union necp_sockaddr_union cond_local_start
;
1924 union necp_sockaddr_union cond_local_end
;
1925 u_int8_t cond_local_prefix
= 0;
1926 union necp_sockaddr_union cond_remote_start
;
1927 union necp_sockaddr_union cond_remote_end
;
1928 u_int8_t cond_remote_prefix
= 0;
1930 u_int8_t ultimate_result
= 0;
1931 u_int32_t secondary_result
= 0;
1932 necp_kernel_policy_result_parameter secondary_result_parameter
;
1933 memset(&secondary_result_parameter
, 0, sizeof(secondary_result_parameter
));
1934 u_int32_t cond_last_interface_index
= 0;
1935 necp_kernel_policy_result_parameter ultimate_result_parameter
;
1936 memset(&ultimate_result_parameter
, 0, sizeof(ultimate_result_parameter
));
1938 if (policy
== NULL
) {
1942 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
1944 // Process conditions
1945 while (offset
< policy
->conditions_size
) {
1947 u_int8_t
*value
= necp_buffer_get_tlv_value(policy
->conditions
, offset
, &length
);
1949 u_int8_t condition_type
= necp_policy_condition_get_type_from_buffer(value
, length
);
1950 u_int8_t condition_flags
= necp_policy_condition_get_flags_from_buffer(value
, length
);
1951 bool condition_is_negative
= condition_flags
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
;
1952 size_t condition_length
= necp_policy_condition_get_value_length_from_buffer(value
, length
);
1953 u_int8_t
*condition_value
= necp_policy_condition_get_value_pointer_from_buffer(value
, length
);
1954 switch (condition_type
) {
1955 case NECP_POLICY_CONDITION_DEFAULT
: {
1956 socket_ip_conditions
= TRUE
;
1959 case NECP_POLICY_CONDITION_ALL_INTERFACES
: {
1960 master_condition_mask
|= NECP_KERNEL_CONDITION_ALL_INTERFACES
;
1961 socket_ip_conditions
= TRUE
;
1964 case NECP_POLICY_CONDITION_ENTITLEMENT
: {
1965 master_condition_mask
|= NECP_KERNEL_CONDITION_ENTITLEMENT
;
1966 socket_only_conditions
= TRUE
;
1969 case NECP_POLICY_CONDITION_DOMAIN
: {
1970 // Make sure there is only one such rule
1971 if (condition_length
> 0 && cond_domain
== NULL
) {
1972 cond_domain
= necp_create_trimmed_domain((char *)condition_value
, condition_length
);
1973 if (cond_domain
!= NULL
) {
1974 master_condition_mask
|= NECP_KERNEL_CONDITION_DOMAIN
;
1975 if (condition_is_negative
) {
1976 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_DOMAIN
;
1978 socket_only_conditions
= TRUE
;
1983 case NECP_POLICY_CONDITION_ACCOUNT
: {
1984 // Make sure there is only one such rule
1985 if (condition_length
> 0 && cond_account_id
== 0 && policy
->applied_account
== NULL
) {
1986 char *string
= NULL
;
1987 MALLOC(string
, char *, condition_length
+ 1, M_NECP
, M_WAITOK
);
1988 if (string
!= NULL
) {
1989 memcpy(string
, condition_value
, condition_length
);
1990 string
[condition_length
] = 0;
1991 cond_account_id
= necp_create_string_to_id_mapping(&necp_account_id_list
, string
);
1992 if (cond_account_id
!= 0) {
1993 policy
->applied_account
= string
; // Save the string in parent policy
1994 master_condition_mask
|= NECP_KERNEL_CONDITION_ACCOUNT_ID
;
1995 if (condition_is_negative
) {
1996 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_ACCOUNT_ID
;
1998 socket_only_conditions
= TRUE
;
2000 FREE(string
, M_NECP
);
2006 case NECP_POLICY_CONDITION_APPLICATION
: {
2007 // Make sure there is only one such rule, because we save the uuid in the policy
2008 if (condition_length
>= sizeof(uuid_t
) && cond_app_id
== 0) {
2009 bool allocated_mapping
= FALSE
;
2010 uuid_t application_uuid
;
2011 memcpy(application_uuid
, condition_value
, sizeof(uuid_t
));
2012 cond_app_id
= necp_create_uuid_app_id_mapping(application_uuid
, &allocated_mapping
, TRUE
);
2013 if (cond_app_id
!= 0) {
2014 if (allocated_mapping
) {
2015 necp_uuid_app_id_mappings_dirty
= TRUE
;
2016 necp_num_uuid_app_id_mappings
++;
2018 uuid_copy(policy
->applied_app_uuid
, application_uuid
);
2019 master_condition_mask
|= NECP_KERNEL_CONDITION_APP_ID
;
2020 if (condition_is_negative
) {
2021 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_APP_ID
;
2023 socket_only_conditions
= TRUE
;
2028 case NECP_POLICY_CONDITION_REAL_APPLICATION
: {
2029 // Make sure there is only one such rule, because we save the uuid in the policy
2030 if (condition_length
>= sizeof(uuid_t
) && cond_real_app_id
== 0) {
2031 uuid_t real_application_uuid
;
2032 memcpy(real_application_uuid
, condition_value
, sizeof(uuid_t
));
2033 cond_real_app_id
= necp_create_uuid_app_id_mapping(real_application_uuid
, NULL
, FALSE
);
2034 if (cond_real_app_id
!= 0) {
2035 uuid_copy(policy
->applied_real_app_uuid
, real_application_uuid
);
2036 master_condition_mask
|= NECP_KERNEL_CONDITION_REAL_APP_ID
;
2037 if (condition_is_negative
) {
2038 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REAL_APP_ID
;
2040 socket_only_conditions
= TRUE
;
2045 case NECP_POLICY_CONDITION_PID
: {
2046 if (condition_length
>= sizeof(pid_t
)) {
2047 master_condition_mask
|= NECP_KERNEL_CONDITION_PID
;
2048 if (condition_is_negative
) {
2049 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_PID
;
2051 memcpy(&cond_pid
, condition_value
, sizeof(cond_pid
));
2052 socket_only_conditions
= TRUE
;
2056 case NECP_POLICY_CONDITION_UID
: {
2057 if (condition_length
>= sizeof(uid_t
)) {
2058 master_condition_mask
|= NECP_KERNEL_CONDITION_UID
;
2059 if (condition_is_negative
) {
2060 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_UID
;
2062 memcpy(&cond_uid
, condition_value
, sizeof(cond_uid
));
2063 socket_only_conditions
= TRUE
;
2067 case NECP_POLICY_CONDITION_TRAFFIC_CLASS
: {
2068 if (condition_length
>= sizeof(struct necp_policy_condition_tc_range
)) {
2069 master_condition_mask
|= NECP_KERNEL_CONDITION_TRAFFIC_CLASS
;
2070 if (condition_is_negative
) {
2071 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_TRAFFIC_CLASS
;
2073 memcpy(&cond_traffic_class
, condition_value
, sizeof(cond_traffic_class
));
2074 socket_only_conditions
= TRUE
;
2078 case NECP_POLICY_CONDITION_BOUND_INTERFACE
: {
2079 if (condition_length
<= IFXNAMSIZ
&& condition_length
> 0) {
2080 char interface_name
[IFXNAMSIZ
];
2081 memcpy(interface_name
, condition_value
, condition_length
);
2082 interface_name
[condition_length
- 1] = 0; // Make sure the string is NULL terminated
2083 if (ifnet_find_by_name(interface_name
, &cond_bound_interface
) == 0) {
2084 master_condition_mask
|= NECP_KERNEL_CONDITION_BOUND_INTERFACE
;
2085 if (condition_is_negative
) {
2086 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_BOUND_INTERFACE
;
2089 socket_ip_conditions
= TRUE
;
2093 case NECP_POLICY_CONDITION_IP_PROTOCOL
: {
2094 if (condition_length
>= sizeof(u_int16_t
)) {
2095 master_condition_mask
|= NECP_KERNEL_CONDITION_PROTOCOL
;
2096 if (condition_is_negative
) {
2097 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_PROTOCOL
;
2099 memcpy(&cond_protocol
, condition_value
, sizeof(cond_protocol
));
2100 socket_ip_conditions
= TRUE
;
2104 case NECP_POLICY_CONDITION_LOCAL_ADDR
: {
2105 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)condition_value
;
2106 cond_local_prefix
= address_struct
->prefix
;
2107 memcpy(&cond_local_start
, &address_struct
->address
, sizeof(address_struct
->address
));
2108 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_START
;
2109 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_PREFIX
;
2110 if (condition_is_negative
) {
2111 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_START
;
2112 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_PREFIX
;
2114 socket_ip_conditions
= TRUE
;
2117 case NECP_POLICY_CONDITION_REMOTE_ADDR
: {
2118 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)condition_value
;
2119 cond_remote_prefix
= address_struct
->prefix
;
2120 memcpy(&cond_remote_start
, &address_struct
->address
, sizeof(address_struct
->address
));
2121 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_START
;
2122 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_PREFIX
;
2123 if (condition_is_negative
) {
2124 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_START
;
2125 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_PREFIX
;
2127 socket_ip_conditions
= TRUE
;
2130 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE
: {
2131 struct necp_policy_condition_addr_range
*address_struct
= (struct necp_policy_condition_addr_range
*)(void *)condition_value
;
2132 memcpy(&cond_local_start
, &address_struct
->start_address
, sizeof(address_struct
->start_address
));
2133 memcpy(&cond_local_end
, &address_struct
->end_address
, sizeof(address_struct
->end_address
));
2134 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_START
;
2135 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_END
;
2136 if (condition_is_negative
) {
2137 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_START
;
2138 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_END
;
2140 socket_ip_conditions
= TRUE
;
2143 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE
: {
2144 struct necp_policy_condition_addr_range
*address_struct
= (struct necp_policy_condition_addr_range
*)(void *)condition_value
;
2145 memcpy(&cond_remote_start
, &address_struct
->start_address
, sizeof(address_struct
->start_address
));
2146 memcpy(&cond_remote_end
, &address_struct
->end_address
, sizeof(address_struct
->end_address
));
2147 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_START
;
2148 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_END
;
2149 if (condition_is_negative
) {
2150 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_START
;
2151 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_END
;
2153 socket_ip_conditions
= TRUE
;
2161 offset
+= sizeof(u_int8_t
) + sizeof(size_t) + length
;
2165 ultimate_result
= necp_policy_get_result_type(policy
);
2166 switch (ultimate_result
) {
2167 case NECP_POLICY_RESULT_PASS
: {
2168 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
2169 socket_layer_non_id_conditions
= TRUE
;
2170 ip_output_layer_id_condition
= TRUE
;
2171 } else if (socket_ip_conditions
) {
2172 socket_layer_non_id_conditions
= TRUE
;
2173 ip_output_layer_id_condition
= TRUE
;
2174 ip_output_layer_non_id_conditions
= TRUE
;
2178 case NECP_POLICY_RESULT_DROP
: {
2179 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
2180 socket_layer_non_id_conditions
= TRUE
;
2181 } else if (socket_ip_conditions
) {
2182 socket_layer_non_id_conditions
= TRUE
;
2183 ip_output_layer_non_id_conditions
= TRUE
;
2187 case NECP_POLICY_RESULT_SKIP
: {
2188 u_int32_t skip_policy_order
= 0;
2189 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&skip_policy_order
, sizeof(skip_policy_order
))) {
2190 ultimate_result_parameter
.skip_policy_order
= skip_policy_order
;
2193 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
2194 socket_layer_non_id_conditions
= TRUE
;
2195 ip_output_layer_id_condition
= TRUE
;
2196 } else if (socket_ip_conditions
) {
2197 socket_layer_non_id_conditions
= TRUE
;
2198 ip_output_layer_non_id_conditions
= TRUE
;
2202 case NECP_POLICY_RESULT_SOCKET_DIVERT
:
2203 case NECP_POLICY_RESULT_SOCKET_FILTER
: {
2204 u_int32_t control_unit
= 0;
2205 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&control_unit
, sizeof(control_unit
))) {
2206 ultimate_result_parameter
.flow_divert_control_unit
= control_unit
;
2208 socket_layer_non_id_conditions
= TRUE
;
2211 case NECP_POLICY_RESULT_IP_TUNNEL
: {
2212 struct necp_policy_result_ip_tunnel tunnel_parameters
;
2213 size_t tunnel_parameters_length
= necp_policy_get_result_parameter_length(policy
);
2214 if (tunnel_parameters_length
> sizeof(u_int32_t
) &&
2215 tunnel_parameters_length
<= sizeof(struct necp_policy_result_ip_tunnel
) &&
2216 necp_policy_get_result_parameter(policy
, (u_int8_t
*)&tunnel_parameters
, sizeof(tunnel_parameters
))) {
2217 ifnet_t tunnel_interface
= NULL
;
2218 tunnel_parameters
.interface_name
[tunnel_parameters_length
- sizeof(u_int32_t
) - 1] = 0; // Make sure the string is NULL terminated
2219 if (ifnet_find_by_name(tunnel_parameters
.interface_name
, &tunnel_interface
) == 0) {
2220 ultimate_result_parameter
.tunnel_interface_index
= tunnel_interface
->if_index
;
2223 secondary_result
= tunnel_parameters
.secondary_result
;
2224 if (secondary_result
) {
2225 cond_last_interface_index
= ultimate_result_parameter
.tunnel_interface_index
;
2229 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
2230 socket_layer_non_id_conditions
= TRUE
;
2231 ip_output_layer_id_condition
= TRUE
;
2232 if (secondary_result
) {
2233 ip_output_layer_tunnel_condition_from_id
= TRUE
;
2235 } else if (socket_ip_conditions
) {
2236 socket_layer_non_id_conditions
= TRUE
;
2237 ip_output_layer_id_condition
= TRUE
;
2238 ip_output_layer_non_id_conditions
= TRUE
;
2239 if (secondary_result
) {
2240 ip_output_layer_tunnel_condition_from_id
= TRUE
;
2241 ip_output_layer_tunnel_condition_from_non_id
= TRUE
;
2246 case NECP_POLICY_RESULT_TRIGGER
:
2247 case NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
:
2248 case NECP_POLICY_RESULT_TRIGGER_SCOPED
:
2249 case NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
: {
2250 struct necp_policy_result_service service_parameters
;
2251 size_t service_result_length
= necp_policy_get_result_parameter_length(policy
);
2252 bool has_extra_service_data
= FALSE
;
2253 if (service_result_length
>= (sizeof(service_parameters
))) {
2254 has_extra_service_data
= TRUE
;
2256 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&service_parameters
, sizeof(service_parameters
))) {
2257 ultimate_result_parameter
.service
.identifier
= necp_create_uuid_service_id_mapping(service_parameters
.identifier
);
2258 if (ultimate_result_parameter
.service
.identifier
!= 0) {
2259 uuid_copy(policy
->applied_service_uuid
, service_parameters
.identifier
);
2260 socket_layer_non_id_conditions
= TRUE
;
2261 if (has_extra_service_data
) {
2262 ultimate_result_parameter
.service
.data
= service_parameters
.data
;
2264 ultimate_result_parameter
.service
.data
= 0;
2270 case NECP_POLICY_RESULT_SOCKET_SCOPED
: {
2271 size_t interface_name_length
= necp_policy_get_result_parameter_length(policy
);
2272 if (interface_name_length
<= IFXNAMSIZ
&& interface_name_length
> 0) {
2273 char interface_name
[IFXNAMSIZ
];
2274 ifnet_t scope_interface
= NULL
;
2275 necp_policy_get_result_parameter(policy
, (u_int8_t
*)interface_name
, interface_name_length
);
2276 interface_name
[interface_name_length
- 1] = 0; // Make sure the string is NULL terminated
2277 if (ifnet_find_by_name(interface_name
, &scope_interface
) == 0) {
2278 ultimate_result_parameter
.scoped_interface_index
= scope_interface
->if_index
;
2279 socket_layer_non_id_conditions
= TRUE
;
2288 if (socket_layer_non_id_conditions
) {
2289 necp_kernel_policy_id policy_id
= necp_kernel_socket_policy_add(policy
->id
, policy
->order
, session
->session_order
, master_condition_mask
, master_condition_negated_mask
, cond_app_id
, cond_real_app_id
, cond_account_id
, cond_domain
, cond_pid
, cond_uid
, cond_bound_interface
, cond_traffic_class
, cond_protocol
, &cond_local_start
, &cond_local_end
, cond_local_prefix
, &cond_remote_start
, &cond_remote_end
, cond_remote_prefix
, ultimate_result
, ultimate_result_parameter
);
2291 if (policy_id
== 0) {
2292 NECPLOG0(LOG_DEBUG
, "Error applying socket kernel policy");
2296 cond_ip_output_layer_id
= policy_id
;
2297 policy
->kernel_socket_policies
[0] = policy_id
;
2300 if (ip_output_layer_non_id_conditions
) {
2301 necp_kernel_policy_id policy_id
= necp_kernel_ip_output_policy_add(policy
->id
, policy
->order
, NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS
, session
->session_order
, master_condition_mask
, master_condition_negated_mask
, NECP_KERNEL_POLICY_ID_NONE
, cond_bound_interface
, 0, cond_protocol
, &cond_local_start
, &cond_local_end
, cond_local_prefix
, &cond_remote_start
, &cond_remote_end
, cond_remote_prefix
, ultimate_result
, ultimate_result_parameter
);
2303 if (policy_id
== 0) {
2304 NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy");
2308 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS
] = policy_id
;
2311 if (ip_output_layer_id_condition
) {
2312 necp_kernel_policy_id policy_id
= necp_kernel_ip_output_policy_add(policy
->id
, policy
->order
, NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION
, session
->session_order
, NECP_KERNEL_CONDITION_POLICY_ID
| NECP_KERNEL_CONDITION_ALL_INTERFACES
, 0, cond_ip_output_layer_id
, NULL
, 0, 0, NULL
, NULL
, 0, NULL
, NULL
, 0, ultimate_result
, ultimate_result_parameter
);
2314 if (policy_id
== 0) {
2315 NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy");
2319 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION
] = policy_id
;
2322 // Extra policies for IP Output tunnels for when packets loop back
2323 if (ip_output_layer_tunnel_condition_from_id
) {
2324 necp_kernel_policy_id policy_id
= necp_kernel_ip_output_policy_add(policy
->id
, policy
->order
, NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION
, session
->session_order
, NECP_KERNEL_CONDITION_POLICY_ID
| NECP_KERNEL_CONDITION_LAST_INTERFACE
| NECP_KERNEL_CONDITION_ALL_INTERFACES
, 0, policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS
], NULL
, cond_last_interface_index
, 0, NULL
, NULL
, 0, NULL
, NULL
, 0, secondary_result
, secondary_result_parameter
);
2326 if (policy_id
== 0) {
2327 NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy");
2331 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION
] = policy_id
;
2334 if (ip_output_layer_tunnel_condition_from_id
) {
2335 necp_kernel_policy_id policy_id
= necp_kernel_ip_output_policy_add(policy
->id
, policy
->order
, NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION
, session
->session_order
, NECP_KERNEL_CONDITION_POLICY_ID
| NECP_KERNEL_CONDITION_LAST_INTERFACE
| NECP_KERNEL_CONDITION_ALL_INTERFACES
, 0, policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION
], NULL
, cond_last_interface_index
, 0, NULL
, NULL
, 0, NULL
, NULL
, 0, secondary_result
, secondary_result_parameter
);
2337 if (policy_id
== 0) {
2338 NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy");
2342 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION
] = policy_id
;
2345 policy
->applied
= TRUE
;
2346 policy
->pending_update
= FALSE
;
2354 necp_policy_apply_all(struct necp_session
*session
)
2356 struct necp_session_policy
*policy
= NULL
;
2357 struct necp_session_policy
*temp_policy
= NULL
;
2359 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
2361 // Remove exisiting applied policies
2362 if (session
->dirty
) {
2363 LIST_FOREACH_SAFE(policy
, &session
->policies
, chain
, temp_policy
) {
2364 if (policy
->pending_deletion
) {
2365 if (policy
->applied
) {
2366 necp_policy_unapply(policy
);
2368 // Delete the policy
2369 necp_policy_delete(session
, policy
);
2370 } else if (!policy
->applied
) {
2371 necp_policy_apply(session
, policy
);
2372 } else if (policy
->pending_update
) {
2373 // Must have been applied, but needs an update. Remove and re-add.
2374 necp_policy_unapply(policy
);
2375 necp_policy_apply(session
, policy
);
2379 necp_kernel_socket_policies_update_uuid_table();
2380 necp_kernel_socket_policies_reprocess();
2381 necp_kernel_ip_output_policies_reprocess();
2383 // Clear dirty bit flags
2384 session
->dirty
= FALSE
;
2387 lck_rw_done(&necp_kernel_policy_lock
);
2390 NECPLOG0(LOG_DEBUG
, "Applied NECP policies");
2394 // Kernel Policy Management
2395 // ---------------------
2396 // Kernel policies are derived from session policies
2397 static necp_kernel_policy_id
2398 necp_kernel_policy_get_new_id(void)
2400 necp_kernel_policy_id newid
= NECP_KERNEL_POLICY_ID_NONE
;
2402 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
2404 necp_last_kernel_policy_id
++;
2405 if (necp_last_kernel_policy_id
< NECP_KERNEL_POLICY_ID_FIRST_VALID
) {
2406 necp_last_kernel_policy_id
= NECP_KERNEL_POLICY_ID_FIRST_VALID
;
2409 newid
= necp_last_kernel_policy_id
;
2410 if (newid
== NECP_KERNEL_POLICY_ID_NONE
) {
2411 NECPLOG0(LOG_DEBUG
, "Allocate kernel policy id failed.\n");
2418 #define NECP_KERNEL_VALID_SOCKET_CONDITIONS (NECP_KERNEL_CONDITION_APP_ID | NECP_KERNEL_CONDITION_REAL_APP_ID | NECP_KERNEL_CONDITION_DOMAIN | NECP_KERNEL_CONDITION_ACCOUNT_ID | NECP_KERNEL_CONDITION_PID | NECP_KERNEL_CONDITION_UID | NECP_KERNEL_CONDITION_ALL_INTERFACES | NECP_KERNEL_CONDITION_BOUND_INTERFACE | NECP_KERNEL_CONDITION_TRAFFIC_CLASS | NECP_KERNEL_CONDITION_PROTOCOL | NECP_KERNEL_CONDITION_LOCAL_START | NECP_KERNEL_CONDITION_LOCAL_END | NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_REMOTE_START | NECP_KERNEL_CONDITION_REMOTE_END | NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_ENTITLEMENT)
2419 static necp_kernel_policy_id
2420 necp_kernel_socket_policy_add(necp_policy_id parent_policy_id
, necp_policy_order order
, u_int32_t session_order
, u_int32_t condition_mask
, u_int32_t condition_negated_mask
, necp_app_id cond_app_id
, necp_app_id cond_real_app_id
, u_int32_t cond_account_id
, char *cond_domain
, pid_t cond_pid
, uid_t cond_uid
, ifnet_t cond_bound_interface
, struct necp_policy_condition_tc_range cond_traffic_class
, u_int16_t cond_protocol
, union necp_sockaddr_union
*cond_local_start
, union necp_sockaddr_union
*cond_local_end
, u_int8_t cond_local_prefix
, union necp_sockaddr_union
*cond_remote_start
, union necp_sockaddr_union
*cond_remote_end
, u_int8_t cond_remote_prefix
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
)
2422 struct necp_kernel_socket_policy
*new_kernel_policy
= NULL
;
2423 struct necp_kernel_socket_policy
*tmp_kernel_policy
= NULL
;
2425 MALLOC_ZONE(new_kernel_policy
, struct necp_kernel_socket_policy
*, sizeof(*new_kernel_policy
), M_NECP_SOCKET_POLICY
, M_WAITOK
);
2426 if (new_kernel_policy
== NULL
) {
2430 memset(new_kernel_policy
, 0, sizeof(*new_kernel_policy
));
2431 new_kernel_policy
->parent_policy_id
= parent_policy_id
;
2432 new_kernel_policy
->id
= necp_kernel_policy_get_new_id();
2433 new_kernel_policy
->order
= order
;
2434 new_kernel_policy
->session_order
= session_order
;
2436 // Sanitize condition mask
2437 new_kernel_policy
->condition_mask
= (condition_mask
& NECP_KERNEL_VALID_SOCKET_CONDITIONS
);
2438 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
)) {
2439 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE
;
2441 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) && !(new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
)) {
2442 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_REAL_APP_ID
;
2444 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
) && !(new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
)) {
2445 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_ENTITLEMENT
;
2447 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
)) {
2448 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX
;
2450 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
)) {
2451 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX
;
2453 new_kernel_policy
->condition_negated_mask
= condition_negated_mask
& new_kernel_policy
->condition_mask
;
2455 // Set condition values
2456 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
2457 new_kernel_policy
->cond_app_id
= cond_app_id
;
2459 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
2460 new_kernel_policy
->cond_real_app_id
= cond_real_app_id
;
2462 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
2463 new_kernel_policy
->cond_account_id
= cond_account_id
;
2465 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
2466 new_kernel_policy
->cond_domain
= cond_domain
;
2467 new_kernel_policy
->cond_domain_dot_count
= necp_count_dots(cond_domain
, strlen(cond_domain
));
2469 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PID
) {
2470 new_kernel_policy
->cond_pid
= cond_pid
;
2472 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_UID
) {
2473 new_kernel_policy
->cond_uid
= cond_uid
;
2475 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
2476 if (cond_bound_interface
) {
2477 ifnet_reference(cond_bound_interface
);
2479 new_kernel_policy
->cond_bound_interface
= cond_bound_interface
;
2481 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
2482 new_kernel_policy
->cond_traffic_class
= cond_traffic_class
;
2484 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
2485 new_kernel_policy
->cond_protocol
= cond_protocol
;
2487 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
2488 memcpy(&new_kernel_policy
->cond_local_start
, cond_local_start
, cond_local_start
->sa
.sa_len
);
2490 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
2491 memcpy(&new_kernel_policy
->cond_local_end
, cond_local_end
, cond_local_end
->sa
.sa_len
);
2493 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
2494 new_kernel_policy
->cond_local_prefix
= cond_local_prefix
;
2496 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
2497 memcpy(&new_kernel_policy
->cond_remote_start
, cond_remote_start
, cond_remote_start
->sa
.sa_len
);
2499 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
2500 memcpy(&new_kernel_policy
->cond_remote_end
, cond_remote_end
, cond_remote_end
->sa
.sa_len
);
2502 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
2503 new_kernel_policy
->cond_remote_prefix
= cond_remote_prefix
;
2506 new_kernel_policy
->result
= result
;
2507 memcpy(&new_kernel_policy
->result_parameter
, &result_parameter
, sizeof(result_parameter
));
2510 NECPLOG(LOG_DEBUG
, "Added kernel policy: socket, id=%d, mask=%x\n", new_kernel_policy
->id
, new_kernel_policy
->condition_mask
);
2512 LIST_INSERT_SORTED_TWICE_ASCENDING(&necp_kernel_socket_policies
, new_kernel_policy
, chain
, session_order
, order
, tmp_kernel_policy
);
2514 return (new_kernel_policy
? new_kernel_policy
->id
: 0);
2517 static struct necp_kernel_socket_policy
*
2518 necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id
)
2520 struct necp_kernel_socket_policy
*kernel_policy
= NULL
;
2521 struct necp_kernel_socket_policy
*tmp_kernel_policy
= NULL
;
2523 if (policy_id
== 0) {
2527 LIST_FOREACH_SAFE(kernel_policy
, &necp_kernel_socket_policies
, chain
, tmp_kernel_policy
) {
2528 if (kernel_policy
->id
== policy_id
) {
2529 return (kernel_policy
);
2537 necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id
)
2539 struct necp_kernel_socket_policy
*policy
= NULL
;
2541 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
2543 policy
= necp_kernel_socket_policy_find(policy_id
);
2545 LIST_REMOVE(policy
, chain
);
2547 if (policy
->cond_bound_interface
) {
2548 ifnet_release(policy
->cond_bound_interface
);
2549 policy
->cond_bound_interface
= NULL
;
2552 if (policy
->cond_domain
) {
2553 FREE(policy
->cond_domain
, M_NECP
);
2554 policy
->cond_domain
= NULL
;
2557 FREE_ZONE(policy
, sizeof(*policy
), M_NECP_SOCKET_POLICY
);
2565 necp_kernel_socket_policies_dump_all(void)
2567 struct necp_kernel_socket_policy
*policy
= NULL
;
2572 NECPLOG0(LOG_DEBUG
, "NECP Application Policies:\n");
2573 NECPLOG0(LOG_DEBUG
, "-----------\n");
2574 for (policy_i
= 0; necp_kernel_socket_policies_app_layer_map
!= NULL
&& necp_kernel_socket_policies_app_layer_map
[policy_i
] != NULL
; policy_i
++) {
2575 policy
= necp_kernel_socket_policies_app_layer_map
[policy_i
];
2576 NECPLOG(LOG_DEBUG
, "\t%d. Policy ID: %d, Order: %d.%d, Mask: %x, Result: %d, Parameter: %d\n", policy_i
, policy
->id
, policy
->session_order
, policy
->order
, policy
->condition_mask
, policy
->result
, policy
->result_parameter
);
2578 if (necp_kernel_socket_policies_app_layer_map
[0] != NULL
) {
2579 NECPLOG0(LOG_DEBUG
, "-----------\n");
2582 NECPLOG0(LOG_DEBUG
, "NECP Socket Policies:\n");
2583 NECPLOG0(LOG_DEBUG
, "-----------\n");
2584 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
2585 NECPLOG(LOG_DEBUG
, "\tApp Bucket: %d\n", app_i
);
2586 for (policy_i
= 0; necp_kernel_socket_policies_map
[app_i
] != NULL
&& (necp_kernel_socket_policies_map
[app_i
])[policy_i
] != NULL
; policy_i
++) {
2587 policy
= (necp_kernel_socket_policies_map
[app_i
])[policy_i
];
2588 NECPLOG(LOG_DEBUG
, "\t%d. Policy ID: %d, Order: %d.%d, Mask: %x, Result: %d, Parameter: %d\n", policy_i
, policy
->id
, policy
->session_order
, policy
->order
, policy
->condition_mask
, policy
->result
, policy
->result_parameter
);
2590 NECPLOG0(LOG_DEBUG
, "-----------\n");
2596 necp_kernel_socket_result_is_service_type(struct necp_kernel_socket_policy
*kernel_policy
)
2598 return (kernel_policy
->result
>= NECP_KERNEL_POLICY_RESULT_TRIGGER
&& kernel_policy
->result
<= NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED
);
2602 necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy
*upper_policy
, struct necp_kernel_socket_policy
*lower_policy
)
2604 if (upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_DROP
) {
2605 // Drop always cancels out lower policies
2607 } else if (upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER
) {
2608 // Filters never cancel out lower policies
2610 } else if (necp_kernel_socket_result_is_service_type(upper_policy
)) {
2611 // Trigger/Scoping policies can overlap one another, but not other results
2612 return (necp_kernel_socket_result_is_service_type(lower_policy
));
2613 } else if (upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
2614 if (upper_policy
->session_order
!= lower_policy
->session_order
) {
2615 // A skip cannot override a policy of a different session
2618 if (upper_policy
->result_parameter
.skip_policy_order
== 0 ||
2619 lower_policy
->order
>= upper_policy
->result_parameter
.skip_policy_order
) {
2620 // This policy is beyond the skip
2623 // This policy is inside the skip
2629 // A hard pass, flow divert, or tunnel will currently block out lower policies
2634 necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy
*policy
, struct necp_kernel_socket_policy
**policy_array
, int valid_indices
)
2636 bool can_skip
= FALSE
;
2637 u_int32_t highest_skip_session_order
= 0;
2638 u_int32_t highest_skip_order
= 0;
2640 for (i
= 0; i
< valid_indices
; i
++) {
2641 struct necp_kernel_socket_policy
*compared_policy
= policy_array
[i
];
2643 // For policies in a skip window, we can't mark conflicting policies as unnecessary
2645 if (highest_skip_session_order
!= compared_policy
->session_order
||
2646 (highest_skip_order
!= 0 && compared_policy
->order
>= highest_skip_order
)) {
2647 // If we've moved on to the next session, or passed the skip window
2648 highest_skip_session_order
= 0;
2649 highest_skip_order
= 0;
2652 // If this policy is also a skip, in can increase the skip window
2653 if (compared_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
2654 if (compared_policy
->result_parameter
.skip_policy_order
> highest_skip_order
) {
2655 highest_skip_order
= compared_policy
->result_parameter
.skip_policy_order
;
2662 if (compared_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
2663 // This policy is a skip. Set the skip window accordingly
2665 highest_skip_session_order
= compared_policy
->session_order
;
2666 highest_skip_order
= compared_policy
->result_parameter
.skip_policy_order
;
2669 // The result of the compared policy must be able to block out this policy result
2670 if (!necp_kernel_socket_policy_results_overlap(compared_policy
, policy
)) {
2674 // If new policy matches All Interfaces, compared policy must also
2675 if ((policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && !(compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) {
2679 // Default makes lower policies unecessary always
2680 if (compared_policy
->condition_mask
== 0) {
2684 // Compared must be more general than policy, and include only conditions within policy
2685 if ((policy
->condition_mask
& compared_policy
->condition_mask
) != compared_policy
->condition_mask
) {
2689 // Negative conditions must match for the overlapping conditions
2690 if ((policy
->condition_negated_mask
& compared_policy
->condition_mask
) != (compared_policy
->condition_negated_mask
& compared_policy
->condition_mask
)) {
2694 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
&&
2695 strcmp(compared_policy
->cond_domain
, policy
->cond_domain
) != 0) {
2699 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
&&
2700 compared_policy
->cond_account_id
!= policy
->cond_account_id
) {
2704 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
&&
2705 compared_policy
->cond_policy_id
!= policy
->cond_policy_id
) {
2709 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
&&
2710 compared_policy
->cond_app_id
!= policy
->cond_app_id
) {
2714 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
&&
2715 compared_policy
->cond_real_app_id
!= policy
->cond_real_app_id
) {
2719 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_PID
&&
2720 compared_policy
->cond_pid
!= policy
->cond_pid
) {
2724 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_UID
&&
2725 compared_policy
->cond_uid
!= policy
->cond_uid
) {
2729 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
&&
2730 compared_policy
->cond_bound_interface
!= policy
->cond_bound_interface
) {
2734 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
&&
2735 compared_policy
->cond_protocol
!= policy
->cond_protocol
) {
2739 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
&&
2740 !(compared_policy
->cond_traffic_class
.start_tc
<= policy
->cond_traffic_class
.start_tc
&&
2741 compared_policy
->cond_traffic_class
.end_tc
>= policy
->cond_traffic_class
.end_tc
)) {
2745 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
2746 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
2747 if (!necp_is_range_in_range((struct sockaddr
*)&policy
->cond_local_start
, (struct sockaddr
*)&policy
->cond_local_end
, (struct sockaddr
*)&compared_policy
->cond_local_start
, (struct sockaddr
*)&compared_policy
->cond_local_end
)) {
2750 } else if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
2751 if (compared_policy
->cond_local_prefix
> policy
->cond_local_prefix
||
2752 !necp_is_addr_in_subnet((struct sockaddr
*)&policy
->cond_local_start
, (struct sockaddr
*)&compared_policy
->cond_local_start
, compared_policy
->cond_local_prefix
)) {
2758 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
2759 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
2760 if (!necp_is_range_in_range((struct sockaddr
*)&policy
->cond_remote_start
, (struct sockaddr
*)&policy
->cond_remote_end
, (struct sockaddr
*)&compared_policy
->cond_remote_start
, (struct sockaddr
*)&compared_policy
->cond_remote_end
)) {
2763 } else if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
2764 if (compared_policy
->cond_remote_prefix
> policy
->cond_remote_prefix
||
2765 !necp_is_addr_in_subnet((struct sockaddr
*)&policy
->cond_remote_start
, (struct sockaddr
*)&compared_policy
->cond_remote_start
, compared_policy
->cond_remote_prefix
)) {
2778 necp_kernel_socket_policies_reprocess(void)
2781 int bucket_allocation_counts
[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
];
2782 int bucket_current_free_index
[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
];
2783 int app_layer_allocation_count
= 0;
2784 int app_layer_current_free_index
= 0;
2785 struct necp_kernel_socket_policy
*kernel_policy
= NULL
;
2787 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
2790 necp_kernel_application_policies_condition_mask
= 0;
2791 necp_kernel_socket_policies_condition_mask
= 0;
2792 necp_kernel_application_policies_count
= 0;
2793 necp_kernel_socket_policies_count
= 0;
2794 necp_kernel_socket_policies_non_app_count
= 0;
2796 // Reset all maps to NULL
2797 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
2798 if (necp_kernel_socket_policies_map
[app_i
] != NULL
) {
2799 FREE(necp_kernel_socket_policies_map
[app_i
], M_NECP
);
2800 necp_kernel_socket_policies_map
[app_i
] = NULL
;
2804 bucket_allocation_counts
[app_i
] = 0;
2806 if (necp_kernel_socket_policies_app_layer_map
!= NULL
) {
2807 FREE(necp_kernel_socket_policies_app_layer_map
, M_NECP
);
2808 necp_kernel_socket_policies_app_layer_map
= NULL
;
2811 // Create masks and counts
2812 LIST_FOREACH(kernel_policy
, &necp_kernel_socket_policies
, chain
) {
2813 // App layer mask/count
2814 necp_kernel_application_policies_condition_mask
|= kernel_policy
->condition_mask
;
2815 necp_kernel_application_policies_count
++;
2816 app_layer_allocation_count
++;
2818 // Update socket layer bucket mask/counts
2819 necp_kernel_socket_policies_condition_mask
|= kernel_policy
->condition_mask
;
2820 necp_kernel_socket_policies_count
++;
2822 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) ||
2823 kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
2824 necp_kernel_socket_policies_non_app_count
++;
2825 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
2826 bucket_allocation_counts
[app_i
]++;
2829 bucket_allocation_counts
[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy
->cond_app_id
)]++;
2834 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
2835 if (bucket_allocation_counts
[app_i
] > 0) {
2836 // Allocate a NULL-terminated array of policy pointers for each bucket
2837 MALLOC(necp_kernel_socket_policies_map
[app_i
], struct necp_kernel_socket_policy
**, sizeof(struct necp_kernel_socket_policy
*) * (bucket_allocation_counts
[app_i
] + 1), M_NECP
, M_WAITOK
);
2838 if (necp_kernel_socket_policies_map
[app_i
] == NULL
) {
2842 // Initialize the first entry to NULL
2843 (necp_kernel_socket_policies_map
[app_i
])[0] = NULL
;
2845 bucket_current_free_index
[app_i
] = 0;
2847 MALLOC(necp_kernel_socket_policies_app_layer_map
, struct necp_kernel_socket_policy
**, sizeof(struct necp_kernel_socket_policy
*) * (app_layer_allocation_count
+ 1), M_NECP
, M_WAITOK
);
2848 if (necp_kernel_socket_policies_app_layer_map
== NULL
) {
2851 necp_kernel_socket_policies_app_layer_map
[0] = NULL
;
2854 LIST_FOREACH(kernel_policy
, &necp_kernel_socket_policies
, chain
) {
2855 // Insert pointers into map
2856 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) ||
2857 kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
2858 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
2859 if (!necp_kernel_socket_policy_is_unnecessary(kernel_policy
, necp_kernel_socket_policies_map
[app_i
], bucket_current_free_index
[app_i
])) {
2860 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = kernel_policy
;
2861 bucket_current_free_index
[app_i
]++;
2862 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = NULL
;
2866 app_i
= NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy
->cond_app_id
);
2867 if (!necp_kernel_socket_policy_is_unnecessary(kernel_policy
, necp_kernel_socket_policies_map
[app_i
], bucket_current_free_index
[app_i
])) {
2868 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = kernel_policy
;
2869 bucket_current_free_index
[app_i
]++;
2870 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = NULL
;
2874 if (!necp_kernel_socket_policy_is_unnecessary(kernel_policy
, necp_kernel_socket_policies_app_layer_map
, app_layer_current_free_index
)) {
2875 necp_kernel_socket_policies_app_layer_map
[app_layer_current_free_index
] = kernel_policy
;
2876 app_layer_current_free_index
++;
2877 necp_kernel_socket_policies_app_layer_map
[app_layer_current_free_index
] = NULL
;
2880 necp_kernel_socket_policies_dump_all();
2881 BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT();
2885 // Free memory, reset masks to 0
2886 necp_kernel_application_policies_condition_mask
= 0;
2887 necp_kernel_socket_policies_condition_mask
= 0;
2888 necp_kernel_application_policies_count
= 0;
2889 necp_kernel_socket_policies_count
= 0;
2890 necp_kernel_socket_policies_non_app_count
= 0;
2891 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
2892 if (necp_kernel_socket_policies_map
[app_i
] != NULL
) {
2893 FREE(necp_kernel_socket_policies_map
[app_i
], M_NECP
);
2894 necp_kernel_socket_policies_map
[app_i
] = NULL
;
2897 if (necp_kernel_socket_policies_app_layer_map
!= NULL
) {
2898 FREE(necp_kernel_socket_policies_app_layer_map
, M_NECP
);
2899 necp_kernel_socket_policies_app_layer_map
= NULL
;
2905 necp_get_new_string_id(void)
2907 u_int32_t newid
= 0;
2909 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
2911 necp_last_string_id
++;
2912 if (necp_last_string_id
< 1) {
2913 necp_last_string_id
= 1;
2916 newid
= necp_last_string_id
;
2918 NECPLOG0(LOG_DEBUG
, "Allocate string id failed.\n");
2925 static struct necp_string_id_mapping
*
2926 necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list
*list
, char *string
)
2928 struct necp_string_id_mapping
*searchentry
= NULL
;
2929 struct necp_string_id_mapping
*foundentry
= NULL
;
2931 LIST_FOREACH(searchentry
, list
, chain
) {
2932 if (strcmp(searchentry
->string
, string
) == 0) {
2933 foundentry
= searchentry
;
2938 return (foundentry
);
2942 necp_create_string_to_id_mapping(struct necp_string_id_mapping_list
*list
, char *string
)
2944 u_int32_t string_id
= 0;
2945 struct necp_string_id_mapping
*existing_mapping
= NULL
;
2947 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
2949 existing_mapping
= necp_lookup_string_to_id_locked(list
, string
);
2950 if (existing_mapping
!= NULL
) {
2951 string_id
= existing_mapping
->id
;
2952 existing_mapping
->refcount
++;
2954 struct necp_string_id_mapping
*new_mapping
= NULL
;
2955 MALLOC(new_mapping
, struct necp_string_id_mapping
*, sizeof(struct necp_string_id_mapping
), M_NECP
, M_WAITOK
);
2956 if (new_mapping
!= NULL
) {
2957 memset(new_mapping
, 0, sizeof(struct necp_string_id_mapping
));
2959 size_t length
= strlen(string
) + 1;
2960 MALLOC(new_mapping
->string
, char *, length
, M_NECP
, M_WAITOK
);
2961 if (new_mapping
->string
!= NULL
) {
2962 memcpy(new_mapping
->string
, string
, length
);
2963 new_mapping
->id
= necp_get_new_string_id();
2964 new_mapping
->refcount
= 1;
2965 LIST_INSERT_HEAD(list
, new_mapping
, chain
);
2966 string_id
= new_mapping
->id
;
2968 FREE(new_mapping
, M_NECP
);
2977 necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list
*list
, char *string
)
2979 struct necp_string_id_mapping
*existing_mapping
= NULL
;
2981 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
2983 existing_mapping
= necp_lookup_string_to_id_locked(list
, string
);
2984 if (existing_mapping
!= NULL
) {
2985 if (--existing_mapping
->refcount
== 0) {
2986 LIST_REMOVE(existing_mapping
, chain
);
2987 FREE(existing_mapping
->string
, M_NECP
);
2988 FREE(existing_mapping
, M_NECP
);
2996 #define NECP_NULL_SERVICE_ID 1
2998 necp_get_new_uuid_id(void)
3000 u_int32_t newid
= 0;
3002 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
3004 necp_last_uuid_id
++;
3005 if (necp_last_uuid_id
< (NECP_NULL_SERVICE_ID
+ 1)) {
3006 necp_last_uuid_id
= (NECP_NULL_SERVICE_ID
+ 1);
3009 newid
= necp_last_uuid_id
;
3011 NECPLOG0(LOG_DEBUG
, "Allocate uuid id failed.\n");
3018 static struct necp_uuid_id_mapping
*
3019 necp_uuid_lookup_app_id_locked(uuid_t uuid
)
3021 struct necp_uuid_id_mapping
*searchentry
= NULL
;
3022 struct necp_uuid_id_mapping
*foundentry
= NULL
;
3024 LIST_FOREACH(searchentry
, APPUUIDHASH(uuid
), chain
) {
3025 if (uuid_compare(searchentry
->uuid
, uuid
) == 0) {
3026 foundentry
= searchentry
;
3031 return (foundentry
);
3035 necp_create_uuid_app_id_mapping(uuid_t uuid
, bool *allocated_mapping
, bool uuid_policy_table
)
3037 u_int32_t local_id
= 0;
3038 struct necp_uuid_id_mapping
*existing_mapping
= NULL
;
3040 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
3042 if (allocated_mapping
) {
3043 *allocated_mapping
= FALSE
;
3046 existing_mapping
= necp_uuid_lookup_app_id_locked(uuid
);
3047 if (existing_mapping
!= NULL
) {
3048 local_id
= existing_mapping
->id
;
3049 existing_mapping
->refcount
++;
3050 if (uuid_policy_table
) {
3051 existing_mapping
->table_refcount
++;
3054 struct necp_uuid_id_mapping
*new_mapping
= NULL
;
3055 MALLOC(new_mapping
, struct necp_uuid_id_mapping
*, sizeof(*new_mapping
), M_NECP
, M_WAITOK
);
3056 if (new_mapping
!= NULL
) {
3057 uuid_copy(new_mapping
->uuid
, uuid
);
3058 new_mapping
->id
= necp_get_new_uuid_id();
3059 new_mapping
->refcount
= 1;
3060 if (uuid_policy_table
) {
3061 new_mapping
->table_refcount
= 1;
3063 new_mapping
->table_refcount
= 0;
3066 LIST_INSERT_HEAD(APPUUIDHASH(uuid
), new_mapping
, chain
);
3068 if (allocated_mapping
) {
3069 *allocated_mapping
= TRUE
;
3072 local_id
= new_mapping
->id
;
3080 necp_remove_uuid_app_id_mapping(uuid_t uuid
, bool *removed_mapping
, bool uuid_policy_table
)
3082 struct necp_uuid_id_mapping
*existing_mapping
= NULL
;
3084 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
3086 if (removed_mapping
) {
3087 *removed_mapping
= FALSE
;
3090 existing_mapping
= necp_uuid_lookup_app_id_locked(uuid
);
3091 if (existing_mapping
!= NULL
) {
3092 if (uuid_policy_table
) {
3093 existing_mapping
->table_refcount
--;
3095 if (--existing_mapping
->refcount
== 0) {
3096 LIST_REMOVE(existing_mapping
, chain
);
3097 FREE(existing_mapping
, M_NECP
);
3098 if (removed_mapping
) {
3099 *removed_mapping
= TRUE
;
3108 static struct necp_uuid_id_mapping
*
3109 necp_uuid_get_null_service_id_mapping(void)
3111 static struct necp_uuid_id_mapping null_mapping
;
3112 uuid_clear(null_mapping
.uuid
);
3113 null_mapping
.id
= NECP_NULL_SERVICE_ID
;
3115 return (&null_mapping
);
3118 static struct necp_uuid_id_mapping
*
3119 necp_uuid_lookup_service_id_locked(uuid_t uuid
)
3121 struct necp_uuid_id_mapping
*searchentry
= NULL
;
3122 struct necp_uuid_id_mapping
*foundentry
= NULL
;
3124 if (uuid_is_null(uuid
)) {
3125 return necp_uuid_get_null_service_id_mapping();
3128 LIST_FOREACH(searchentry
, &necp_uuid_service_id_list
, chain
) {
3129 if (uuid_compare(searchentry
->uuid
, uuid
) == 0) {
3130 foundentry
= searchentry
;
3135 return (foundentry
);
3138 static struct necp_uuid_id_mapping
*
3139 necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id
)
3141 struct necp_uuid_id_mapping
*searchentry
= NULL
;
3142 struct necp_uuid_id_mapping
*foundentry
= NULL
;
3144 if (local_id
== NECP_NULL_SERVICE_ID
) {
3145 return necp_uuid_get_null_service_id_mapping();
3148 LIST_FOREACH(searchentry
, &necp_uuid_service_id_list
, chain
) {
3149 if (searchentry
->id
== local_id
) {
3150 foundentry
= searchentry
;
3155 return (foundentry
);
3159 necp_create_uuid_service_id_mapping(uuid_t uuid
)
3161 u_int32_t local_id
= 0;
3162 struct necp_uuid_id_mapping
*existing_mapping
= NULL
;
3164 if (uuid_is_null(uuid
)) {
3165 return (NECP_NULL_SERVICE_ID
);
3168 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
3170 existing_mapping
= necp_uuid_lookup_service_id_locked(uuid
);
3171 if (existing_mapping
!= NULL
) {
3172 local_id
= existing_mapping
->id
;
3173 existing_mapping
->refcount
++;
3175 struct necp_uuid_id_mapping
*new_mapping
= NULL
;
3176 MALLOC(new_mapping
, struct necp_uuid_id_mapping
*, sizeof(*new_mapping
), M_NECP
, M_WAITOK
);
3177 if (new_mapping
!= NULL
) {
3178 uuid_copy(new_mapping
->uuid
, uuid
);
3179 new_mapping
->id
= necp_get_new_uuid_id();
3180 new_mapping
->refcount
= 1;
3182 LIST_INSERT_HEAD(&necp_uuid_service_id_list
, new_mapping
, chain
);
3184 local_id
= new_mapping
->id
;
3192 necp_remove_uuid_service_id_mapping(uuid_t uuid
)
3194 struct necp_uuid_id_mapping
*existing_mapping
= NULL
;
3196 if (uuid_is_null(uuid
)) {
3200 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
3202 existing_mapping
= necp_uuid_lookup_app_id_locked(uuid
);
3203 if (existing_mapping
!= NULL
) {
3204 if (--existing_mapping
->refcount
== 0) {
3205 LIST_REMOVE(existing_mapping
, chain
);
3206 FREE(existing_mapping
, M_NECP
);
3216 necp_kernel_socket_policies_update_uuid_table(void)
3218 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
3220 if (necp_uuid_app_id_mappings_dirty
) {
3221 if (proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_CLEAR
, NULL
, PROC_UUID_NECP_APP_POLICY
) < 0) {
3222 NECPLOG0(LOG_DEBUG
, "Error clearing uuids from policy table\n");
3226 if (necp_num_uuid_app_id_mappings
> 0) {
3227 struct necp_uuid_id_mapping_head
*uuid_list_head
= NULL
;
3228 for (uuid_list_head
= &necp_uuid_app_id_hashtbl
[necp_uuid_app_id_hash_num_buckets
- 1]; uuid_list_head
>= necp_uuid_app_id_hashtbl
; uuid_list_head
--) {
3229 struct necp_uuid_id_mapping
*mapping
= NULL
;
3230 LIST_FOREACH(mapping
, uuid_list_head
, chain
) {
3231 if (mapping
->table_refcount
> 0 &&
3232 proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_ADD
, mapping
->uuid
, PROC_UUID_NECP_APP_POLICY
) < 0) {
3233 NECPLOG0(LOG_DEBUG
, "Error adding uuid to policy table\n");
3239 necp_uuid_app_id_mappings_dirty
= FALSE
;
3245 #define NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS (NECP_KERNEL_CONDITION_ALL_INTERFACES | NECP_KERNEL_CONDITION_BOUND_INTERFACE | NECP_KERNEL_CONDITION_PROTOCOL | NECP_KERNEL_CONDITION_LOCAL_START | NECP_KERNEL_CONDITION_LOCAL_END | NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_REMOTE_START | NECP_KERNEL_CONDITION_REMOTE_END | NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_POLICY_ID | NECP_KERNEL_CONDITION_LAST_INTERFACE)
3246 static necp_kernel_policy_id
3247 necp_kernel_ip_output_policy_add(necp_policy_id parent_policy_id
, necp_policy_order order
, necp_policy_order suborder
, u_int32_t session_order
, u_int32_t condition_mask
, u_int32_t condition_negated_mask
, necp_kernel_policy_id cond_policy_id
, ifnet_t cond_bound_interface
, u_int32_t cond_last_interface_index
, u_int16_t cond_protocol
, union necp_sockaddr_union
*cond_local_start
, union necp_sockaddr_union
*cond_local_end
, u_int8_t cond_local_prefix
, union necp_sockaddr_union
*cond_remote_start
, union necp_sockaddr_union
*cond_remote_end
, u_int8_t cond_remote_prefix
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
)
3249 struct necp_kernel_ip_output_policy
*new_kernel_policy
= NULL
;
3250 struct necp_kernel_ip_output_policy
*tmp_kernel_policy
= NULL
;
3252 MALLOC_ZONE(new_kernel_policy
, struct necp_kernel_ip_output_policy
*, sizeof(*new_kernel_policy
), M_NECP_IP_POLICY
, M_WAITOK
);
3253 if (new_kernel_policy
== NULL
) {
3257 memset(new_kernel_policy
, 0, sizeof(*new_kernel_policy
));
3258 new_kernel_policy
->parent_policy_id
= parent_policy_id
;
3259 new_kernel_policy
->id
= necp_kernel_policy_get_new_id();
3260 new_kernel_policy
->suborder
= suborder
;
3261 new_kernel_policy
->order
= order
;
3262 new_kernel_policy
->session_order
= session_order
;
3264 // Sanitize condition mask
3265 new_kernel_policy
->condition_mask
= (condition_mask
& NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS
);
3266 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
)) {
3267 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE
;
3269 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
)) {
3270 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX
;
3272 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
)) {
3273 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX
;
3275 new_kernel_policy
->condition_negated_mask
= condition_negated_mask
& new_kernel_policy
->condition_mask
;
3277 // Set condition values
3278 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
) {
3279 new_kernel_policy
->cond_policy_id
= cond_policy_id
;
3281 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
3282 if (cond_bound_interface
) {
3283 ifnet_reference(cond_bound_interface
);
3285 new_kernel_policy
->cond_bound_interface
= cond_bound_interface
;
3287 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LAST_INTERFACE
) {
3288 new_kernel_policy
->cond_last_interface_index
= cond_last_interface_index
;
3290 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
3291 new_kernel_policy
->cond_protocol
= cond_protocol
;
3293 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
3294 memcpy(&new_kernel_policy
->cond_local_start
, cond_local_start
, cond_local_start
->sa
.sa_len
);
3296 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
3297 memcpy(&new_kernel_policy
->cond_local_end
, cond_local_end
, cond_local_end
->sa
.sa_len
);
3299 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
3300 new_kernel_policy
->cond_local_prefix
= cond_local_prefix
;
3302 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
3303 memcpy(&new_kernel_policy
->cond_remote_start
, cond_remote_start
, cond_remote_start
->sa
.sa_len
);
3305 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
3306 memcpy(&new_kernel_policy
->cond_remote_end
, cond_remote_end
, cond_remote_end
->sa
.sa_len
);
3308 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
3309 new_kernel_policy
->cond_remote_prefix
= cond_remote_prefix
;
3312 new_kernel_policy
->result
= result
;
3313 memcpy(&new_kernel_policy
->result_parameter
, &result_parameter
, sizeof(result_parameter
));
3316 NECPLOG(LOG_DEBUG
, "Added kernel policy: ip output, id=%d, mask=%x\n", new_kernel_policy
->id
, new_kernel_policy
->condition_mask
);
3318 LIST_INSERT_SORTED_THRICE_ASCENDING(&necp_kernel_ip_output_policies
, new_kernel_policy
, chain
, session_order
, order
, suborder
, tmp_kernel_policy
);
3320 return (new_kernel_policy
? new_kernel_policy
->id
: 0);
3323 static struct necp_kernel_ip_output_policy
*
3324 necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id
)
3326 struct necp_kernel_ip_output_policy
*kernel_policy
= NULL
;
3327 struct necp_kernel_ip_output_policy
*tmp_kernel_policy
= NULL
;
3329 if (policy_id
== 0) {
3333 LIST_FOREACH_SAFE(kernel_policy
, &necp_kernel_ip_output_policies
, chain
, tmp_kernel_policy
) {
3334 if (kernel_policy
->id
== policy_id
) {
3335 return (kernel_policy
);
3343 necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id
)
3345 struct necp_kernel_ip_output_policy
*policy
= NULL
;
3347 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
3349 policy
= necp_kernel_ip_output_policy_find(policy_id
);
3351 LIST_REMOVE(policy
, chain
);
3353 if (policy
->cond_bound_interface
) {
3354 ifnet_release(policy
->cond_bound_interface
);
3355 policy
->cond_bound_interface
= NULL
;
3358 FREE_ZONE(policy
, sizeof(*policy
), M_NECP_IP_POLICY
);
3366 necp_kernel_ip_output_policies_dump_all(void)
3368 struct necp_kernel_ip_output_policy
*policy
= NULL
;
3373 NECPLOG0(LOG_DEBUG
, "NECP IP Output Policies:\n");
3374 NECPLOG0(LOG_DEBUG
, "-----------\n");
3375 for (id_i
= 0; id_i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; id_i
++) {
3376 NECPLOG(LOG_DEBUG
, " ID Bucket: %d\n", id_i
);
3377 for (policy_i
= 0; necp_kernel_ip_output_policies_map
[id_i
] != NULL
&& (necp_kernel_ip_output_policies_map
[id_i
])[policy_i
] != NULL
; policy_i
++) {
3378 policy
= (necp_kernel_ip_output_policies_map
[id_i
])[policy_i
];
3379 NECPLOG(LOG_DEBUG
, "\t%d. Policy ID: %d, Order: %d.%d.%d, Mask: %x, Result: %d, Parameter: %d\n", policy_i
, policy
->id
, policy
->session_order
, policy
->order
, policy
->suborder
, policy
->condition_mask
, policy
->result
, policy
->result_parameter
);
3381 NECPLOG0(LOG_DEBUG
, "-----------\n");
3387 necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy
*upper_policy
, struct necp_kernel_ip_output_policy
*lower_policy
)
3389 if (upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
3390 if (upper_policy
->session_order
!= lower_policy
->session_order
) {
3391 // A skip cannot override a policy of a different session
3394 if (upper_policy
->result_parameter
.skip_policy_order
== 0 ||
3395 lower_policy
->order
>= upper_policy
->result_parameter
.skip_policy_order
) {
3396 // This policy is beyond the skip
3399 // This policy is inside the skip
3405 // All other IP Output policy results (drop, tunnel, hard pass) currently overlap
3410 necp_kernel_ip_output_policy_is_unnecessary(struct necp_kernel_ip_output_policy
*policy
, struct necp_kernel_ip_output_policy
**policy_array
, int valid_indices
)
3412 bool can_skip
= FALSE
;
3413 u_int32_t highest_skip_session_order
= 0;
3414 u_int32_t highest_skip_order
= 0;
3416 for (i
= 0; i
< valid_indices
; i
++) {
3417 struct necp_kernel_ip_output_policy
*compared_policy
= policy_array
[i
];
3419 // For policies in a skip window, we can't mark conflicting policies as unnecessary
3421 if (highest_skip_session_order
!= compared_policy
->session_order
||
3422 (highest_skip_order
!= 0 && compared_policy
->order
>= highest_skip_order
)) {
3423 // If we've moved on to the next session, or passed the skip window
3424 highest_skip_session_order
= 0;
3425 highest_skip_order
= 0;
3428 // If this policy is also a skip, in can increase the skip window
3429 if (compared_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
3430 if (compared_policy
->result_parameter
.skip_policy_order
> highest_skip_order
) {
3431 highest_skip_order
= compared_policy
->result_parameter
.skip_policy_order
;
3438 if (compared_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
3439 // This policy is a skip. Set the skip window accordingly
3441 highest_skip_session_order
= compared_policy
->session_order
;
3442 highest_skip_order
= compared_policy
->result_parameter
.skip_policy_order
;
3445 // The result of the compared policy must be able to block out this policy result
3446 if (!necp_kernel_ip_output_policy_results_overlap(compared_policy
, policy
)) {
3450 // If new policy matches All Interfaces, compared policy must also
3451 if ((policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && !(compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) {
3455 // Default makes lower policies unecessary always
3456 if (compared_policy
->condition_mask
== 0) {
3460 // Compared must be more general than policy, and include only conditions within policy
3461 if ((policy
->condition_mask
& compared_policy
->condition_mask
) != compared_policy
->condition_mask
) {
3465 // Negative conditions must match for the overlapping conditions
3466 if ((policy
->condition_negated_mask
& compared_policy
->condition_mask
) != (compared_policy
->condition_negated_mask
& compared_policy
->condition_mask
)) {
3470 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
&&
3471 compared_policy
->cond_policy_id
!= policy
->cond_policy_id
) {
3475 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
&&
3476 compared_policy
->cond_bound_interface
!= policy
->cond_bound_interface
) {
3480 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
&&
3481 compared_policy
->cond_protocol
!= policy
->cond_protocol
) {
3485 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
3486 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
3487 if (!necp_is_range_in_range((struct sockaddr
*)&policy
->cond_local_start
, (struct sockaddr
*)&policy
->cond_local_end
, (struct sockaddr
*)&compared_policy
->cond_local_start
, (struct sockaddr
*)&compared_policy
->cond_local_end
)) {
3490 } else if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
3491 if (compared_policy
->cond_local_prefix
> policy
->cond_local_prefix
||
3492 !necp_is_addr_in_subnet((struct sockaddr
*)&policy
->cond_local_start
, (struct sockaddr
*)&compared_policy
->cond_local_start
, compared_policy
->cond_local_prefix
)) {
3498 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
3499 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
3500 if (!necp_is_range_in_range((struct sockaddr
*)&policy
->cond_remote_start
, (struct sockaddr
*)&policy
->cond_remote_end
, (struct sockaddr
*)&compared_policy
->cond_remote_start
, (struct sockaddr
*)&compared_policy
->cond_remote_end
)) {
3503 } else if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
3504 if (compared_policy
->cond_remote_prefix
> policy
->cond_remote_prefix
||
3505 !necp_is_addr_in_subnet((struct sockaddr
*)&policy
->cond_remote_start
, (struct sockaddr
*)&compared_policy
->cond_remote_start
, compared_policy
->cond_remote_prefix
)) {
3518 necp_kernel_ip_output_policies_reprocess(void)
3521 int bucket_allocation_counts
[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
];
3522 int bucket_current_free_index
[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
];
3523 struct necp_kernel_ip_output_policy
*kernel_policy
= NULL
;
3525 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
3528 necp_kernel_ip_output_policies_condition_mask
= 0;
3529 necp_kernel_ip_output_policies_count
= 0;
3530 necp_kernel_ip_output_policies_non_id_count
= 0;
3532 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
3533 if (necp_kernel_ip_output_policies_map
[i
] != NULL
) {
3534 FREE(necp_kernel_ip_output_policies_map
[i
], M_NECP
);
3535 necp_kernel_ip_output_policies_map
[i
] = NULL
;
3539 bucket_allocation_counts
[i
] = 0;
3542 LIST_FOREACH(kernel_policy
, &necp_kernel_ip_output_policies
, chain
) {
3544 necp_kernel_ip_output_policies_condition_mask
|= kernel_policy
->condition_mask
;
3545 necp_kernel_ip_output_policies_count
++;
3547 // Update bucket counts
3548 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
)) {
3549 necp_kernel_ip_output_policies_non_id_count
++;
3550 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
3551 bucket_allocation_counts
[i
]++;
3554 bucket_allocation_counts
[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy
->cond_policy_id
)]++;
3558 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
3559 if (bucket_allocation_counts
[i
] > 0) {
3560 // Allocate a NULL-terminated array of policy pointers for each bucket
3561 MALLOC(necp_kernel_ip_output_policies_map
[i
], struct necp_kernel_ip_output_policy
**, sizeof(struct necp_kernel_ip_output_policy
*) * (bucket_allocation_counts
[i
] + 1), M_NECP
, M_WAITOK
);
3562 if (necp_kernel_ip_output_policies_map
[i
] == NULL
) {
3566 // Initialize the first entry to NULL
3567 (necp_kernel_ip_output_policies_map
[i
])[0] = NULL
;
3569 bucket_current_free_index
[i
] = 0;
3572 LIST_FOREACH(kernel_policy
, &necp_kernel_ip_output_policies
, chain
) {
3573 // Insert pointers into map
3574 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
)) {
3575 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
3576 if (!necp_kernel_ip_output_policy_is_unnecessary(kernel_policy
, necp_kernel_ip_output_policies_map
[i
], bucket_current_free_index
[i
])) {
3577 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = kernel_policy
;
3578 bucket_current_free_index
[i
]++;
3579 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = NULL
;
3583 i
= NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy
->cond_policy_id
);
3584 if (!necp_kernel_ip_output_policy_is_unnecessary(kernel_policy
, necp_kernel_ip_output_policies_map
[i
], bucket_current_free_index
[i
])) {
3585 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = kernel_policy
;
3586 bucket_current_free_index
[i
]++;
3587 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = NULL
;
3591 necp_kernel_ip_output_policies_dump_all();
3595 // Free memory, reset mask to 0
3596 necp_kernel_ip_output_policies_condition_mask
= 0;
3597 necp_kernel_ip_output_policies_count
= 0;
3598 necp_kernel_ip_output_policies_non_id_count
= 0;
3599 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
3600 if (necp_kernel_ip_output_policies_map
[i
] != NULL
) {
3601 FREE(necp_kernel_ip_output_policies_map
[i
], M_NECP
);
3602 necp_kernel_ip_output_policies_map
[i
] = NULL
;
3608 // Outbound Policy Matching
3609 // ---------------------
3615 static struct substring
3616 necp_trim_dots_and_stars(char *string
, size_t length
)
3618 struct substring sub
;
3619 sub
.string
= string
;
3620 sub
.length
= string
? length
: 0;
3622 while (sub
.length
&& (sub
.string
[0] == '.' || sub
.string
[0] == '*')) {
3627 while (sub
.length
&& (sub
.string
[sub
.length
- 1] == '.' || sub
.string
[sub
.length
- 1] == '*')) {
3635 necp_create_trimmed_domain(char *string
, size_t length
)
3637 char *trimmed_domain
= NULL
;
3638 struct substring sub
= necp_trim_dots_and_stars(string
, length
);
3640 MALLOC(trimmed_domain
, char *, sub
.length
+ 1, M_NECP
, M_WAITOK
);
3641 if (trimmed_domain
== NULL
) {
3645 memcpy(trimmed_domain
, sub
.string
, sub
.length
);
3646 trimmed_domain
[sub
.length
] = 0;
3648 return (trimmed_domain
);
3652 necp_count_dots(char *string
, size_t length
)
3657 for (i
= 0; i
< length
; i
++) {
3658 if (string
[i
] == '.') {
3667 necp_check_suffix(struct substring parent
, struct substring suffix
, bool require_dot_before_suffix
)
3669 if (parent
.length
<= suffix
.length
) {
3673 size_t length_difference
= (parent
.length
- suffix
.length
);
3675 if (require_dot_before_suffix
) {
3676 if (((char *)(parent
.string
+ length_difference
- 1))[0] != '.') {
3681 return (memcmp(parent
.string
+ length_difference
, suffix
.string
, suffix
.length
) == 0);
3685 necp_hostname_matches_domain(struct substring hostname_substring
, u_int8_t hostname_dot_count
, char *domain
, u_int8_t domain_dot_count
)
3687 if (hostname_substring
.string
== NULL
|| domain
== NULL
) {
3688 return (hostname_substring
.string
== domain
);
3691 struct substring domain_substring
;
3692 domain_substring
.string
= domain
;
3693 domain_substring
.length
= strlen(domain
);
3695 if (hostname_dot_count
== domain_dot_count
) {
3696 if (hostname_substring
.length
== domain_substring
.length
&&
3697 memcmp(hostname_substring
.string
, domain_substring
.string
, hostname_substring
.length
) == 0) {
3700 } else if (domain_dot_count
> 0 && domain_dot_count
< hostname_dot_count
) {
3701 if (necp_check_suffix(hostname_substring
, domain_substring
, TRUE
)) {
3710 necp_application_fillout_info_locked(uuid_t application_uuid
, uuid_t real_application_uuid
, char *account
, char *domain
, pid_t pid
, uid_t uid
, u_int16_t protocol
, u_int32_t bound_interface_index
, u_int32_t traffic_class
, struct necp_socket_info
*info
)
3712 memset(info
, 0, sizeof(struct necp_socket_info
));
3716 info
->protocol
= protocol
;
3717 info
->bound_interface_index
= bound_interface_index
;
3718 info
->traffic_class
= traffic_class
;
3719 info
->cred_result
= 0; // Don't check the entitlement here, only in the socket layer
3721 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_APP_ID
&& !uuid_is_null(application_uuid
)) {
3722 struct necp_uuid_id_mapping
*existing_mapping
= necp_uuid_lookup_app_id_locked(application_uuid
);
3723 if (existing_mapping
) {
3724 info
->application_id
= existing_mapping
->id
;
3728 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
&& !uuid_is_null(real_application_uuid
)) {
3729 if (uuid_compare(application_uuid
, real_application_uuid
) == 0) {
3730 info
->real_application_id
= info
->application_id
;
3732 struct necp_uuid_id_mapping
*existing_mapping
= necp_uuid_lookup_app_id_locked(real_application_uuid
);
3733 if (existing_mapping
) {
3734 info
->real_application_id
= existing_mapping
->id
;
3739 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
&& account
!= NULL
) {
3740 struct necp_string_id_mapping
*existing_mapping
= necp_lookup_string_to_id_locked(&necp_account_id_list
, account
);
3741 if (existing_mapping
) {
3742 info
->account_id
= existing_mapping
->id
;
3746 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
3747 info
->domain
= domain
;
3752 necp_application_find_policy_match_internal(u_int8_t
*parameters
, size_t parameters_size
, struct necp_aggregate_result
*returned_result
)
3757 struct necp_kernel_socket_policy
*matched_policy
= NULL
;
3758 struct necp_socket_info info
;
3759 necp_kernel_policy_filter filter_control_unit
= 0;
3760 necp_kernel_policy_result service_action
= 0;
3761 necp_kernel_policy_service service
= { 0, 0 };
3765 u_int16_t protocol
= 0;
3766 u_int32_t bound_interface_index
= 0;
3767 u_int32_t traffic_class
= 0;
3769 uuid_t application_uuid
;
3770 uuid_clear(application_uuid
);
3771 uuid_t real_application_uuid
;
3772 uuid_clear(real_application_uuid
);
3773 char *domain
= NULL
;
3774 char *account
= NULL
;
3776 if (returned_result
== NULL
) {
3780 memset(returned_result
, 0, sizeof(struct necp_aggregate_result
));
3782 lck_rw_lock_shared(&necp_kernel_policy_lock
);
3783 if (necp_kernel_application_policies_count
== 0) {
3784 if (necp_drop_all_order
> 0) {
3785 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
3786 lck_rw_done(&necp_kernel_policy_lock
);
3790 lck_rw_done(&necp_kernel_policy_lock
);
3792 while (offset
< parameters_size
) {
3793 u_int8_t type
= necp_buffer_get_tlv_type(parameters
, offset
);
3794 size_t length
= necp_buffer_get_tlv_length(parameters
, offset
);
3796 if (length
> 0 && (offset
+ sizeof(u_int8_t
) + sizeof(size_t) + length
) <= parameters_size
) {
3797 u_int8_t
*value
= necp_buffer_get_tlv_value(parameters
, offset
, NULL
);
3798 if (value
!= NULL
) {
3800 case NECP_POLICY_CONDITION_APPLICATION
: {
3801 if (length
>= sizeof(uuid_t
)) {
3802 uuid_copy(application_uuid
, value
);
3806 case NECP_POLICY_CONDITION_REAL_APPLICATION
: {
3807 if (length
>= sizeof(uuid_t
)) {
3808 uuid_copy(real_application_uuid
, value
);
3812 case NECP_POLICY_CONDITION_DOMAIN
: {
3813 domain
= (char *)value
;
3814 domain
[length
- 1] = 0;
3817 case NECP_POLICY_CONDITION_ACCOUNT
: {
3818 account
= (char *)value
;
3819 account
[length
- 1] = 0;
3822 case NECP_POLICY_CONDITION_TRAFFIC_CLASS
: {
3823 if (length
>= sizeof(u_int32_t
)) {
3824 memcpy(&traffic_class
, value
, sizeof(u_int32_t
));
3828 case NECP_POLICY_CONDITION_PID
: {
3829 if (length
>= sizeof(pid_t
)) {
3830 memcpy(&pid
, value
, sizeof(pid_t
));
3834 case NECP_POLICY_CONDITION_UID
: {
3835 if (length
>= sizeof(uid_t
)) {
3836 memcpy(&uid
, value
, sizeof(uid_t
));
3840 case NECP_POLICY_CONDITION_IP_PROTOCOL
: {
3841 if (length
>= sizeof(u_int16_t
)) {
3842 memcpy(&protocol
, value
, sizeof(u_int16_t
));
3846 case NECP_POLICY_CONDITION_BOUND_INTERFACE
: {
3847 if (length
<= IFXNAMSIZ
&& length
> 0) {
3848 ifnet_t bound_interface
= NULL
;
3849 char interface_name
[IFXNAMSIZ
];
3850 memcpy(interface_name
, value
, length
);
3851 interface_name
[length
- 1] = 0; // Make sure the string is NULL terminated
3852 if (ifnet_find_by_name(interface_name
, &bound_interface
) == 0) {
3853 bound_interface_index
= bound_interface
->if_index
;
3865 offset
+= sizeof(u_int8_t
) + sizeof(size_t) + length
;
3869 lck_rw_lock_shared(&necp_kernel_policy_lock
);
3871 necp_application_fillout_info_locked(application_uuid
, real_application_uuid
, account
, domain
, pid
, uid
, protocol
, bound_interface_index
, traffic_class
, &info
);
3872 matched_policy
= necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_app_layer_map
, &info
, &filter_control_unit
, &service_action
, &service
);
3873 if (matched_policy
) {
3874 returned_result
->routing_result
= matched_policy
->result
;
3875 memcpy(&returned_result
->routing_result_parameter
, &matched_policy
->result_parameter
, sizeof(returned_result
->routing_result_parameter
));
3877 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_NONE
;
3879 returned_result
->filter_control_unit
= filter_control_unit
;
3880 returned_result
->service_action
= service_action
;
3882 if (service
.identifier
!= 0) {
3883 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(service
.identifier
);
3884 if (mapping
!= NULL
) {
3885 struct necp_service_registration
*service_registration
= NULL
;
3886 uuid_copy(returned_result
->service_uuid
, mapping
->uuid
);
3887 returned_result
->service_data
= service
.data
;
3888 if (service
.identifier
== NECP_NULL_SERVICE_ID
) {
3889 // NULL service is always 'registered'
3890 returned_result
->service_flags
|= NECP_SERVICE_FLAGS_REGISTERED
;
3892 LIST_FOREACH(service_registration
, &necp_registered_service_list
, kernel_chain
) {
3893 if (service
.identifier
== service_registration
->service_id
) {
3894 returned_result
->service_flags
|= NECP_SERVICE_FLAGS_REGISTERED
;
3903 lck_rw_done(&necp_kernel_policy_lock
);
3908 #define NECP_MAX_MATCH_POLICY_PARAMETER_SIZE 1024
3911 necp_match_policy(struct proc
*p
, struct necp_match_policy_args
*uap
, int32_t *retval
)
3913 #pragma unused(p, retval)
3914 u_int8_t
*parameters
= NULL
;
3915 struct necp_aggregate_result returned_result
;
3923 if (uap
->parameters
== 0 || uap
->parameters_size
== 0 || uap
->parameters_size
> NECP_MAX_MATCH_POLICY_PARAMETER_SIZE
|| uap
->returned_result
== 0) {
3928 MALLOC(parameters
, u_int8_t
*, uap
->parameters_size
, M_NECP
, M_WAITOK
);
3929 if (parameters
== NULL
) {
3933 // Copy parameters in
3934 copyin(uap
->parameters
, parameters
, uap
->parameters_size
);
3936 error
= necp_application_find_policy_match_internal(parameters
, uap
->parameters_size
, &returned_result
);
3941 // Copy return value back
3942 copyout(&returned_result
, uap
->returned_result
, sizeof(struct necp_aggregate_result
));
3944 if (parameters
!= NULL
) {
3945 FREE(parameters
, M_NECP
);
3951 necp_socket_check_policy(struct necp_kernel_socket_policy
*kernel_policy
, necp_app_id app_id
, necp_app_id real_app_id
, errno_t cred_result
, u_int32_t account_id
, struct substring domain
, u_int8_t domain_dot_count
, pid_t pid
, uid_t uid
, u_int32_t bound_interface_index
, u_int32_t traffic_class
, u_int16_t protocol
, union necp_sockaddr_union
*local
, union necp_sockaddr_union
*remote
)
3953 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) {
3954 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
3955 u_int32_t cond_bound_interface_index
= kernel_policy
->cond_bound_interface
? kernel_policy
->cond_bound_interface
->if_index
: 0;
3956 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
3957 if (bound_interface_index
== cond_bound_interface_index
) {
3958 // No match, matches forbidden interface
3962 if (bound_interface_index
!= cond_bound_interface_index
) {
3963 // No match, does not match required interface
3968 if (bound_interface_index
!= 0) {
3969 // No match, requires a non-bound packet
3975 if (kernel_policy
->condition_mask
== 0) {
3979 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
3980 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
3981 if (app_id
== kernel_policy
->cond_app_id
) {
3982 // No match, matches forbidden application
3986 if (app_id
!= kernel_policy
->cond_app_id
) {
3987 // No match, does not match required application
3993 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
3994 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
3995 if (real_app_id
== kernel_policy
->cond_real_app_id
) {
3996 // No match, matches forbidden application
4000 if (real_app_id
!= kernel_policy
->cond_real_app_id
) {
4001 // No match, does not match required application
4007 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
) {
4008 if (cred_result
!= 0) {
4009 // Process is missing entitlement
4014 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
4015 bool domain_matches
= necp_hostname_matches_domain(domain
, domain_dot_count
, kernel_policy
->cond_domain
, kernel_policy
->cond_domain_dot_count
);
4016 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
4017 if (domain_matches
) {
4018 // No match, matches forbidden domain
4022 if (!domain_matches
) {
4023 // No match, does not match required domain
4029 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
4030 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
4031 if (account_id
== kernel_policy
->cond_account_id
) {
4032 // No match, matches forbidden account
4036 if (account_id
!= kernel_policy
->cond_account_id
) {
4037 // No match, does not match required account
4043 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PID
) {
4044 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_PID
) {
4045 if (pid
== kernel_policy
->cond_pid
) {
4046 // No match, matches forbidden pid
4050 if (pid
!= kernel_policy
->cond_pid
) {
4051 // No match, does not match required pid
4057 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_UID
) {
4058 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_UID
) {
4059 if (uid
== kernel_policy
->cond_uid
) {
4060 // No match, matches forbidden uid
4064 if (uid
!= kernel_policy
->cond_uid
) {
4065 // No match, does not match required uid
4071 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
4072 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
4073 if (traffic_class
>= kernel_policy
->cond_traffic_class
.start_tc
&&
4074 traffic_class
<= kernel_policy
->cond_traffic_class
.end_tc
) {
4075 // No match, matches forbidden traffic class
4079 if (traffic_class
< kernel_policy
->cond_traffic_class
.start_tc
||
4080 traffic_class
> kernel_policy
->cond_traffic_class
.end_tc
) {
4081 // No match, does not match required traffic class
4087 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
4088 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
4089 if (protocol
== kernel_policy
->cond_protocol
) {
4090 // No match, matches forbidden protocol
4094 if (protocol
!= kernel_policy
->cond_protocol
) {
4095 // No match, does not match required protocol
4101 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
4102 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
4103 bool inRange
= necp_is_addr_in_range((struct sockaddr
*)local
, (struct sockaddr
*)&kernel_policy
->cond_local_start
, (struct sockaddr
*)&kernel_policy
->cond_local_end
);
4104 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
4113 } else if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
4114 bool inSubnet
= necp_is_addr_in_subnet((struct sockaddr
*)local
, (struct sockaddr
*)&kernel_policy
->cond_local_start
, kernel_policy
->cond_local_prefix
);
4115 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
4127 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
4128 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
4129 bool inRange
= necp_is_addr_in_range((struct sockaddr
*)remote
, (struct sockaddr
*)&kernel_policy
->cond_remote_start
, (struct sockaddr
*)&kernel_policy
->cond_remote_end
);
4130 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
4139 } else if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
4140 bool inSubnet
= necp_is_addr_in_subnet((struct sockaddr
*)remote
, (struct sockaddr
*)&kernel_policy
->cond_remote_start
, kernel_policy
->cond_remote_prefix
);
4141 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
4156 static inline u_int32_t
4157 necp_socket_calc_flowhash_locked(struct necp_socket_info
*info
)
4159 return (net_flowhash(info
, sizeof(*info
), necp_kernel_socket_policies_gencount
));
4162 #define NECP_KERNEL_ADDRESS_TYPE_CONDITIONS (NECP_KERNEL_CONDITION_LOCAL_START | NECP_KERNEL_CONDITION_LOCAL_END | NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_REMOTE_START | NECP_KERNEL_CONDITION_REMOTE_END | NECP_KERNEL_CONDITION_REMOTE_PREFIX)
4164 necp_socket_fillout_info_locked(struct inpcb
*inp
, struct sockaddr
*override_local_addr
, struct sockaddr
*override_remote_addr
, u_int32_t override_bound_interface
, struct necp_socket_info
*info
)
4166 struct socket
*so
= NULL
;
4168 memset(info
, 0, sizeof(struct necp_socket_info
));
4170 so
= inp
->inp_socket
;
4172 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_PID
) {
4173 info
->pid
= ((so
->so_flags
& SOF_DELEGATED
) ? so
->e_pid
: so
->last_pid
);
4176 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_UID
) {
4177 info
->uid
= kauth_cred_getuid(so
->so_cred
);
4180 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
4181 info
->traffic_class
= so
->so_traffic_class
;
4184 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
4185 if (inp
->inp_ip_p
) {
4186 info
->protocol
= inp
->inp_ip_p
;
4188 info
->protocol
= SOCK_PROTO(so
);
4192 if (inp
->inp_flags2
& INP2_WANT_APP_POLICY
&& necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
4193 struct necp_uuid_id_mapping
*existing_mapping
= necp_uuid_lookup_app_id_locked(((so
->so_flags
& SOF_DELEGATED
) ? so
->e_uuid
: so
->last_uuid
));
4194 if (existing_mapping
) {
4195 info
->application_id
= existing_mapping
->id
;
4198 if (!(so
->so_flags
& SOF_DELEGATED
)) {
4199 info
->real_application_id
= info
->application_id
;
4200 } else if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
4201 struct necp_uuid_id_mapping
*real_existing_mapping
= necp_uuid_lookup_app_id_locked(so
->last_uuid
);
4202 if (real_existing_mapping
) {
4203 info
->real_application_id
= real_existing_mapping
->id
;
4207 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
) {
4208 info
->cred_result
= priv_check_cred(so
->so_cred
, PRIV_NET_PRIVILEGED_NECP_MATCH
, 0);
4212 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
&& inp
->inp_necp_attributes
.inp_account
!= NULL
) {
4213 struct necp_string_id_mapping
*existing_mapping
= necp_lookup_string_to_id_locked(&necp_account_id_list
, inp
->inp_necp_attributes
.inp_account
);
4214 if (existing_mapping
) {
4215 info
->account_id
= existing_mapping
->id
;
4219 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
4220 info
->domain
= inp
->inp_necp_attributes
.inp_domain
;
4223 if (override_bound_interface
) {
4224 info
->bound_interface_index
= override_bound_interface
;
4226 if ((inp
->inp_flags
& INP_BOUND_IF
) && inp
->inp_boundifp
) {
4227 info
->bound_interface_index
= inp
->inp_boundifp
->if_index
;
4231 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_ADDRESS_TYPE_CONDITIONS
) {
4232 if (inp
->inp_vflag
& INP_IPV4
) {
4233 if (override_local_addr
) {
4234 memcpy(&info
->local_addr
, override_local_addr
, override_local_addr
->sa_len
);
4236 ((struct sockaddr_in
*)&info
->local_addr
)->sin_family
= AF_INET
;
4237 ((struct sockaddr_in
*)&info
->local_addr
)->sin_len
= sizeof(struct sockaddr_in
);
4238 ((struct sockaddr_in
*)&info
->local_addr
)->sin_port
= inp
->inp_lport
;
4239 memcpy(&((struct sockaddr_in
*)&info
->local_addr
)->sin_addr
, &inp
->inp_laddr
, sizeof(struct in_addr
));
4242 if (override_remote_addr
) {
4243 memcpy(&info
->remote_addr
, override_remote_addr
, override_remote_addr
->sa_len
);
4245 ((struct sockaddr_in
*)&info
->remote_addr
)->sin_family
= AF_INET
;
4246 ((struct sockaddr_in
*)&info
->remote_addr
)->sin_len
= sizeof(struct sockaddr_in
);
4247 ((struct sockaddr_in
*)&info
->remote_addr
)->sin_port
= inp
->inp_fport
;
4248 memcpy(&((struct sockaddr_in
*)&info
->remote_addr
)->sin_addr
, &inp
->inp_faddr
, sizeof(struct in_addr
));
4250 } else if (inp
->inp_vflag
& INP_IPV6
) {
4251 if (override_local_addr
) {
4252 memcpy(&info
->local_addr
, override_local_addr
, override_local_addr
->sa_len
);
4254 ((struct sockaddr_in6
*)&info
->local_addr
)->sin6_family
= AF_INET6
;
4255 ((struct sockaddr_in6
*)&info
->local_addr
)->sin6_len
= sizeof(struct sockaddr_in6
);
4256 ((struct sockaddr_in6
*)&info
->local_addr
)->sin6_port
= inp
->inp_lport
;
4257 memcpy(&((struct sockaddr_in6
*)&info
->local_addr
)->sin6_addr
, &inp
->in6p_laddr
, sizeof(struct in6_addr
));
4260 if (override_remote_addr
) {
4261 memcpy(&info
->remote_addr
, override_remote_addr
, override_remote_addr
->sa_len
);
4263 ((struct sockaddr_in6
*)&info
->remote_addr
)->sin6_family
= AF_INET6
;
4264 ((struct sockaddr_in6
*)&info
->remote_addr
)->sin6_len
= sizeof(struct sockaddr_in6
);
4265 ((struct sockaddr_in6
*)&info
->remote_addr
)->sin6_port
= inp
->inp_fport
;
4266 memcpy(&((struct sockaddr_in6
*)&info
->remote_addr
)->sin6_addr
, &inp
->in6p_faddr
, sizeof(struct in6_addr
));
4272 static inline struct necp_kernel_socket_policy
*
4273 necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy
**policy_search_array
, struct necp_socket_info
*info
, necp_kernel_policy_filter
*return_filter
, necp_kernel_policy_result
*return_service_action
, necp_kernel_policy_service
*return_service
)
4275 struct necp_kernel_socket_policy
*matched_policy
= NULL
;
4276 u_int32_t skip_order
= 0;
4277 u_int32_t skip_session_order
= 0;
4280 // Pre-process domain for quick matching
4281 struct substring domain_substring
= necp_trim_dots_and_stars(info
->domain
, info
->domain
? strlen(info
->domain
) : 0);
4282 u_int8_t domain_dot_count
= necp_count_dots(domain_substring
.string
, domain_substring
.length
);
4284 if (return_filter
) {
4288 if (return_service_action
) {
4289 *return_service_action
= 0;
4292 if (return_service
) {
4293 return_service
->identifier
= 0;
4294 return_service
->data
= 0;
4297 if (policy_search_array
!= NULL
) {
4298 for (i
= 0; policy_search_array
[i
] != NULL
; i
++) {
4299 if (necp_drop_all_order
!= 0 && policy_search_array
[i
]->session_order
>= necp_drop_all_order
) {
4300 // We've hit a drop all rule
4303 if (skip_session_order
&& policy_search_array
[i
]->session_order
>= skip_session_order
) {
4306 skip_session_order
= 0;
4309 if (policy_search_array
[i
]->order
< skip_order
) {
4315 skip_session_order
= 0;
4317 } else if (skip_session_order
) {
4321 if (necp_socket_check_policy(policy_search_array
[i
], info
->application_id
, info
->real_application_id
, info
->cred_result
, info
->account_id
, domain_substring
, domain_dot_count
, info
->pid
, info
->uid
, info
->bound_interface_index
, info
->traffic_class
, info
->protocol
, &info
->local_addr
, &info
->remote_addr
)) {
4322 if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER
) {
4323 if (return_filter
&& *return_filter
== 0) {
4324 *return_filter
= policy_search_array
[i
]->result_parameter
.filter_control_unit
;
4325 if (necp_debug
> 1) {
4326 NECPLOG(LOG_DEBUG
, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) Filter %d", info
->application_id
, info
->real_application_id
, info
->bound_interface_index
, info
->protocol
, policy_search_array
[i
]->result_parameter
.filter_control_unit
);
4330 } else if (necp_kernel_socket_result_is_service_type(policy_search_array
[i
])) {
4331 if (return_service_action
&& *return_service_action
== 0) {
4332 *return_service_action
= policy_search_array
[i
]->result
;
4333 if (necp_debug
> 1) {
4334 NECPLOG(LOG_DEBUG
, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) Service Action %d", info
->application_id
, info
->real_application_id
, info
->bound_interface_index
, info
->protocol
, policy_search_array
[i
]->result
);
4337 if (return_service
&& return_service
->identifier
== 0) {
4338 return_service
->identifier
= policy_search_array
[i
]->result_parameter
.service
.identifier
;
4339 return_service
->data
= policy_search_array
[i
]->result_parameter
.service
.data
;
4340 if (necp_debug
> 1) {
4341 NECPLOG(LOG_DEBUG
, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) Service ID %d Data %d", info
->application_id
, info
->real_application_id
, info
->bound_interface_index
, info
->protocol
, policy_search_array
[i
]->result_parameter
.service
.identifier
, policy_search_array
[i
]->result_parameter
.service
.data
);
4347 // Passed all tests, found a match
4348 matched_policy
= policy_search_array
[i
];
4349 if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
4350 skip_order
= policy_search_array
[i
]->result_parameter
.skip_policy_order
;
4351 skip_session_order
= policy_search_array
[i
]->session_order
+ 1;
4359 return (matched_policy
);
4363 necp_socket_uses_interface(struct inpcb
*inp
, u_int32_t interface_index
)
4365 bool found_match
= FALSE
;
4367 ifaddr_t
*addresses
= NULL
;
4368 union necp_sockaddr_union address_storage
;
4370 int family
= AF_INET
;
4371 ifnet_t interface
= ifindex2ifnet
[interface_index
];
4373 if (inp
== NULL
|| interface
== NULL
) {
4377 if (inp
->inp_vflag
& INP_IPV4
) {
4379 } else if (inp
->inp_vflag
& INP_IPV6
) {
4383 result
= ifnet_get_address_list_family(interface
, &addresses
, family
);
4385 NECPLOG(LOG_ERR
, "Failed to get address list for %s%d", ifnet_name(interface
), ifnet_unit(interface
));
4389 for (i
= 0; addresses
[i
] != NULL
; i
++) {
4390 if (ifaddr_address(addresses
[i
], &address_storage
.sa
, sizeof(address_storage
)) == 0) {
4391 if (family
== AF_INET
) {
4392 if (memcmp(&address_storage
.sin
.sin_addr
, &inp
->inp_laddr
, sizeof(inp
->inp_laddr
)) == 0) {
4396 } else if (family
== AF_INET6
) {
4397 if (memcmp(&address_storage
.sin6
.sin6_addr
, &inp
->in6p_laddr
, sizeof(inp
->in6p_laddr
)) == 0) {
4406 ifnet_free_address_list(addresses
);
4408 return (found_match
);
4412 necp_socket_is_connected(struct inpcb
*inp
)
4414 return (inp
->inp_socket
->so_state
& (SS_ISCONNECTING
| SS_ISCONNECTED
| SS_ISDISCONNECTING
));
4417 necp_kernel_policy_id
4418 necp_socket_find_policy_match(struct inpcb
*inp
, struct sockaddr
*override_local_addr
, struct sockaddr
*override_remote_addr
, u_int32_t override_bound_interface
)
4420 struct socket
*so
= NULL
;
4421 necp_kernel_policy_filter filter_control_unit
= 0;
4422 struct necp_kernel_socket_policy
*matched_policy
= NULL
;
4423 necp_kernel_policy_id matched_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
4424 necp_kernel_policy_result service_action
= 0;
4425 necp_kernel_policy_service service
= { 0, 0 };
4427 struct necp_socket_info info
;
4430 return (NECP_KERNEL_POLICY_ID_NONE
);
4433 so
= inp
->inp_socket
;
4435 // Don't lock. Possible race condition, but we don't want the performance hit.
4436 if (necp_kernel_socket_policies_count
== 0 ||
4437 (!(inp
->inp_flags2
& INP2_WANT_APP_POLICY
) && necp_kernel_socket_policies_non_app_count
== 0)) {
4438 if (necp_drop_all_order
> 0) {
4439 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
4440 inp
->inp_policyresult
.policy_gencount
= 0;
4441 inp
->inp_policyresult
.flowhash
= 0;
4442 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
4443 if (necp_pass_loopback
> 0 &&
4444 necp_is_loopback(override_local_addr
, override_remote_addr
, inp
, NULL
)) {
4445 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_PASS
;
4447 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_DROP
;
4450 return (NECP_KERNEL_POLICY_ID_NONE
);
4453 // Check for loopback exception
4454 if (necp_pass_loopback
> 0 &&
4455 necp_is_loopback(override_local_addr
, override_remote_addr
, inp
, NULL
)) {
4456 // Mark socket as a pass
4457 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
4458 inp
->inp_policyresult
.policy_gencount
= 0;
4459 inp
->inp_policyresult
.flowhash
= 0;
4460 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
4461 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_PASS
;
4462 return (NECP_KERNEL_POLICY_ID_NONE
);
4466 lck_rw_lock_shared(&necp_kernel_policy_lock
);
4468 necp_socket_fillout_info_locked(inp
, override_local_addr
, override_remote_addr
, override_bound_interface
, &info
);
4471 u_int32_t flowhash
= necp_socket_calc_flowhash_locked(&info
);
4472 if (inp
->inp_policyresult
.policy_id
!= NECP_KERNEL_POLICY_ID_NONE
&&
4473 inp
->inp_policyresult
.policy_gencount
== necp_kernel_socket_policies_gencount
&&
4474 inp
->inp_policyresult
.flowhash
== flowhash
) {
4475 // If already matched this socket on this generation of table, skip
4478 lck_rw_done(&necp_kernel_policy_lock
);
4480 return (inp
->inp_policyresult
.policy_id
);
4483 // Match socket to policy
4484 matched_policy
= necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map
[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info
.application_id
)], &info
, &filter_control_unit
, &service_action
, &service
);
4485 // If the socket matched a scoped service policy, mark as Drop if not registered.
4486 // This covers the cases in which a service is required (on demand) but hasn't started yet.
4487 if ((service_action
== NECP_KERNEL_POLICY_RESULT_TRIGGER_SCOPED
||
4488 service_action
== NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED
) &&
4489 service
.identifier
!= 0 &&
4490 service
.identifier
!= NECP_NULL_SERVICE_ID
) {
4491 bool service_is_registered
= FALSE
;
4492 struct necp_service_registration
*service_registration
= NULL
;
4493 LIST_FOREACH(service_registration
, &necp_registered_service_list
, kernel_chain
) {
4494 if (service
.identifier
== service_registration
->service_id
) {
4495 service_is_registered
= TRUE
;
4499 if (!service_is_registered
) {
4500 // Mark socket as a drop if service is not registered
4501 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
4502 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
4503 inp
->inp_policyresult
.flowhash
= flowhash
;
4504 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
4505 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_DROP
;
4507 if (necp_debug
> 1) {
4508 NECPLOG(LOG_DEBUG
, "Socket Policy: (BoundInterface %d Proto %d) Dropping packet because service is not registered", info
.bound_interface_index
, info
.protocol
);
4512 lck_rw_done(&necp_kernel_policy_lock
);
4513 return (NECP_KERNEL_POLICY_ID_NONE
);
4516 if (matched_policy
) {
4517 matched_policy_id
= matched_policy
->id
;
4518 inp
->inp_policyresult
.policy_id
= matched_policy
->id
;
4519 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
4520 inp
->inp_policyresult
.flowhash
= flowhash
;
4521 inp
->inp_policyresult
.results
.filter_control_unit
= filter_control_unit
;
4522 inp
->inp_policyresult
.results
.result
= matched_policy
->result
;
4523 memcpy(&inp
->inp_policyresult
.results
.result_parameter
, &matched_policy
->result_parameter
, sizeof(matched_policy
->result_parameter
));
4525 if (necp_socket_is_connected(inp
) &&
4526 (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_DROP
||
4527 (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&& !necp_socket_uses_interface(inp
, matched_policy
->result_parameter
.tunnel_interface_index
)))) {
4529 NECPLOG(LOG_DEBUG
, "Marking socket in state %d as defunct", so
->so_state
);
4531 sosetdefunct(current_proc(), so
, SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL
, TRUE
);
4534 if (necp_debug
> 1) {
4535 NECPLOG(LOG_DEBUG
, "Socket Policy: (BoundInterface %d Proto %d) Policy %d Result %d Parameter %d", info
.bound_interface_index
, info
.protocol
, matched_policy
->id
, matched_policy
->result
, matched_policy
->result_parameter
.tunnel_interface_index
);
4537 } else if (necp_drop_all_order
> 0) {
4538 // Mark socket as a drop if set
4539 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
4540 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
4541 inp
->inp_policyresult
.flowhash
= flowhash
;
4542 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
4543 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_DROP
;
4545 // Mark non-matching socket so we don't re-check it
4546 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
4547 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
4548 inp
->inp_policyresult
.flowhash
= flowhash
;
4549 inp
->inp_policyresult
.results
.filter_control_unit
= filter_control_unit
; // We may have matched a filter, so mark it!
4550 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_NONE
;
4554 lck_rw_done(&necp_kernel_policy_lock
);
4556 return (matched_policy_id
);
4560 necp_ip_output_check_policy(struct necp_kernel_ip_output_policy
*kernel_policy
, necp_kernel_policy_id socket_policy_id
, u_int32_t bound_interface_index
, u_int32_t last_interface_index
, u_int16_t protocol
, union necp_sockaddr_union
*local
, union necp_sockaddr_union
*remote
)
4562 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) {
4563 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
4564 u_int32_t cond_bound_interface_index
= kernel_policy
->cond_bound_interface
? kernel_policy
->cond_bound_interface
->if_index
: 0;
4565 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
4566 if (bound_interface_index
== cond_bound_interface_index
) {
4567 // No match, matches forbidden interface
4571 if (bound_interface_index
!= cond_bound_interface_index
) {
4572 // No match, does not match required interface
4577 if (bound_interface_index
!= 0) {
4578 // No match, requires a non-bound packet
4584 if (kernel_policy
->condition_mask
== 0) {
4588 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
) {
4589 if (socket_policy_id
!= kernel_policy
->cond_policy_id
) {
4590 // No match, does not match required id
4595 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LAST_INTERFACE
) {
4596 if (last_interface_index
!= kernel_policy
->cond_last_interface_index
) {
4601 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
4602 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
4603 if (protocol
== kernel_policy
->cond_protocol
) {
4604 // No match, matches forbidden protocol
4608 if (protocol
!= kernel_policy
->cond_protocol
) {
4609 // No match, does not match required protocol
4615 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
4616 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
4617 bool inRange
= necp_is_addr_in_range((struct sockaddr
*)local
, (struct sockaddr
*)&kernel_policy
->cond_local_start
, (struct sockaddr
*)&kernel_policy
->cond_local_end
);
4618 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
4627 } else if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
4628 bool inSubnet
= necp_is_addr_in_subnet((struct sockaddr
*)local
, (struct sockaddr
*)&kernel_policy
->cond_local_start
, kernel_policy
->cond_local_prefix
);
4629 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
4641 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
4642 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
4643 bool inRange
= necp_is_addr_in_range((struct sockaddr
*)remote
, (struct sockaddr
*)&kernel_policy
->cond_remote_start
, (struct sockaddr
*)&kernel_policy
->cond_remote_end
);
4644 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
4653 } else if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
4654 bool inSubnet
= necp_is_addr_in_subnet((struct sockaddr
*)remote
, (struct sockaddr
*)&kernel_policy
->cond_remote_start
, kernel_policy
->cond_remote_prefix
);
4655 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
4670 static inline struct necp_kernel_ip_output_policy
*
4671 necp_ip_output_find_policy_match_locked(necp_kernel_policy_id socket_policy_id
, u_int32_t bound_interface_index
, u_int32_t last_interface_index
, u_int16_t protocol
, union necp_sockaddr_union
*local_addr
, union necp_sockaddr_union
*remote_addr
)
4673 u_int32_t skip_order
= 0;
4674 u_int32_t skip_session_order
= 0;
4676 struct necp_kernel_ip_output_policy
*matched_policy
= NULL
;
4677 struct necp_kernel_ip_output_policy
**policy_search_array
= necp_kernel_ip_output_policies_map
[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(socket_policy_id
)];
4678 if (policy_search_array
!= NULL
) {
4679 for (i
= 0; policy_search_array
[i
] != NULL
; i
++) {
4680 if (necp_drop_all_order
!= 0 && policy_search_array
[i
]->session_order
>= necp_drop_all_order
) {
4681 // We've hit a drop all rule
4684 if (skip_session_order
&& policy_search_array
[i
]->session_order
>= skip_session_order
) {
4687 skip_session_order
= 0;
4690 if (policy_search_array
[i
]->order
< skip_order
) {
4696 skip_session_order
= 0;
4698 } else if (skip_session_order
) {
4702 if (necp_ip_output_check_policy(policy_search_array
[i
], socket_policy_id
, bound_interface_index
, last_interface_index
, protocol
, local_addr
, remote_addr
)) {
4703 // Passed all tests, found a match
4704 matched_policy
= policy_search_array
[i
];
4706 if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
4707 skip_order
= policy_search_array
[i
]->result_parameter
.skip_policy_order
;
4708 skip_session_order
= policy_search_array
[i
]->session_order
+ 1;
4717 return (matched_policy
);
4720 necp_kernel_policy_id
4721 necp_ip_output_find_policy_match(struct mbuf
*packet
, int flags
, struct ip_out_args
*ipoa
, necp_kernel_policy_result
*result
, necp_kernel_policy_result_parameter
*result_parameter
)
4723 struct ip
*ip
= NULL
;
4724 int hlen
= sizeof(struct ip
);
4725 necp_kernel_policy_id socket_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
4726 necp_kernel_policy_id matched_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
4727 struct necp_kernel_ip_output_policy
*matched_policy
= NULL
;
4728 u_int16_t protocol
= 0;
4729 u_int32_t bound_interface_index
= 0;
4730 u_int32_t last_interface_index
= 0;
4731 union necp_sockaddr_union local_addr
;
4732 union necp_sockaddr_union remote_addr
;
4738 if (result_parameter
) {
4739 memset(result_parameter
, 0, sizeof(*result_parameter
));
4742 if (packet
== NULL
) {
4743 return (NECP_KERNEL_POLICY_ID_NONE
);
4746 socket_policy_id
= necp_get_policy_id_from_packet(packet
);
4748 // Exit early for an empty list
4749 // Don't lock. Possible race condition, but we don't want the performance hit.
4750 if (necp_kernel_ip_output_policies_count
== 0 ||
4751 ((socket_policy_id
== NECP_KERNEL_POLICY_ID_NONE
) && necp_kernel_ip_output_policies_non_id_count
== 0)) {
4752 if (necp_drop_all_order
> 0) {
4753 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
4755 if ((necp_pass_loopback
> 0 &&
4756 necp_is_loopback(NULL
, NULL
, NULL
, packet
)) ||
4757 (necp_pass_keepalives
> 0 &&
4758 necp_get_is_keepalive_from_packet(packet
))) {
4759 *result
= NECP_KERNEL_POLICY_RESULT_PASS
;
4761 *result
= NECP_KERNEL_POLICY_RESULT_DROP
;
4766 return (matched_policy_id
);
4769 // Check for loopback exception
4770 if ((necp_pass_loopback
> 0 &&
4771 necp_is_loopback(NULL
, NULL
, NULL
, packet
)) ||
4772 (necp_pass_keepalives
> 0 &&
4773 necp_get_is_keepalive_from_packet(packet
))) {
4774 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
4776 *result
= NECP_KERNEL_POLICY_RESULT_PASS
;
4778 return (matched_policy_id
);
4781 last_interface_index
= necp_get_last_interface_index_from_packet(packet
);
4783 // Process packet to get relevant fields
4784 ip
= mtod(packet
, struct ip
*);
4786 hlen
= _IP_VHL_HL(ip
->ip_vhl
) << 2;
4788 hlen
= ip
->ip_hl
<< 2;
4791 protocol
= ip
->ip_p
;
4793 if ((flags
& IP_OUTARGS
) && (ipoa
!= NULL
) &&
4794 (ipoa
->ipoa_flags
& IPOAF_BOUND_IF
) &&
4795 ipoa
->ipoa_boundif
!= IFSCOPE_NONE
) {
4796 bound_interface_index
= ipoa
->ipoa_boundif
;
4799 local_addr
.sin
.sin_family
= AF_INET
;
4800 local_addr
.sin
.sin_len
= sizeof(struct sockaddr_in
);
4801 memcpy(&local_addr
.sin
.sin_addr
, &ip
->ip_src
, sizeof(ip
->ip_src
));
4803 remote_addr
.sin
.sin_family
= AF_INET
;
4804 remote_addr
.sin
.sin_len
= sizeof(struct sockaddr_in
);
4805 memcpy(&((struct sockaddr_in
*)&remote_addr
)->sin_addr
, &ip
->ip_dst
, sizeof(ip
->ip_dst
));
4810 if ((int)(hlen
+ sizeof(th
)) <= packet
->m_pkthdr
.len
) {
4811 m_copydata(packet
, hlen
, sizeof(th
), (u_int8_t
*)&th
);
4812 ((struct sockaddr_in
*)&local_addr
)->sin_port
= th
.th_sport
;
4813 ((struct sockaddr_in
*)&remote_addr
)->sin_port
= th
.th_dport
;
4819 if ((int)(hlen
+ sizeof(uh
)) <= packet
->m_pkthdr
.len
) {
4820 m_copydata(packet
, hlen
, sizeof(uh
), (u_int8_t
*)&uh
);
4821 ((struct sockaddr_in
*)&local_addr
)->sin_port
= uh
.uh_sport
;
4822 ((struct sockaddr_in
*)&remote_addr
)->sin_port
= uh
.uh_dport
;
4827 ((struct sockaddr_in
*)&local_addr
)->sin_port
= 0;
4828 ((struct sockaddr_in
*)&remote_addr
)->sin_port
= 0;
4833 // Match packet to policy
4834 lck_rw_lock_shared(&necp_kernel_policy_lock
);
4835 matched_policy
= necp_ip_output_find_policy_match_locked(socket_policy_id
, bound_interface_index
, last_interface_index
, protocol
, &local_addr
, &remote_addr
);
4836 if (matched_policy
) {
4837 matched_policy_id
= matched_policy
->id
;
4839 *result
= matched_policy
->result
;
4842 if (result_parameter
) {
4843 memcpy(result_parameter
, &matched_policy
->result_parameter
, sizeof(matched_policy
->result_parameter
));
4846 if (necp_debug
> 1) {
4847 NECPLOG(LOG_DEBUG
, "IP Output: (ID %d BoundInterface %d LastInterface %d Proto %d) Policy %d Result %d Parameter %d", socket_policy_id
, bound_interface_index
, last_interface_index
, protocol
, matched_policy
->id
, matched_policy
->result
, matched_policy
->result_parameter
.tunnel_interface_index
);
4849 } else if (necp_drop_all_order
> 0) {
4850 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
4852 *result
= NECP_KERNEL_POLICY_RESULT_DROP
;
4856 lck_rw_done(&necp_kernel_policy_lock
);
4858 return (matched_policy_id
);
4861 necp_kernel_policy_id
4862 necp_ip6_output_find_policy_match(struct mbuf
*packet
, int flags
, struct ip6_out_args
*ip6oa
, necp_kernel_policy_result
*result
, necp_kernel_policy_result_parameter
*result_parameter
)
4864 struct ip6_hdr
*ip6
= NULL
;
4867 necp_kernel_policy_id socket_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
4868 necp_kernel_policy_id matched_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
4869 struct necp_kernel_ip_output_policy
*matched_policy
= NULL
;
4870 u_int16_t protocol
= 0;
4871 u_int32_t bound_interface_index
= 0;
4872 u_int32_t last_interface_index
= 0;
4873 union necp_sockaddr_union local_addr
;
4874 union necp_sockaddr_union remote_addr
;
4880 if (result_parameter
) {
4881 memset(result_parameter
, 0, sizeof(*result_parameter
));
4884 if (packet
== NULL
) {
4885 return (NECP_KERNEL_POLICY_ID_NONE
);
4888 socket_policy_id
= necp_get_policy_id_from_packet(packet
);
4890 // Exit early for an empty list
4891 // Don't lock. Possible race condition, but we don't want the performance hit.
4892 if (necp_kernel_ip_output_policies_count
== 0 ||
4893 ((socket_policy_id
== NECP_KERNEL_POLICY_ID_NONE
) && necp_kernel_ip_output_policies_non_id_count
== 0)) {
4894 if (necp_drop_all_order
> 0) {
4895 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
4897 if ((necp_pass_loopback
> 0 &&
4898 necp_is_loopback(NULL
, NULL
, NULL
, packet
)) ||
4899 (necp_pass_keepalives
> 0 &&
4900 necp_get_is_keepalive_from_packet(packet
))) {
4901 *result
= NECP_KERNEL_POLICY_RESULT_PASS
;
4903 *result
= NECP_KERNEL_POLICY_RESULT_DROP
;
4908 return (matched_policy_id
);
4911 // Check for loopback exception
4912 if ((necp_pass_loopback
> 0 &&
4913 necp_is_loopback(NULL
, NULL
, NULL
, packet
)) ||
4914 (necp_pass_keepalives
> 0 &&
4915 necp_get_is_keepalive_from_packet(packet
))) {
4916 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
4918 *result
= NECP_KERNEL_POLICY_RESULT_PASS
;
4920 return (matched_policy_id
);
4923 last_interface_index
= necp_get_last_interface_index_from_packet(packet
);
4925 // Process packet to get relevant fields
4926 ip6
= mtod(packet
, struct ip6_hdr
*);
4928 if ((flags
& IPV6_OUTARGS
) && (ip6oa
!= NULL
) &&
4929 (ip6oa
->ip6oa_flags
& IP6OAF_BOUND_IF
) &&
4930 ip6oa
->ip6oa_boundif
!= IFSCOPE_NONE
) {
4931 bound_interface_index
= ip6oa
->ip6oa_boundif
;
4934 ((struct sockaddr_in6
*)&local_addr
)->sin6_family
= AF_INET6
;
4935 ((struct sockaddr_in6
*)&local_addr
)->sin6_len
= sizeof(struct sockaddr_in6
);
4936 memcpy(&((struct sockaddr_in6
*)&local_addr
)->sin6_addr
, &ip6
->ip6_src
, sizeof(ip6
->ip6_src
));
4938 ((struct sockaddr_in6
*)&remote_addr
)->sin6_family
= AF_INET6
;
4939 ((struct sockaddr_in6
*)&remote_addr
)->sin6_len
= sizeof(struct sockaddr_in6
);
4940 memcpy(&((struct sockaddr_in6
*)&remote_addr
)->sin6_addr
, &ip6
->ip6_dst
, sizeof(ip6
->ip6_dst
));
4942 offset
= ip6_lasthdr(packet
, 0, IPPROTO_IPV6
, &next
);
4943 if (offset
>= 0 && packet
->m_pkthdr
.len
>= offset
) {
4948 if ((int)(offset
+ sizeof(th
)) <= packet
->m_pkthdr
.len
) {
4949 m_copydata(packet
, offset
, sizeof(th
), (u_int8_t
*)&th
);
4950 ((struct sockaddr_in6
*)&local_addr
)->sin6_port
= th
.th_sport
;
4951 ((struct sockaddr_in6
*)&remote_addr
)->sin6_port
= th
.th_dport
;
4957 if ((int)(offset
+ sizeof(uh
)) <= packet
->m_pkthdr
.len
) {
4958 m_copydata(packet
, offset
, sizeof(uh
), (u_int8_t
*)&uh
);
4959 ((struct sockaddr_in6
*)&local_addr
)->sin6_port
= uh
.uh_sport
;
4960 ((struct sockaddr_in6
*)&remote_addr
)->sin6_port
= uh
.uh_dport
;
4965 ((struct sockaddr_in6
*)&local_addr
)->sin6_port
= 0;
4966 ((struct sockaddr_in6
*)&remote_addr
)->sin6_port
= 0;
4972 // Match packet to policy
4973 lck_rw_lock_shared(&necp_kernel_policy_lock
);
4974 matched_policy
= necp_ip_output_find_policy_match_locked(socket_policy_id
, bound_interface_index
, last_interface_index
, protocol
, &local_addr
, &remote_addr
);
4975 if (matched_policy
) {
4976 matched_policy_id
= matched_policy
->id
;
4978 *result
= matched_policy
->result
;
4981 if (result_parameter
) {
4982 memcpy(result_parameter
, &matched_policy
->result_parameter
, sizeof(matched_policy
->result_parameter
));
4985 if (necp_debug
> 1) {
4986 NECPLOG(LOG_DEBUG
, "IP6 Output: (ID %d BoundInterface %d LastInterface %d Proto %d) Policy %d Result %d Parameter %d", socket_policy_id
, bound_interface_index
, last_interface_index
, protocol
, matched_policy
->id
, matched_policy
->result
, matched_policy
->result_parameter
.tunnel_interface_index
);
4988 } else if (necp_drop_all_order
> 0) {
4989 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
4991 *result
= NECP_KERNEL_POLICY_RESULT_DROP
;
4995 lck_rw_done(&necp_kernel_policy_lock
);
4997 return (matched_policy_id
);
5002 necp_is_addr_in_range(struct sockaddr
*addr
, struct sockaddr
*range_start
, struct sockaddr
*range_end
)
5006 if (addr
== NULL
|| range_start
== NULL
|| range_end
== NULL
) {
5010 /* Must be greater than or equal to start */
5011 cmp
= necp_addr_compare(addr
, range_start
, 1);
5012 if (cmp
!= 0 && cmp
!= 1) {
5016 /* Must be less than or equal to end */
5017 cmp
= necp_addr_compare(addr
, range_end
, 1);
5018 if (cmp
!= 0 && cmp
!= -1) {
5026 necp_is_range_in_range(struct sockaddr
*inner_range_start
, struct sockaddr
*inner_range_end
, struct sockaddr
*range_start
, struct sockaddr
*range_end
)
5030 if (inner_range_start
== NULL
|| inner_range_end
== NULL
|| range_start
== NULL
|| range_end
== NULL
) {
5034 /* Must be greater than or equal to start */
5035 cmp
= necp_addr_compare(inner_range_start
, range_start
, 1);
5036 if (cmp
!= 0 && cmp
!= 1) {
5040 /* Must be less than or equal to end */
5041 cmp
= necp_addr_compare(inner_range_end
, range_end
, 1);
5042 if (cmp
!= 0 && cmp
!= -1) {
5050 necp_is_addr_in_subnet(struct sockaddr
*addr
, struct sockaddr
*subnet_addr
, u_int8_t subnet_prefix
)
5052 if (addr
== NULL
|| subnet_addr
== NULL
) {
5056 if (addr
->sa_family
!= subnet_addr
->sa_family
|| addr
->sa_len
!= subnet_addr
->sa_len
) {
5060 switch (addr
->sa_family
) {
5062 if (satosin(subnet_addr
)->sin_port
!= 0 &&
5063 satosin(addr
)->sin_port
!= satosin(subnet_addr
)->sin_port
) {
5066 return (necp_buffer_compare_with_bit_prefix((u_int8_t
*)&satosin(addr
)->sin_addr
, (u_int8_t
*)&satosin(subnet_addr
)->sin_addr
, subnet_prefix
));
5069 if (satosin6(subnet_addr
)->sin6_port
!= 0 &&
5070 satosin6(addr
)->sin6_port
!= satosin6(subnet_addr
)->sin6_port
) {
5073 if (satosin6(addr
)->sin6_scope_id
&&
5074 satosin6(subnet_addr
)->sin6_scope_id
&&
5075 satosin6(addr
)->sin6_scope_id
!= satosin6(subnet_addr
)->sin6_scope_id
) {
5078 return (necp_buffer_compare_with_bit_prefix((u_int8_t
*)&satosin6(addr
)->sin6_addr
, (u_int8_t
*)&satosin6(subnet_addr
)->sin6_addr
, subnet_prefix
));
5093 * 2: Not comparable or error
5096 necp_addr_compare(struct sockaddr
*sa1
, struct sockaddr
*sa2
, int check_port
)
5099 int port_result
= 0;
5101 if (sa1
->sa_family
!= sa2
->sa_family
|| sa1
->sa_len
!= sa2
->sa_len
) {
5105 if (sa1
->sa_len
== 0) {
5109 switch (sa1
->sa_family
) {
5111 if (sa1
->sa_len
!= sizeof(struct sockaddr_in
)) {
5115 result
= memcmp(&satosin(sa1
)->sin_addr
.s_addr
, &satosin(sa2
)->sin_addr
.s_addr
, sizeof(satosin(sa1
)->sin_addr
.s_addr
));
5118 if (satosin(sa1
)->sin_port
< satosin(sa2
)->sin_port
) {
5120 } else if (satosin(sa1
)->sin_port
> satosin(sa2
)->sin_port
) {
5125 result
= port_result
;
5126 } else if ((result
> 0 && port_result
< 0) || (result
< 0 && port_result
> 0)) {
5134 if (sa1
->sa_len
!= sizeof(struct sockaddr_in6
)) {
5138 if (satosin6(sa1
)->sin6_scope_id
!= satosin6(sa2
)->sin6_scope_id
) {
5142 result
= memcmp(&satosin6(sa1
)->sin6_addr
.s6_addr
[0], &satosin6(sa2
)->sin6_addr
.s6_addr
[0], sizeof(struct in6_addr
));
5145 if (satosin6(sa1
)->sin6_port
< satosin6(sa2
)->sin6_port
) {
5147 } else if (satosin6(sa1
)->sin6_port
> satosin6(sa2
)->sin6_port
) {
5152 result
= port_result
;
5153 } else if ((result
> 0 && port_result
< 0) || (result
< 0 && port_result
> 0)) {
5161 result
= memcmp(sa1
, sa2
, sa1
->sa_len
);
5168 } else if (result
> 0) {
5176 necp_buffer_compare_with_bit_prefix(u_int8_t
*p1
, u_int8_t
*p2
, u_int32_t bits
)
5180 /* Handle null pointers */
5181 if (p1
== NULL
|| p2
== NULL
) {
5186 if (*p1
++ != *p2
++) {
5193 mask
= ~((1<<(8-bits
))-1);
5194 if ((*p1
& mask
) != (*p2
& mask
)) {
5201 // Socket operations
5202 #define NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH 253
5205 necp_set_socket_attribute(u_int8_t
*buffer
, size_t buffer_length
, u_int8_t type
, char **buffer_p
)
5209 size_t string_size
= 0;
5210 char *local_string
= NULL
;
5211 u_int8_t
*value
= NULL
;
5213 cursor
= necp_buffer_find_tlv(buffer
, buffer_length
, 0, type
, 0);
5215 // This will clear out the parameter
5219 string_size
= necp_buffer_get_tlv_length(buffer
, cursor
);
5220 if (string_size
== 0 || string_size
> NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH
) {
5221 // This will clear out the parameter
5225 MALLOC(local_string
, char *, string_size
+ 1, M_NECP
, M_WAITOK
);
5226 if (local_string
== NULL
) {
5227 NECPLOG(LOG_ERR
, "Failed to allocate a socket attribute buffer (size %d)", string_size
);
5231 value
= necp_buffer_get_tlv_value(buffer
, cursor
, NULL
);
5232 if (value
== NULL
) {
5233 NECPLOG0(LOG_ERR
, "Failed to get socket attribute");
5237 memcpy(local_string
, value
, string_size
);
5238 local_string
[string_size
] = 0;
5241 if (*buffer_p
!= NULL
) {
5242 FREE(*buffer_p
, M_NECP
);
5246 *buffer_p
= local_string
;
5249 if (local_string
!= NULL
) {
5250 FREE(local_string
, M_NECP
);
5256 necp_set_socket_attributes(struct socket
*so
, struct sockopt
*sopt
)
5259 u_int8_t
*buffer
= NULL
;
5260 struct inpcb
*inp
= sotoinpcb(so
);
5262 size_t valsize
= sopt
->sopt_valsize
;
5264 valsize
> ((sizeof(u_int8_t
) + sizeof(size_t) + NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH
) * 2)) {
5268 MALLOC(buffer
, u_int8_t
*, valsize
, M_NECP
, M_WAITOK
);
5269 if (buffer
== NULL
) {
5273 error
= sooptcopyin(sopt
, buffer
, valsize
, 0);
5278 error
= necp_set_socket_attribute(buffer
, valsize
, NECP_TLV_ATTRIBUTE_DOMAIN
, &inp
->inp_necp_attributes
.inp_domain
);
5280 NECPLOG0(LOG_ERR
, "Could not set domain TLV for socket attributes");
5284 error
= necp_set_socket_attribute(buffer
, valsize
, NECP_TLV_ATTRIBUTE_ACCOUNT
, &inp
->inp_necp_attributes
.inp_account
);
5286 NECPLOG0(LOG_ERR
, "Could not set account TLV for socket attributes");
5291 NECPLOG(LOG_DEBUG
, "Set on socket: Domain %s, Account %s", inp
->inp_necp_attributes
.inp_domain
, inp
->inp_necp_attributes
.inp_account
);
5294 if (buffer
!= NULL
) {
5295 FREE(buffer
, M_NECP
);
5302 necp_get_socket_attributes(struct socket
*so
, struct sockopt
*sopt
)
5305 u_int8_t
*buffer
= NULL
;
5306 u_int8_t
*cursor
= NULL
;
5308 struct inpcb
*inp
= sotoinpcb(so
);
5310 if (inp
->inp_necp_attributes
.inp_domain
!= NULL
) {
5311 valsize
+= sizeof(u_int8_t
) + sizeof(size_t) + strlen(inp
->inp_necp_attributes
.inp_domain
);
5313 if (inp
->inp_necp_attributes
.inp_account
!= NULL
) {
5314 valsize
+= sizeof(u_int8_t
) + sizeof(size_t) + strlen(inp
->inp_necp_attributes
.inp_account
);
5320 MALLOC(buffer
, u_int8_t
*, valsize
, M_NECP
, M_WAITOK
);
5321 if (buffer
== NULL
) {
5326 if (inp
->inp_necp_attributes
.inp_domain
!= NULL
) {
5327 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_ATTRIBUTE_DOMAIN
, strlen(inp
->inp_necp_attributes
.inp_domain
), inp
->inp_necp_attributes
.inp_domain
);
5330 if (inp
->inp_necp_attributes
.inp_account
!= NULL
) {
5331 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_ATTRIBUTE_ACCOUNT
, strlen(inp
->inp_necp_attributes
.inp_account
), inp
->inp_necp_attributes
.inp_account
);
5334 error
= sooptcopyout(sopt
, buffer
, valsize
);
5339 if (buffer
!= NULL
) {
5340 FREE(buffer
, M_NECP
);
5347 necp_socket_is_allowed_to_send_recv_internal(struct inpcb
*inp
, struct sockaddr
*override_local_addr
, struct sockaddr
*override_remote_addr
, ifnet_t interface
, necp_kernel_policy_id
*return_policy_id
)
5349 u_int32_t verifyifindex
= interface
? interface
->if_index
: 0;
5350 bool allowed_to_receive
= TRUE
;
5351 struct necp_socket_info info
;
5352 u_int32_t flowhash
= 0;
5353 necp_kernel_policy_result service_action
= 0;
5354 necp_kernel_policy_service service
= { 0, 0 };
5356 if (return_policy_id
) {
5357 *return_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
5364 // Don't lock. Possible race condition, but we don't want the performance hit.
5365 if (necp_kernel_socket_policies_count
== 0 ||
5366 (!(inp
->inp_flags2
& INP2_WANT_APP_POLICY
) && necp_kernel_socket_policies_non_app_count
== 0)) {
5367 if (necp_drop_all_order
> 0) {
5368 if (necp_pass_loopback
> 0 &&
5369 necp_is_loopback(override_local_addr
, override_remote_addr
, inp
, NULL
)) {
5370 allowed_to_receive
= TRUE
;
5372 allowed_to_receive
= FALSE
;
5378 // If this socket is connected, or we are not taking addresses into account, try to reuse last result
5379 if ((necp_socket_is_connected(inp
) || (override_local_addr
== NULL
&& override_remote_addr
== NULL
)) && inp
->inp_policyresult
.policy_id
!= NECP_KERNEL_POLICY_ID_NONE
) {
5380 bool policies_have_changed
= FALSE
;
5381 lck_rw_lock_shared(&necp_kernel_policy_lock
);
5382 if (inp
->inp_policyresult
.policy_gencount
!= necp_kernel_socket_policies_gencount
) {
5383 policies_have_changed
= TRUE
;
5385 lck_rw_done(&necp_kernel_policy_lock
);
5387 if (!policies_have_changed
) {
5388 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_DROP
||
5389 inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
||
5390 (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&& interface
&&
5391 inp
->inp_policyresult
.results
.result_parameter
.tunnel_interface_index
!= verifyifindex
)) {
5392 allowed_to_receive
= FALSE
;
5393 } else if (return_policy_id
) {
5394 *return_policy_id
= inp
->inp_policyresult
.policy_id
;
5400 // Check for loopback exception
5401 if (necp_pass_loopback
> 0 &&
5402 necp_is_loopback(override_local_addr
, override_remote_addr
, inp
, NULL
)) {
5403 allowed_to_receive
= TRUE
;
5407 // Actually calculate policy result
5408 lck_rw_lock_shared(&necp_kernel_policy_lock
);
5409 necp_socket_fillout_info_locked(inp
, override_local_addr
, override_remote_addr
, 0, &info
);
5411 flowhash
= necp_socket_calc_flowhash_locked(&info
);
5412 if (inp
->inp_policyresult
.policy_id
!= NECP_KERNEL_POLICY_ID_NONE
&&
5413 inp
->inp_policyresult
.policy_gencount
== necp_kernel_socket_policies_gencount
&&
5414 inp
->inp_policyresult
.flowhash
== flowhash
) {
5415 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_DROP
||
5416 inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
||
5417 (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&& interface
&&
5418 inp
->inp_policyresult
.results
.result_parameter
.tunnel_interface_index
!= verifyifindex
)) {
5419 allowed_to_receive
= FALSE
;
5420 } else if (return_policy_id
) {
5421 *return_policy_id
= inp
->inp_policyresult
.policy_id
;
5423 lck_rw_done(&necp_kernel_policy_lock
);
5427 struct necp_kernel_socket_policy
*matched_policy
= necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map
[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info
.application_id
)], &info
, NULL
, &service_action
, &service
);
5428 if (matched_policy
!= NULL
) {
5429 if (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_DROP
||
5430 matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
||
5431 (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&& interface
&&
5432 matched_policy
->result_parameter
.tunnel_interface_index
!= verifyifindex
) ||
5433 ((service_action
== NECP_KERNEL_POLICY_RESULT_TRIGGER_SCOPED
||
5434 service_action
== NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED
) &&
5435 service
.identifier
!= 0 && service
.identifier
!= NECP_NULL_SERVICE_ID
)) {
5436 allowed_to_receive
= FALSE
;
5437 } else if (return_policy_id
) {
5438 *return_policy_id
= matched_policy
->id
;
5440 lck_rw_done(&necp_kernel_policy_lock
);
5442 if (necp_debug
> 1 && matched_policy
->id
!= inp
->inp_policyresult
.policy_id
) {
5443 NECPLOG(LOG_DEBUG
, "Socket Send/Recv Policy: Policy %d Allowed %d", return_policy_id
? *return_policy_id
: 0, allowed_to_receive
);
5446 } else if (necp_drop_all_order
> 0) {
5447 allowed_to_receive
= FALSE
;
5450 lck_rw_done(&necp_kernel_policy_lock
);
5453 return (allowed_to_receive
);
5457 necp_socket_is_allowed_to_send_recv_v4(struct inpcb
*inp
, u_int16_t local_port
, u_int16_t remote_port
, struct in_addr
*local_addr
, struct in_addr
*remote_addr
, ifnet_t interface
, necp_kernel_policy_id
*return_policy_id
)
5459 struct sockaddr_in local
;
5460 struct sockaddr_in remote
;
5461 local
.sin_family
= remote
.sin_family
= AF_INET
;
5462 local
.sin_len
= remote
.sin_len
= sizeof(struct sockaddr_in
);
5463 local
.sin_port
= local_port
;
5464 remote
.sin_port
= remote_port
;
5465 memcpy(&local
.sin_addr
, local_addr
, sizeof(local
.sin_addr
));
5466 memcpy(&remote
.sin_addr
, remote_addr
, sizeof(remote
.sin_addr
));
5468 return (necp_socket_is_allowed_to_send_recv_internal(inp
, (struct sockaddr
*)&local
, (struct sockaddr
*)&remote
, interface
, return_policy_id
));
5472 necp_socket_is_allowed_to_send_recv_v6(struct inpcb
*inp
, u_int16_t local_port
, u_int16_t remote_port
, struct in6_addr
*local_addr
, struct in6_addr
*remote_addr
, ifnet_t interface
, necp_kernel_policy_id
*return_policy_id
)
5474 struct sockaddr_in6 local
;
5475 struct sockaddr_in6 remote
;
5476 local
.sin6_family
= remote
.sin6_family
= AF_INET6
;
5477 local
.sin6_len
= remote
.sin6_len
= sizeof(struct sockaddr_in6
);
5478 local
.sin6_port
= local_port
;
5479 remote
.sin6_port
= remote_port
;
5480 memcpy(&local
.sin6_addr
, local_addr
, sizeof(local
.sin6_addr
));
5481 memcpy(&remote
.sin6_addr
, remote_addr
, sizeof(remote
.sin6_addr
));
5483 return (necp_socket_is_allowed_to_send_recv_internal(inp
, (struct sockaddr
*)&local
, (struct sockaddr
*)&remote
, interface
, return_policy_id
));
5487 necp_socket_is_allowed_to_send_recv(struct inpcb
*inp
, necp_kernel_policy_id
*return_policy_id
)
5489 return (necp_socket_is_allowed_to_send_recv_internal(inp
, NULL
, NULL
, NULL
, return_policy_id
));
5493 necp_mark_packet_from_socket(struct mbuf
*packet
, struct inpcb
*inp
, necp_kernel_policy_id policy_id
)
5495 if (packet
== NULL
|| inp
== NULL
) {
5499 // Mark ID for Pass and IP Tunnel
5500 if (policy_id
!= NECP_KERNEL_POLICY_ID_NONE
) {
5501 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= policy_id
;
5502 } else if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_PASS
||
5503 inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
) {
5504 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= inp
->inp_policyresult
.policy_id
;
5506 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
5508 packet
->m_pkthdr
.necp_mtag
.necp_last_interface_index
= 0;
5514 necp_mark_packet_from_ip(struct mbuf
*packet
, necp_kernel_policy_id policy_id
)
5516 if (packet
== NULL
) {
5520 // Mark ID for Pass and IP Tunnel
5521 if (policy_id
!= NECP_KERNEL_POLICY_ID_NONE
) {
5522 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= policy_id
;
5524 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
5531 necp_mark_packet_from_interface(struct mbuf
*packet
, ifnet_t interface
)
5533 if (packet
== NULL
) {
5537 // Mark ID for Pass and IP Tunnel
5538 if (interface
!= NULL
) {
5539 packet
->m_pkthdr
.necp_mtag
.necp_last_interface_index
= interface
->if_index
;
5546 necp_mark_packet_as_keepalive(struct mbuf
*packet
, bool is_keepalive
)
5548 if (packet
== NULL
) {
5553 packet
->m_pkthdr
.pkt_flags
|= PKTF_KEEPALIVE
;
5555 packet
->m_pkthdr
.pkt_flags
&= ~PKTF_KEEPALIVE
;
5561 necp_kernel_policy_id
5562 necp_get_policy_id_from_packet(struct mbuf
*packet
)
5564 if (packet
== NULL
) {
5565 return (NECP_KERNEL_POLICY_ID_NONE
);
5568 return (packet
->m_pkthdr
.necp_mtag
.necp_policy_id
);
5572 necp_get_last_interface_index_from_packet(struct mbuf
*packet
)
5574 if (packet
== NULL
) {
5578 return (packet
->m_pkthdr
.necp_mtag
.necp_last_interface_index
);
5582 necp_get_is_keepalive_from_packet(struct mbuf
*packet
)
5584 if (packet
== NULL
) {
5588 return (packet
->m_pkthdr
.pkt_flags
& PKTF_KEEPALIVE
);
5592 necp_socket_get_content_filter_control_unit(struct socket
*so
)
5594 struct inpcb
*inp
= sotoinpcb(so
);
5599 return (inp
->inp_policyresult
.results
.filter_control_unit
);
5603 necp_socket_should_use_flow_divert(struct inpcb
*inp
)
5609 return (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
);
5613 necp_socket_get_flow_divert_control_unit(struct inpcb
*inp
)
5619 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
) {
5620 return (inp
->inp_policyresult
.results
.result_parameter
.flow_divert_control_unit
);
5627 necp_socket_should_rescope(struct inpcb
*inp
)
5633 return (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
);
5637 necp_socket_get_rescope_if_index(struct inpcb
*inp
)
5643 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
) {
5644 return (inp
->inp_policyresult
.results
.result_parameter
.scoped_interface_index
);
5651 necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter
*result_parameter
)
5653 if (result_parameter
== NULL
) {
5657 return (ifindex2ifnet
[result_parameter
->tunnel_interface_index
]);
5661 necp_packet_can_rebind_to_ifnet(struct mbuf
*packet
, struct ifnet
*interface
, struct route
*new_route
, int family
)
5663 bool found_match
= FALSE
;
5665 ifaddr_t
*addresses
= NULL
;
5666 union necp_sockaddr_union address_storage
;
5669 if (packet
== NULL
|| interface
== NULL
|| new_route
== NULL
|| (family
!= AF_INET
&& family
!= AF_INET6
)) {
5673 result
= ifnet_get_address_list_family(interface
, &addresses
, family
);
5675 NECPLOG(LOG_ERR
, "Failed to get address list for %s%d", ifnet_name(interface
), ifnet_unit(interface
));
5679 for (i
= 0; addresses
[i
] != NULL
; i
++) {
5680 ROUTE_RELEASE(new_route
);
5681 if (ifaddr_address(addresses
[i
], &address_storage
.sa
, sizeof(address_storage
)) == 0) {
5682 if (family
== AF_INET
) {
5683 struct ip
*ip
= mtod(packet
, struct ip
*);
5684 if (memcmp(&address_storage
.sin
.sin_addr
, &ip
->ip_src
, sizeof(ip
->ip_src
)) == 0) {
5685 struct sockaddr_in
*dst4
= (struct sockaddr_in
*)(void *)&new_route
->ro_dst
;
5686 dst4
->sin_family
= AF_INET
;
5687 dst4
->sin_len
= sizeof(struct sockaddr_in
);
5688 dst4
->sin_addr
= ip
->ip_dst
;
5689 rtalloc_scoped(new_route
, interface
->if_index
);
5690 if (!ROUTE_UNUSABLE(new_route
)) {
5695 } else if (family
== AF_INET6
) {
5696 struct ip6_hdr
*ip6
= mtod(packet
, struct ip6_hdr
*);
5697 if (memcmp(&address_storage
.sin6
.sin6_addr
, &ip6
->ip6_src
, sizeof(ip6
->ip6_src
)) == 0) {
5698 struct sockaddr_in6
*dst6
= (struct sockaddr_in6
*)(void *)&new_route
->ro_dst
;
5699 dst6
->sin6_family
= AF_INET6
;
5700 dst6
->sin6_len
= sizeof(struct sockaddr_in6
);
5701 dst6
->sin6_addr
= ip6
->ip6_dst
;
5702 rtalloc_scoped(new_route
, interface
->if_index
);
5703 if (!ROUTE_UNUSABLE(new_route
)) {
5713 ifnet_free_address_list(addresses
);
5715 return (found_match
);
5719 necp_addr_is_loopback(struct sockaddr
*address
)
5721 if (address
== NULL
) {
5725 if (address
->sa_family
== AF_INET
) {
5726 return (ntohl(((struct sockaddr_in
*)(void *)address
)->sin_addr
.s_addr
) == INADDR_LOOPBACK
);
5727 } else if (address
->sa_family
== AF_INET6
) {
5728 return IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6
*)(void *)address
)->sin6_addr
);
5735 necp_is_loopback(struct sockaddr
*local_addr
, struct sockaddr
*remote_addr
, struct inpcb
*inp
, struct mbuf
*packet
)
5737 // Note: This function only checks for the loopback addresses.
5738 // In the future, we may want to expand to also allow any traffic
5739 // going through the loopback interface, but until then, this
5740 // check is cheaper.
5742 if (local_addr
!= NULL
&& necp_addr_is_loopback(local_addr
)) {
5746 if (remote_addr
!= NULL
&& necp_addr_is_loopback(remote_addr
)) {
5751 if ((inp
->inp_flags
& INP_BOUND_IF
) && inp
->inp_boundifp
&& (inp
->inp_boundifp
->if_flags
& IFF_LOOPBACK
)) {
5754 if (inp
->inp_vflag
& INP_IPV4
) {
5755 if (ntohl(inp
->inp_laddr
.s_addr
) == INADDR_LOOPBACK
||
5756 ntohl(inp
->inp_faddr
.s_addr
) == INADDR_LOOPBACK
) {
5759 } else if (inp
->inp_vflag
& INP_IPV6
) {
5760 if (IN6_IS_ADDR_LOOPBACK(&inp
->in6p_laddr
) ||
5761 IN6_IS_ADDR_LOOPBACK(&inp
->in6p_faddr
)) {
5767 if (packet
!= NULL
) {
5768 struct ip
*ip
= mtod(packet
, struct ip
*);
5769 if (ip
->ip_v
== 4) {
5770 if (ntohl(ip
->ip_src
.s_addr
) == INADDR_LOOPBACK
) {
5773 if (ntohl(ip
->ip_dst
.s_addr
) == INADDR_LOOPBACK
) {
5776 } else if (ip
->ip_v
== 6) {
5777 struct ip6_hdr
*ip6
= mtod(packet
, struct ip6_hdr
*);
5778 if (IN6_IS_ADDR_LOOPBACK(&ip6
->ip6_src
)) {
5781 if (IN6_IS_ADDR_LOOPBACK(&ip6
->ip6_dst
)) {