2 * Copyright (c) 2013-2020 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/queue.h>
33 #include <sys/malloc.h>
34 #include <sys/kernel.h>
35 #include <sys/kern_control.h>
37 #include <sys/kpi_mbuf.h>
38 #include <sys/proc_uuid_policy.h>
40 #include <sys/domain.h>
41 #include <sys/protosw.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/coalition.h>
46 #include <sys/codesign.h>
47 #include <kern/cs_blobs.h>
48 #include <netinet/ip.h>
49 #include <netinet/ip6.h>
50 #include <netinet/tcp.h>
51 #include <netinet/tcp_var.h>
52 #include <netinet/tcp_cache.h>
53 #include <netinet/udp.h>
54 #include <netinet/in_pcb.h>
55 #include <netinet/in_tclass.h>
56 #include <netinet6/esp.h>
57 #include <net/flowhash.h>
58 #include <net/if_var.h>
59 #include <sys/kauth.h>
60 #include <sys/sysctl.h>
61 #include <sys/sysproto.h>
63 #include <sys/kern_event.h>
64 #include <sys/file_internal.h>
65 #include <IOKit/IOBSD.h>
66 #include <libkern/crypto/rand.h>
67 #include <corecrypto/cchmac.h>
68 #include <corecrypto/ccsha2.h>
69 #include <os/refcnt.h>
70 #include <net/network_agent.h>
72 #include <netinet/flow_divert_proto.h>
75 * NECP - Network Extension Control Policy database
76 * ------------------------------------------------
77 * The goal of this module is to allow clients connecting via a
78 * policy file descriptor to create high-level policy sessions, which
79 * are ingested into low-level kernel policies that control and tag
80 * traffic at the application, socket, and IP layers.
82 * ------------------------------------------------
84 * ------------------------------------------------
85 * Each session owns a list of session policies, each of which can
86 * specify any combination of conditions and a single result. Each
87 * session also has a priority level (such as High, Default, or Low)
88 * which is requested by the client. Based on the requested level,
89 * a session order value is assigned to the session, which will be used
90 * to sort kernel policies generated by the session. The session client
91 * can specify the sub-order for each policy it creates which will be
92 * used to further sort the kernel policies.
94 * Policy fd --> 1 necp_session --> list of necp_session_policy structs
96 * ------------------------------------------------
98 * ------------------------------------------------
99 * Whenever a session send the Apply command, its policies are ingested
100 * and generate kernel policies. There are two phases of kernel policy
103 * 1. The session policy is parsed to create kernel policies at the socket
104 * and IP layers, when applicable. For example, a policy that requires
105 * all traffic from App1 to Pass will generate a socket kernel policy to
106 * match App1 and mark packets with ID1, and also an IP policy to match
107 * ID1 and let the packet pass. This is handled in necp_apply_policy. The
108 * resulting kernel policies are added to the global socket and IP layer
110 * necp_session_policy --> necp_kernel_socket_policy and necp_kernel_ip_output_policy
113 * necp_kernel_socket_policies necp_kernel_ip_output_policies
115 * 2. Once the global lists of kernel policies have been filled out, each
116 * list is traversed to create optimized sub-lists ("Maps") which are used during
117 * data-path evaluation. IP policies are sent into necp_kernel_ip_output_policies_map,
118 * which hashes incoming packets based on marked socket-layer policies, and removes
119 * duplicate or overlapping policies. Socket policies are sent into two maps,
120 * necp_kernel_socket_policies_map and necp_kernel_socket_policies_app_layer_map.
121 * The app layer map is used for policy checks coming in from user space, and is one
122 * list with duplicate and overlapping policies removed. The socket map hashes based
123 * on app UUID, and removes duplicate and overlapping policies.
124 * necp_kernel_socket_policy --> necp_kernel_socket_policies_app_layer_map
125 * |-> necp_kernel_socket_policies_map
127 * necp_kernel_ip_output_policies --> necp_kernel_ip_output_policies_map
129 * ------------------------------------------------
131 * ------------------------------------------------
132 * The Drop All Level is a sysctl that controls the level at which policies are allowed
133 * to override a global drop rule. If the value is 0, no drop rule is applied. If the value
134 * is 1, all traffic is dropped. If the value is greater than 1, all kernel policies created
135 * by a session with a priority level better than (numerically less than) the
136 * Drop All Level will allow matching traffic to not be dropped. The Drop All Level is
137 * dynamically interpreted into necp_drop_all_order, which specifies the equivalent assigned
138 * session orders to be dropped.
141 u_int32_t necp_drop_all_order
= 0;
142 u_int32_t necp_drop_all_level
= 0;
144 u_int32_t necp_pass_loopback
= 1; // 0=Off, 1=On
145 u_int32_t necp_pass_keepalives
= 1; // 0=Off, 1=On
146 u_int32_t necp_pass_interpose
= 1; // 0=Off, 1=On
147 u_int32_t necp_restrict_multicast
= 1; // 0=Off, 1=On
148 u_int32_t necp_dedup_policies
= 0; // 0=Off, 1=On
150 u_int32_t necp_drop_unentitled_order
= 0;
151 #ifdef XNU_TARGET_OS_WATCH
152 u_int32_t necp_drop_unentitled_level
= NECP_SESSION_PRIORITY_CONTROL
+ 1; // Block all unentitled traffic from policies below control level
153 #else // XNU_TARGET_OS_WATCH
154 u_int32_t necp_drop_unentitled_level
= 0;
155 #endif // XNU_TARGET_OS_WATCH
157 u_int32_t necp_debug
= 0; // 0=None, 1=Basic, 2=EveryMatch
159 os_log_t necp_log_handle
= NULL
;
161 u_int32_t necp_session_count
= 0;
163 ZONE_DECLARE(necp_session_policy_zone
, "necp_session_policy",
164 sizeof(struct necp_session_policy
), ZC_ZFREE_CLEARMEM
| ZC_NOENCRYPT
);
165 ZONE_DECLARE(necp_socket_policy_zone
, "necp_socket_policy",
166 sizeof(struct necp_kernel_socket_policy
), ZC_ZFREE_CLEARMEM
| ZC_NOENCRYPT
);
167 ZONE_DECLARE(necp_ip_policy_zone
, "necp_ip_policy",
168 sizeof(struct necp_kernel_ip_output_policy
), ZC_ZFREE_CLEARMEM
| ZC_NOENCRYPT
);
170 #define LIST_INSERT_SORTED_ASCENDING(head, elm, field, sortfield, tmpelm) do { \
171 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->sortfield >= (elm)->sortfield)) { \
172 LIST_INSERT_HEAD((head), elm, field); \
174 LIST_FOREACH(tmpelm, head, field) { \
175 if (LIST_NEXT(tmpelm, field) == NULL || LIST_NEXT(tmpelm, field)->sortfield >= (elm)->sortfield) { \
176 LIST_INSERT_AFTER(tmpelm, elm, field); \
183 #define LIST_INSERT_SORTED_TWICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, tmpelm) do { \
184 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield))) { \
185 LIST_INSERT_HEAD((head), elm, field); \
187 LIST_FOREACH(tmpelm, head, field) { \
188 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))) { \
189 LIST_INSERT_AFTER(tmpelm, elm, field); \
196 #define LIST_INSERT_SORTED_THRICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, thirdsortfield, tmpelm) do { \
197 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))) { \
198 LIST_INSERT_HEAD((head), elm, field); \
200 LIST_FOREACH(tmpelm, head, field) { \
201 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))) { \
202 LIST_INSERT_AFTER(tmpelm, elm, field); \
209 #define IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(x) ((x) == NECP_ROUTE_RULE_DENY_INTERFACE || (x) == NECP_ROUTE_RULE_ALLOW_INTERFACE)
211 #define IS_NECP_DEST_IN_LOCAL_NETWORKS(rt) \
212 ((rt) != NULL && !((rt)->rt_flags & RTF_GATEWAY) && ((rt)->rt_ifa && (rt)->rt_ifa->ifa_ifp && !((rt)->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT)))
214 #define NECP_KERNEL_CONDITION_ALL_INTERFACES 0x000001
215 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE 0x000002
216 #define NECP_KERNEL_CONDITION_PROTOCOL 0x000004
217 #define NECP_KERNEL_CONDITION_LOCAL_START 0x000008
218 #define NECP_KERNEL_CONDITION_LOCAL_END 0x000010
219 #define NECP_KERNEL_CONDITION_LOCAL_PREFIX 0x000020
220 #define NECP_KERNEL_CONDITION_REMOTE_START 0x000040
221 #define NECP_KERNEL_CONDITION_REMOTE_END 0x000080
222 #define NECP_KERNEL_CONDITION_REMOTE_PREFIX 0x000100
223 #define NECP_KERNEL_CONDITION_APP_ID 0x000200
224 #define NECP_KERNEL_CONDITION_REAL_APP_ID 0x000400
225 #define NECP_KERNEL_CONDITION_DOMAIN 0x000800
226 #define NECP_KERNEL_CONDITION_ACCOUNT_ID 0x001000
227 #define NECP_KERNEL_CONDITION_POLICY_ID 0x002000
228 #define NECP_KERNEL_CONDITION_PID 0x004000
229 #define NECP_KERNEL_CONDITION_UID 0x008000
230 #define NECP_KERNEL_CONDITION_LAST_INTERFACE 0x010000 // Only set from packets looping between interfaces
231 #define NECP_KERNEL_CONDITION_TRAFFIC_CLASS 0x020000
232 #define NECP_KERNEL_CONDITION_ENTITLEMENT 0x040000
233 #define NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT 0x080000
234 #define NECP_KERNEL_CONDITION_AGENT_TYPE 0x100000
235 #define NECP_KERNEL_CONDITION_HAS_CLIENT 0x200000
236 #define NECP_KERNEL_CONDITION_LOCAL_NETWORKS 0x400000
237 #define NECP_KERNEL_CONDITION_CLIENT_FLAGS 0x800000
238 #define NECP_KERNEL_CONDITION_LOCAL_EMPTY 0x1000000
239 #define NECP_KERNEL_CONDITION_REMOTE_EMPTY 0x2000000
240 #define NECP_KERNEL_CONDITION_PLATFORM_BINARY 0x4000000
241 #define NECP_KERNEL_CONDITION_SDK_VERSION 0x8000000
242 #define NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER 0x10000000
243 #define NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS 0x20000000
245 #define NECP_MAX_POLICY_RESULT_SIZE 512
246 #define NECP_MAX_ROUTE_RULES_ARRAY_SIZE 1024
247 #define NECP_MAX_CONDITIONS_ARRAY_SIZE 4096
248 #define NECP_MAX_POLICY_LIST_COUNT 1024
250 // Cap the policy size at the max result + conditions size, with room for extra TLVs
251 #define NECP_MAX_POLICY_SIZE (1024 + NECP_MAX_POLICY_RESULT_SIZE + NECP_MAX_CONDITIONS_ARRAY_SIZE)
253 struct necp_service_registration
{
254 LIST_ENTRY(necp_service_registration
) session_chain
;
255 LIST_ENTRY(necp_service_registration
) kernel_chain
;
256 u_int32_t service_id
;
259 struct necp_session
{
260 u_int8_t necp_fd_type
;
261 u_int32_t control_unit
;
262 u_int32_t session_priority
; // Descriptive priority rating
263 u_int32_t session_order
;
265 necp_policy_id last_policy_id
;
267 decl_lck_mtx_data(, lock
);
269 bool proc_locked
; // Messages must come from proc_uuid
274 LIST_HEAD(_policies
, necp_session_policy
) policies
;
276 LIST_HEAD(_services
, necp_service_registration
) services
;
278 TAILQ_ENTRY(necp_session
) chain
;
281 #define NECP_SESSION_LOCK(_s) lck_mtx_lock(&_s->lock)
282 #define NECP_SESSION_UNLOCK(_s) lck_mtx_unlock(&_s->lock)
284 static TAILQ_HEAD(_necp_session_list
, necp_session
) necp_session_list
;
286 struct necp_socket_info
{
289 union necp_sockaddr_union local_addr
;
290 union necp_sockaddr_union remote_addr
;
291 u_int32_t bound_interface_index
;
292 u_int32_t traffic_class
;
294 u_int32_t application_id
;
295 u_int32_t real_application_id
;
296 u_int32_t account_id
;
297 u_int32_t drop_order
;
298 u_int32_t client_flags
;
301 unsigned has_client
: 1;
302 unsigned is_platform_binary
: 1;
303 unsigned used_responsible_pid
: 1;
304 unsigned __pad_bits
: 5;
307 static lck_grp_attr_t
*necp_kernel_policy_grp_attr
= NULL
;
308 static lck_attr_t
*necp_kernel_policy_mtx_attr
= NULL
;
309 static lck_grp_t
*necp_kernel_policy_mtx_grp
= NULL
;
310 decl_lck_rw_data(static, necp_kernel_policy_lock
);
312 static lck_grp_attr_t
*necp_route_rule_grp_attr
= NULL
;
313 static lck_attr_t
*necp_route_rule_mtx_attr
= NULL
;
314 static lck_grp_t
*necp_route_rule_mtx_grp
= NULL
;
315 decl_lck_rw_data(static, necp_route_rule_lock
);
317 os_refgrp_decl(static, necp_refgrp
, "NECPRefGroup", NULL
);
320 * On modification, invalidate cached lookups by bumping the generation count.
321 * Other calls will need to take the slowpath of taking
322 * the subsystem lock.
324 static volatile int32_t necp_kernel_socket_policies_gencount
;
325 #define BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT() do { \
326 if (OSIncrementAtomic(&necp_kernel_socket_policies_gencount) == (INT32_MAX - 1)) { \
327 necp_kernel_socket_policies_gencount = 1; \
333 * Allow priviledged processes to bypass the default drop-all
334 * via entitlement check. For OSX, since entitlement check is
335 * not supported for configd, configd signing identity is checked
338 #define SIGNING_ID_CONFIGD "com.apple.configd"
339 #define SIGNING_ID_CONFIGD_LEN (sizeof(SIGNING_ID_CONFIGD) - 1)
342 NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
= 0,
343 NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE
= 1,
344 NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
= 2,
345 } necp_drop_all_bypass_check_result_t
;
347 static u_int32_t necp_kernel_application_policies_condition_mask
;
348 static size_t necp_kernel_application_policies_count
;
349 static u_int32_t necp_kernel_socket_policies_condition_mask
;
350 static size_t necp_kernel_socket_policies_count
;
351 static size_t necp_kernel_socket_policies_non_app_count
;
352 static LIST_HEAD(_necpkernelsocketconnectpolicies
, necp_kernel_socket_policy
) necp_kernel_socket_policies
;
353 #define NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS 5
354 #define NECP_SOCKET_MAP_APP_ID_TO_BUCKET(appid) (appid ? (appid%(NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS - 1) + 1) : 0)
355 static struct necp_kernel_socket_policy
**necp_kernel_socket_policies_map
[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
];
356 static struct necp_kernel_socket_policy
**necp_kernel_socket_policies_app_layer_map
;
358 * A note on policy 'maps': these are used for boosting efficiency when matching policies. For each dimension of the map,
359 * such as an ID, the 0 bucket is reserved for sockets/packets that do not have this parameter, while the other
360 * buckets lead to an array of policy pointers that form the list applicable when the (parameter%(NUM_BUCKETS - 1) + 1) == bucket_index.
362 * For example, a packet with policy ID of 7, when there are 4 ID buckets, will map to bucket (7%3 + 1) = 2.
365 static u_int32_t necp_kernel_ip_output_policies_condition_mask
;
366 static size_t necp_kernel_ip_output_policies_count
;
367 static size_t necp_kernel_ip_output_policies_non_id_count
;
368 static LIST_HEAD(_necpkernelipoutputpolicies
, necp_kernel_ip_output_policy
) necp_kernel_ip_output_policies
;
369 #define NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS 5
370 #define NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(id) (id ? (id%(NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS - 1) + 1) : 0)
371 static struct necp_kernel_ip_output_policy
**necp_kernel_ip_output_policies_map
[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
];
372 static struct necp_kernel_socket_policy pass_policy
=
374 .id
= NECP_KERNEL_POLICY_ID_NO_MATCH
,
375 .result
= NECP_KERNEL_POLICY_RESULT_PASS
,
378 static struct necp_session
*necp_create_session(void);
379 static void necp_delete_session(struct necp_session
*session
);
381 static necp_policy_id
necp_handle_policy_add(struct necp_session
*session
,
382 u_int8_t
*tlv_buffer
, size_t tlv_buffer_length
, int offset
, int *error
);
383 static int necp_handle_policy_dump_all(user_addr_t out_buffer
, size_t out_buffer_length
);
385 #define MAX_RESULT_STRING_LEN 64
386 static inline const char * necp_get_result_description(char *result_string
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
);
388 static struct necp_session_policy
*necp_policy_create(struct necp_session
*session
, necp_policy_order order
, u_int8_t
*conditions_array
, u_int32_t conditions_array_size
, u_int8_t
*route_rules_array
, u_int32_t route_rules_array_size
, u_int8_t
*result
, u_int32_t result_size
);
389 static struct necp_session_policy
*necp_policy_find(struct necp_session
*session
, necp_policy_id policy_id
);
390 static bool necp_policy_mark_for_deletion(struct necp_session
*session
, struct necp_session_policy
*policy
);
391 static bool necp_policy_mark_all_for_deletion(struct necp_session
*session
);
392 static bool necp_policy_delete(struct necp_session
*session
, struct necp_session_policy
*policy
);
393 static void necp_policy_apply_all(struct necp_session
*session
);
395 static necp_kernel_policy_id
necp_kernel_socket_policy_add(necp_policy_order order
, u_int32_t session_order
, int session_pid
, u_int32_t condition_mask
, u_int32_t condition_negated_mask
, necp_app_id cond_app_id
, necp_app_id cond_real_app_id
, char *cond_custom_entitlement
, 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
, struct necp_policy_condition_agent_type
*cond_agent_type
, struct necp_policy_condition_sdk_version
*cond_sdk_version
, u_int32_t cond_client_flags
, char *cond_signing_identifier
, u_int16_t cond_packet_filter_tags
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
);
396 static bool necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id
);
397 static bool necp_kernel_socket_policies_reprocess(void);
398 static bool necp_kernel_socket_policies_update_uuid_table(void);
399 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
, u_int32_t
*return_route_rule_id_array
, size_t *return_route_rule_id_array_count
, size_t route_rule_id_array_count
, necp_kernel_policy_result
*return_service_action
, necp_kernel_policy_service
*return_service
, u_int32_t
*return_netagent_array
, u_int32_t
*return_netagent_use_flags_array
, size_t netagent_array_count
, struct necp_client_parameter_netagent_type
*required_agent_types
, u_int32_t num_required_agent_types
, proc_t proc
, u_int16_t pf_tag
, necp_kernel_policy_id
*skip_policy_id
, struct rtentry
*rt
, necp_kernel_policy_result
*return_drop_dest_policy_result
, necp_drop_all_bypass_check_result_t
*return_drop_all_bypass
, u_int32_t
*return_flow_divert_aggregate_unit
);
401 static necp_kernel_policy_id
necp_kernel_ip_output_policy_add(necp_policy_order order
, necp_policy_order suborder
, u_int32_t session_order
, int session_pid
, 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
, u_int16_t cond_packet_filter_tags
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
);
402 static bool necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id
);
403 static bool necp_kernel_ip_output_policies_reprocess(void);
405 static bool necp_is_addr_in_range(struct sockaddr
*addr
, struct sockaddr
*range_start
, struct sockaddr
*range_end
);
406 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
);
407 static bool necp_is_addr_in_subnet(struct sockaddr
*addr
, struct sockaddr
*subnet_addr
, u_int8_t subnet_prefix
);
408 static int necp_addr_compare(struct sockaddr
*sa1
, struct sockaddr
*sa2
, int check_port
);
409 static bool necp_buffer_compare_with_bit_prefix(u_int8_t
*p1
, u_int8_t
*p2
, u_int32_t bits
);
410 static bool necp_addr_is_empty(struct sockaddr
*addr
);
411 static bool necp_is_loopback(struct sockaddr
*local_addr
, struct sockaddr
*remote_addr
, struct inpcb
*inp
, struct mbuf
*packet
, u_int32_t bound_interface_index
);
412 static bool necp_is_intcoproc(struct inpcb
*inp
, struct mbuf
*packet
);
414 struct necp_uuid_id_mapping
{
415 LIST_ENTRY(necp_uuid_id_mapping
) chain
;
418 os_refcnt_t refcount
;
419 u_int32_t table_usecount
; // Add to UUID policy table count
421 static size_t necp_num_uuid_app_id_mappings
;
422 static bool necp_uuid_app_id_mappings_dirty
;
423 #define NECP_UUID_APP_ID_HASH_SIZE 64
424 static u_long necp_uuid_app_id_hash_mask
;
425 static u_long necp_uuid_app_id_hash_num_buckets
;
426 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
427 #define APPUUIDHASH(uuid) (&necp_uuid_app_id_hashtbl[uuid[0] & necp_uuid_app_id_hash_mask]) // Assume first byte of UUIDs are evenly distributed
428 static u_int32_t
necp_create_uuid_app_id_mapping(uuid_t uuid
, bool *allocated_mapping
, bool uuid_policy_table
);
429 static bool necp_remove_uuid_app_id_mapping(uuid_t uuid
, bool *removed_mapping
, bool uuid_policy_table
);
430 static struct necp_uuid_id_mapping
*necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id
);
432 static struct necp_uuid_id_mapping
*necp_uuid_lookup_service_id_locked(uuid_t uuid
);
433 static struct necp_uuid_id_mapping
*necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id
);
434 static u_int32_t
necp_create_uuid_service_id_mapping(uuid_t uuid
);
435 static bool necp_remove_uuid_service_id_mapping(uuid_t uuid
);
437 struct necp_string_id_mapping
{
438 LIST_ENTRY(necp_string_id_mapping
) chain
;
441 os_refcnt_t refcount
;
443 static LIST_HEAD(necp_string_id_mapping_list
, necp_string_id_mapping
) necp_account_id_list
;
444 static u_int32_t
necp_create_string_to_id_mapping(struct necp_string_id_mapping_list
*list
, char *domain
);
445 static bool necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list
*list
, char *domain
);
446 static struct necp_string_id_mapping
*necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list
*list
, u_int32_t local_id
);
448 static struct necp_kernel_socket_policy
*necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id
);
449 static struct necp_kernel_ip_output_policy
*necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id
);
451 static LIST_HEAD(_necp_kernel_service_list
, necp_service_registration
) necp_registered_service_list
;
453 static char *necp_create_trimmed_domain(char *string
, size_t length
);
454 static inline int necp_count_dots(char *string
, size_t length
);
456 static char *necp_copy_string(char *string
, size_t length
);
457 static bool necp_update_qos_marking(struct ifnet
*ifp
, u_int32_t route_rule_id
);
459 #define ROUTE_RULE_IS_AGGREGATE(ruleid) (ruleid > UINT16_MAX)
461 #define MAX_ROUTE_RULE_INTERFACES 10
462 struct necp_route_rule
{
463 LIST_ENTRY(necp_route_rule
) chain
;
465 u_int32_t default_action
;
466 u_int8_t cellular_action
;
467 u_int8_t wifi_action
;
468 u_int8_t wired_action
;
469 u_int8_t expensive_action
;
470 u_int8_t constrained_action
;
471 u_int exception_if_indices
[MAX_ROUTE_RULE_INTERFACES
];
472 u_int8_t exception_if_actions
[MAX_ROUTE_RULE_INTERFACES
];
473 os_refcnt_t refcount
;
475 static LIST_HEAD(necp_route_rule_list
, necp_route_rule
) necp_route_rules
;
476 static u_int32_t
necp_create_route_rule(struct necp_route_rule_list
*list
, u_int8_t
*route_rules_array
, u_int32_t route_rules_array_size
);
477 static bool necp_remove_route_rule(struct necp_route_rule_list
*list
, u_int32_t route_rule_id
);
478 static bool necp_route_is_allowed(struct rtentry
*route
, ifnet_t interface
, u_int32_t route_rule_id
, u_int32_t
*interface_type_denied
);
479 static struct necp_route_rule
*necp_lookup_route_rule_locked(struct necp_route_rule_list
*list
, u_int32_t route_rule_id
);
480 static inline void necp_get_parent_cred_result(proc_t proc
, struct necp_socket_info
*info
);
482 #define MAX_AGGREGATE_ROUTE_RULES 16
483 struct necp_aggregate_route_rule
{
484 LIST_ENTRY(necp_aggregate_route_rule
) chain
;
486 u_int32_t rule_ids
[MAX_AGGREGATE_ROUTE_RULES
];
488 static LIST_HEAD(necp_aggregate_route_rule_list
, necp_aggregate_route_rule
) necp_aggregate_route_rules
;
489 static u_int32_t
necp_create_aggregate_route_rule(u_int32_t
*rule_ids
);
491 // Sysctl definitions
492 static int sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
;
493 static int sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS
;
495 SYSCTL_NODE(_net
, OID_AUTO
, necp
, CTLFLAG_RW
| CTLFLAG_LOCKED
, 0, "NECP");
496 SYSCTL_INT(_net_necp
, NECPCTL_DEDUP_POLICIES
, dedup_policies
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_dedup_policies
, 0, "");
497 SYSCTL_INT(_net_necp
, NECPCTL_RESTRICT_MULTICAST
, restrict_multicast
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_restrict_multicast
, 0, "");
498 SYSCTL_INT(_net_necp
, NECPCTL_PASS_LOOPBACK
, pass_loopback
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_pass_loopback
, 0, "");
499 SYSCTL_INT(_net_necp
, NECPCTL_PASS_KEEPALIVES
, pass_keepalives
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_pass_keepalives
, 0, "");
500 SYSCTL_INT(_net_necp
, NECPCTL_PASS_INTERPOSE
, pass_interpose
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_pass_interpose
, 0, "");
501 SYSCTL_INT(_net_necp
, NECPCTL_DEBUG
, debug
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_debug
, 0, "");
502 SYSCTL_PROC(_net_necp
, NECPCTL_DROP_UNENTITLED_LEVEL
, drop_unentitled_level
, CTLTYPE_INT
| CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_drop_unentitled_level
, 0, &sysctl_handle_necp_unentitled_level
, "IU", "");
503 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", "");
504 SYSCTL_LONG(_net_necp
, NECPCTL_SOCKET_POLICY_COUNT
, socket_policy_count
, CTLFLAG_LOCKED
| CTLFLAG_RD
, &necp_kernel_socket_policies_count
, "");
505 SYSCTL_LONG(_net_necp
, NECPCTL_SOCKET_NON_APP_POLICY_COUNT
, socket_non_app_policy_count
, CTLFLAG_LOCKED
| CTLFLAG_RD
, &necp_kernel_socket_policies_non_app_count
, "");
506 SYSCTL_LONG(_net_necp
, NECPCTL_IP_POLICY_COUNT
, ip_policy_count
, CTLFLAG_LOCKED
| CTLFLAG_RD
, &necp_kernel_ip_output_policies_count
, "");
507 SYSCTL_INT(_net_necp
, NECPCTL_SESSION_COUNT
, session_count
, CTLFLAG_LOCKED
| CTLFLAG_RD
, &necp_session_count
, 0, "");
509 static struct necp_drop_dest_policy necp_drop_dest_policy
;
510 static int necp_drop_dest_debug
= 0; // 0: off, 1: match, >1: every evaluation
511 SYSCTL_INT(_net_necp
, OID_AUTO
, drop_dest_debug
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_drop_dest_debug
, 0, "");
513 static int sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS
;
514 SYSCTL_PROC(_net_necp
, OID_AUTO
, drop_dest_level
, CTLTYPE_STRUCT
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
| CTLFLAG_RW
,
515 0, 0, &sysctl_handle_necp_drop_dest_level
, "S,necp_drop_dest_level", "");
517 static bool necp_address_matches_drop_dest_policy(union necp_sockaddr_union
*, u_int32_t
);
519 // Session order allocation
521 necp_allocate_new_session_order(u_int32_t priority
, u_int32_t control_unit
)
523 u_int32_t new_order
= 0;
525 // For now, just allocate 1000 orders for each priority
526 if (priority
== NECP_SESSION_PRIORITY_UNKNOWN
|| priority
> NECP_SESSION_NUM_PRIORITIES
) {
527 priority
= NECP_SESSION_PRIORITY_DEFAULT
;
530 // Use the control unit to decide the offset into the priority list
531 new_order
= (control_unit
) + ((priority
- 1) * 1000);
536 static inline u_int32_t
537 necp_get_first_order_for_priority(u_int32_t priority
)
542 return ((priority
- 1) * 1000) + 1;
547 sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
549 #pragma unused(arg1, arg2)
550 int error
= sysctl_handle_int(oidp
, oidp
->oid_arg1
, oidp
->oid_arg2
, req
);
551 necp_drop_all_order
= necp_get_first_order_for_priority(necp_drop_all_level
);
556 sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS
558 #pragma unused(arg1, arg2)
559 int error
= sysctl_handle_int(oidp
, oidp
->oid_arg1
, oidp
->oid_arg2
, req
);
560 necp_drop_unentitled_order
= necp_get_first_order_for_priority(necp_drop_unentitled_level
);
564 // Use a macro here to avoid computing the kauth_cred_t when necp_drop_unentitled_level is 0
565 static inline u_int32_t
566 _necp_process_drop_order_inner(kauth_cred_t cred
)
568 if (priv_check_cred(cred
, PRIV_NET_PRIVILEGED_CLIENT_ACCESS
, 0) != 0 &&
569 priv_check_cred(cred
, PRIV_NET_PRIVILEGED_SERVER_ACCESS
, 0) != 0) {
570 return necp_drop_unentitled_order
;
576 #define necp_process_drop_order(_cred) (necp_drop_unentitled_order != 0 ? _necp_process_drop_order_inner(_cred) : necp_drop_unentitled_order)
577 #pragma GCC poison _necp_process_drop_order_inner
581 static int necp_session_op_close(struct fileglob
*, vfs_context_t
);
583 static const struct fileops necp_session_fd_ops
= {
584 .fo_type
= DTYPE_NETPOLICY
,
585 .fo_read
= fo_no_read
,
586 .fo_write
= fo_no_write
,
587 .fo_ioctl
= fo_no_ioctl
,
588 .fo_select
= fo_no_select
,
589 .fo_close
= necp_session_op_close
,
590 .fo_drain
= fo_no_drain
,
591 .fo_kqfilter
= fo_no_kqfilter
,
595 necp_is_platform_binary(proc_t proc
)
597 return (proc
!= NULL
) ? (csproc_get_platform_binary(proc
) && cs_valid(proc
)) : 0;
600 static inline necp_drop_all_bypass_check_result_t
601 necp_check_drop_all_bypass_result(proc_t proc
)
604 proc
= current_proc();
606 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
;
610 #if defined(XNU_TARGET_OS_OSX)
611 const char *signing_id
= NULL
;
612 const bool isConfigd
= (necp_is_platform_binary(proc
) &&
613 (signing_id
= cs_identity_get(proc
)) &&
614 (strlen(signing_id
) == SIGNING_ID_CONFIGD_LEN
) &&
615 (memcmp(signing_id
, SIGNING_ID_CONFIGD
, SIGNING_ID_CONFIGD_LEN
) == 0));
617 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE
;
621 const task_t task
= proc_task(proc
);
622 if (task
== NULL
|| !IOTaskHasEntitlement(task
, "com.apple.private.necp.drop_all_bypass")) {
623 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
;
625 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE
;
630 necp_session_open(struct proc
*p
, struct necp_session_open_args
*uap
, int *retval
)
634 struct necp_session
*session
= NULL
;
635 struct fileproc
*fp
= NULL
;
638 uid_t uid
= kauth_cred_getuid(proc_ucred(p
));
639 if (uid
!= 0 && priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES
, 0) != 0) {
640 NECPLOG0(LOG_ERR
, "Process does not hold necessary entitlement to open NECP session");
645 error
= falloc(p
, &fp
, &fd
, vfs_context_current());
650 session
= necp_create_session();
651 if (session
== NULL
) {
656 fp
->fp_glob
->fg_flag
= 0;
657 fp
->fp_glob
->fg_ops
= &necp_session_fd_ops
;
658 fp
->fp_glob
->fg_data
= session
;
661 FDFLAGS_SET(p
, fd
, (UF_EXCLOSE
| UF_FORKCLOSE
));
662 procfdtbl_releasefd(p
, fd
, NULL
);
663 fp_drop(p
, fd
, fp
, 1);
679 necp_session_op_close(struct fileglob
*fg
, vfs_context_t ctx
)
682 struct necp_session
*session
= (struct necp_session
*)fg
->fg_data
;
685 if (session
!= NULL
) {
686 necp_policy_mark_all_for_deletion(session
);
687 necp_policy_apply_all(session
);
688 necp_delete_session(session
);
696 necp_session_find_from_fd(struct proc
*p
, int fd
,
697 struct fileproc
**fpp
, struct necp_session
**session
)
699 struct fileproc
*fp
= NULL
;
700 int error
= fp_get_ftype(p
, fd
, DTYPE_NETPOLICY
, ENODEV
, &fp
);
704 *session
= (struct necp_session
*)fp
->fp_glob
->fg_data
;
705 if ((*session
)->necp_fd_type
!= necp_fd_type_session
) {
706 // Not a client fd, ignore
707 fp_drop(p
, fd
, fp
, 0);
716 necp_session_add_policy(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
719 u_int8_t
*tlv_buffer
= NULL
;
721 if (uap
->in_buffer_length
== 0 || uap
->in_buffer_length
> NECP_MAX_POLICY_SIZE
|| uap
->in_buffer
== 0) {
722 NECPLOG(LOG_ERR
, "necp_session_add_policy invalid input (%zu)", (size_t)uap
->in_buffer_length
);
727 if (uap
->out_buffer_length
< sizeof(necp_policy_id
) || uap
->out_buffer
== 0) {
728 NECPLOG(LOG_ERR
, "necp_session_add_policy invalid output buffer (%zu)", (size_t)uap
->out_buffer_length
);
733 if ((tlv_buffer
= _MALLOC(uap
->in_buffer_length
, M_NECP
, M_WAITOK
| M_ZERO
)) == NULL
) {
738 error
= copyin(uap
->in_buffer
, tlv_buffer
, uap
->in_buffer_length
);
740 NECPLOG(LOG_ERR
, "necp_session_add_policy tlv copyin error (%d)", error
);
744 necp_policy_id new_policy_id
= necp_handle_policy_add(session
, tlv_buffer
, uap
->in_buffer_length
, 0, &error
);
746 NECPLOG(LOG_ERR
, "necp_session_add_policy failed to add policy (%d)", error
);
750 error
= copyout(&new_policy_id
, uap
->out_buffer
, sizeof(new_policy_id
));
752 NECPLOG(LOG_ERR
, "necp_session_add_policy policy_id copyout error (%d)", error
);
757 if (tlv_buffer
!= NULL
) {
758 FREE(tlv_buffer
, M_NECP
);
767 necp_session_get_policy(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
770 u_int8_t
*response
= NULL
;
772 if (uap
->in_buffer_length
< sizeof(necp_policy_id
) || uap
->in_buffer
== 0) {
773 NECPLOG(LOG_ERR
, "necp_session_get_policy invalid input (%zu)", (size_t)uap
->in_buffer_length
);
778 necp_policy_id policy_id
= 0;
779 error
= copyin(uap
->in_buffer
, &policy_id
, sizeof(policy_id
));
781 NECPLOG(LOG_ERR
, "necp_session_get_policy policy_id copyin error (%d)", error
);
785 struct necp_session_policy
*policy
= necp_policy_find(session
, policy_id
);
786 if (policy
== NULL
|| policy
->pending_deletion
) {
787 NECPLOG(LOG_ERR
, "Failed to find policy with id %d", policy_id
);
792 u_int32_t order_tlv_size
= sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(necp_policy_order
);
793 u_int32_t result_tlv_size
= (policy
->result_size
? (sizeof(u_int8_t
) + sizeof(u_int32_t
) + policy
->result_size
) : 0);
794 u_int32_t response_size
= order_tlv_size
+ result_tlv_size
+ policy
->conditions_size
;
796 if (uap
->out_buffer_length
< response_size
|| uap
->out_buffer
== 0) {
797 NECPLOG(LOG_ERR
, "necp_session_get_policy buffer not large enough (%zu < %u)", (size_t)uap
->out_buffer_length
, response_size
);
802 if (response_size
> NECP_MAX_POLICY_SIZE
) {
803 NECPLOG(LOG_ERR
, "necp_session_get_policy size too large to copy (%u)", response_size
);
808 MALLOC(response
, u_int8_t
*, response_size
, M_NECP
, M_WAITOK
| M_ZERO
);
809 if (response
== NULL
) {
814 u_int8_t
*cursor
= response
;
815 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ORDER
, sizeof(necp_policy_order
), &policy
->order
, response
, response_size
);
816 if (result_tlv_size
) {
817 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_RESULT
, policy
->result_size
, &policy
->result
, response
, response_size
);
819 if (policy
->conditions_size
) {
820 memcpy(((u_int8_t
*)(void *)(cursor
)), policy
->conditions
, policy
->conditions_size
);
823 error
= copyout(response
, uap
->out_buffer
, response_size
);
825 NECPLOG(LOG_ERR
, "necp_session_get_policy TLV copyout error (%d)", error
);
830 if (response
!= NULL
) {
831 FREE(response
, M_NECP
);
840 necp_session_delete_policy(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
844 if (uap
->in_buffer_length
< sizeof(necp_policy_id
) || uap
->in_buffer
== 0) {
845 NECPLOG(LOG_ERR
, "necp_session_delete_policy invalid input (%zu)", (size_t)uap
->in_buffer_length
);
850 necp_policy_id delete_policy_id
= 0;
851 error
= copyin(uap
->in_buffer
, &delete_policy_id
, sizeof(delete_policy_id
));
853 NECPLOG(LOG_ERR
, "necp_session_delete_policy policy_id copyin error (%d)", error
);
857 struct necp_session_policy
*policy
= necp_policy_find(session
, delete_policy_id
);
858 if (policy
== NULL
|| policy
->pending_deletion
) {
859 NECPLOG(LOG_ERR
, "necp_session_delete_policy failed to find policy with id %u", delete_policy_id
);
864 necp_policy_mark_for_deletion(session
, policy
);
871 necp_session_apply_all(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
874 necp_policy_apply_all(session
);
880 necp_session_list_all(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
882 u_int32_t tlv_size
= (sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(necp_policy_id
));
883 u_int32_t response_size
= 0;
884 u_int8_t
*response
= NULL
;
885 int num_policies
= 0;
886 int cur_policy_index
= 0;
888 struct necp_session_policy
*policy
;
890 LIST_FOREACH(policy
, &session
->policies
, chain
) {
891 if (!policy
->pending_deletion
) {
896 if (num_policies
> NECP_MAX_POLICY_LIST_COUNT
) {
897 NECPLOG(LOG_ERR
, "necp_session_list_all size too large to copy (%u policies)", num_policies
);
902 response_size
= num_policies
* tlv_size
;
903 if (uap
->out_buffer_length
< response_size
|| uap
->out_buffer
== 0) {
904 NECPLOG(LOG_ERR
, "necp_session_list_all buffer not large enough (%zu < %u)", (size_t)uap
->out_buffer_length
, response_size
);
909 // Create a response with one Policy ID TLV for each policy
910 MALLOC(response
, u_int8_t
*, response_size
, M_NECP
, M_WAITOK
| M_ZERO
);
911 if (response
== NULL
) {
916 u_int8_t
*cursor
= response
;
917 LIST_FOREACH(policy
, &session
->policies
, chain
) {
918 if (!policy
->pending_deletion
&& cur_policy_index
< num_policies
) {
919 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ID
, sizeof(u_int32_t
), &policy
->local_id
, response
, response_size
);
924 error
= copyout(response
, uap
->out_buffer
, response_size
);
926 NECPLOG(LOG_ERR
, "necp_session_list_all TLV copyout error (%d)", error
);
931 if (response
!= NULL
) {
932 FREE(response
, M_NECP
);
942 necp_session_delete_all(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
945 necp_policy_mark_all_for_deletion(session
);
951 necp_session_set_session_priority(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
954 struct necp_session_policy
*policy
= NULL
;
955 struct necp_session_policy
*temp_policy
= NULL
;
957 if (uap
->in_buffer_length
< sizeof(necp_session_priority
) || uap
->in_buffer
== 0) {
958 NECPLOG(LOG_ERR
, "necp_session_set_session_priority invalid input (%zu)", (size_t)uap
->in_buffer_length
);
963 necp_session_priority requested_session_priority
= 0;
964 error
= copyin(uap
->in_buffer
, &requested_session_priority
, sizeof(requested_session_priority
));
966 NECPLOG(LOG_ERR
, "necp_session_set_session_priority priority copyin error (%d)", error
);
970 // Enforce special session priorities with entitlements
971 if (requested_session_priority
== NECP_SESSION_PRIORITY_CONTROL
||
972 requested_session_priority
== NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL
||
973 requested_session_priority
== NECP_SESSION_PRIORITY_HIGH_RESTRICTED
) {
974 errno_t cred_result
= priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES
, 0);
975 if (cred_result
!= 0) {
976 NECPLOG(LOG_ERR
, "Session does not hold necessary entitlement to claim priority level %d", requested_session_priority
);
982 if (session
->session_priority
!= requested_session_priority
) {
983 session
->session_priority
= requested_session_priority
;
984 session
->session_order
= necp_allocate_new_session_order(session
->session_priority
, session
->control_unit
);
985 session
->dirty
= TRUE
;
987 // Mark all policies as needing updates
988 LIST_FOREACH_SAFE(policy
, &session
->policies
, chain
, temp_policy
) {
989 policy
->pending_update
= TRUE
;
999 necp_session_lock_to_process(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
1002 session
->proc_locked
= TRUE
;
1008 necp_session_register_service(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
1011 struct necp_service_registration
*new_service
= NULL
;
1013 if (uap
->in_buffer_length
< sizeof(uuid_t
) || uap
->in_buffer
== 0) {
1014 NECPLOG(LOG_ERR
, "necp_session_register_service invalid input (%zu)", (size_t)uap
->in_buffer_length
);
1019 uuid_t service_uuid
;
1020 error
= copyin(uap
->in_buffer
, service_uuid
, sizeof(service_uuid
));
1022 NECPLOG(LOG_ERR
, "necp_session_register_service uuid copyin error (%d)", error
);
1026 MALLOC(new_service
, struct necp_service_registration
*, sizeof(*new_service
), M_NECP
, M_WAITOK
| M_ZERO
);
1027 if (new_service
== NULL
) {
1028 NECPLOG0(LOG_ERR
, "Failed to allocate service registration");
1033 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1034 new_service
->service_id
= necp_create_uuid_service_id_mapping(service_uuid
);
1035 LIST_INSERT_HEAD(&session
->services
, new_service
, session_chain
);
1036 LIST_INSERT_HEAD(&necp_registered_service_list
, new_service
, kernel_chain
);
1037 lck_rw_done(&necp_kernel_policy_lock
);
1045 necp_session_unregister_service(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
1048 struct necp_service_registration
*service
= NULL
;
1049 struct necp_service_registration
*temp_service
= NULL
;
1050 struct necp_uuid_id_mapping
*mapping
= NULL
;
1052 if (uap
->in_buffer_length
< sizeof(uuid_t
) || uap
->in_buffer
== 0) {
1053 NECPLOG(LOG_ERR
, "necp_session_unregister_service invalid input (%zu)", (size_t)uap
->in_buffer_length
);
1058 uuid_t service_uuid
;
1059 error
= copyin(uap
->in_buffer
, service_uuid
, sizeof(service_uuid
));
1061 NECPLOG(LOG_ERR
, "necp_session_unregister_service uuid copyin error (%d)", error
);
1065 // Remove all matching services for this session
1066 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1067 mapping
= necp_uuid_lookup_service_id_locked(service_uuid
);
1068 if (mapping
!= NULL
) {
1069 LIST_FOREACH_SAFE(service
, &session
->services
, session_chain
, temp_service
) {
1070 if (service
->service_id
== mapping
->id
) {
1071 LIST_REMOVE(service
, session_chain
);
1072 LIST_REMOVE(service
, kernel_chain
);
1073 FREE(service
, M_NECP
);
1076 necp_remove_uuid_service_id_mapping(service_uuid
);
1078 lck_rw_done(&necp_kernel_policy_lock
);
1086 necp_session_dump_all(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
1088 #pragma unused(session)
1091 if (uap
->out_buffer_length
== 0 || uap
->out_buffer
== 0) {
1092 NECPLOG(LOG_ERR
, "necp_session_dump_all invalid output buffer (%zu)", (size_t)uap
->out_buffer_length
);
1097 error
= necp_handle_policy_dump_all(uap
->out_buffer
, uap
->out_buffer_length
);
1104 necp_session_action(struct proc
*p
, struct necp_session_action_args
*uap
, int *retval
)
1106 struct fileproc
*fp
;
1108 int return_value
= 0;
1109 struct necp_session
*session
= NULL
;
1111 error
= necp_session_find_from_fd(p
, uap
->necp_fd
, &fp
, &session
);
1113 NECPLOG(LOG_ERR
, "necp_session_action find fd error (%d)", error
);
1117 NECP_SESSION_LOCK(session
);
1119 if (session
->proc_locked
) {
1120 // Verify that the calling process is allowed to do actions
1122 proc_getexecutableuuid(current_proc(), proc_uuid
, sizeof(proc_uuid
));
1123 if (uuid_compare(proc_uuid
, session
->proc_uuid
) != 0) {
1128 // If not locked, update the proc_uuid and proc_pid of the session
1129 proc_getexecutableuuid(current_proc(), session
->proc_uuid
, sizeof(session
->proc_uuid
));
1130 session
->proc_pid
= proc_pid(current_proc());
1133 u_int32_t action
= uap
->action
;
1135 case NECP_SESSION_ACTION_POLICY_ADD
: {
1136 return_value
= necp_session_add_policy(session
, uap
, retval
);
1139 case NECP_SESSION_ACTION_POLICY_GET
: {
1140 return_value
= necp_session_get_policy(session
, uap
, retval
);
1143 case NECP_SESSION_ACTION_POLICY_DELETE
: {
1144 return_value
= necp_session_delete_policy(session
, uap
, retval
);
1147 case NECP_SESSION_ACTION_POLICY_APPLY_ALL
: {
1148 return_value
= necp_session_apply_all(session
, uap
, retval
);
1151 case NECP_SESSION_ACTION_POLICY_LIST_ALL
: {
1152 return_value
= necp_session_list_all(session
, uap
, retval
);
1155 case NECP_SESSION_ACTION_POLICY_DELETE_ALL
: {
1156 return_value
= necp_session_delete_all(session
, uap
, retval
);
1159 case NECP_SESSION_ACTION_SET_SESSION_PRIORITY
: {
1160 return_value
= necp_session_set_session_priority(session
, uap
, retval
);
1163 case NECP_SESSION_ACTION_LOCK_SESSION_TO_PROC
: {
1164 return_value
= necp_session_lock_to_process(session
, uap
, retval
);
1167 case NECP_SESSION_ACTION_REGISTER_SERVICE
: {
1168 return_value
= necp_session_register_service(session
, uap
, retval
);
1171 case NECP_SESSION_ACTION_UNREGISTER_SERVICE
: {
1172 return_value
= necp_session_unregister_service(session
, uap
, retval
);
1175 case NECP_SESSION_ACTION_POLICY_DUMP_ALL
: {
1176 return_value
= necp_session_dump_all(session
, uap
, retval
);
1180 NECPLOG(LOG_ERR
, "necp_session_action unknown action (%u)", action
);
1181 return_value
= EINVAL
;
1187 NECP_SESSION_UNLOCK(session
);
1188 fp_drop(p
, uap
->necp_fd
, fp
, 0);
1189 return return_value
;
1192 struct necp_resolver_key_state
{
1193 const struct ccdigest_info
*digest_info
;
1194 uint8_t key
[CCSHA256_OUTPUT_SIZE
];
1196 static struct necp_resolver_key_state s_necp_resolver_key_state
;
1199 necp_generate_resolver_key(void)
1201 s_necp_resolver_key_state
.digest_info
= ccsha256_di();
1202 cc_rand_generate(s_necp_resolver_key_state
.key
, sizeof(s_necp_resolver_key_state
.key
));
1206 necp_sign_update_context(const struct ccdigest_info
*di
,
1210 u_int32_t query_length
,
1212 u_int32_t answer_length
)
1214 const uint8_t context
[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
1215 const char *context_string
= "NECP Resolver Binder";
1216 uint8_t separator
= 0;
1217 cchmac_update(di
, ctx
, sizeof(context
), context
);
1218 cchmac_update(di
, ctx
, strlen(context_string
), context_string
);
1219 cchmac_update(di
, ctx
, sizeof(separator
), &separator
);
1220 cchmac_update(di
, ctx
, sizeof(uuid_t
), client_id
);
1221 cchmac_update(di
, ctx
, sizeof(query_length
), &query_length
);
1222 cchmac_update(di
, ctx
, query_length
, query
);
1223 cchmac_update(di
, ctx
, sizeof(answer_length
), &answer_length
);
1224 cchmac_update(di
, ctx
, answer_length
, answer
);
1228 necp_sign_resolver_answer(uuid_t client_id
, u_int8_t
*query
, u_int32_t query_length
,
1229 u_int8_t
*answer
, u_int32_t answer_length
,
1230 u_int8_t
*tag
, u_int32_t
*out_tag_length
)
1232 if (s_necp_resolver_key_state
.digest_info
== NULL
) {
1236 if (query
== NULL
||
1237 query_length
== 0 ||
1239 answer_length
== 0 ||
1241 out_tag_length
== NULL
) {
1245 size_t required_tag_length
= s_necp_resolver_key_state
.digest_info
->output_size
;
1246 if (*out_tag_length
< required_tag_length
) {
1250 *out_tag_length
= required_tag_length
;
1252 cchmac_ctx_decl(s_necp_resolver_key_state
.digest_info
->state_size
,
1253 s_necp_resolver_key_state
.digest_info
->block_size
, ctx
);
1254 cchmac_init(s_necp_resolver_key_state
.digest_info
, ctx
,
1255 sizeof(s_necp_resolver_key_state
.key
),
1256 s_necp_resolver_key_state
.key
);
1257 necp_sign_update_context(s_necp_resolver_key_state
.digest_info
,
1258 ctx
, client_id
, query
, query_length
,
1259 answer
, answer_length
);
1260 cchmac_final(s_necp_resolver_key_state
.digest_info
, ctx
, tag
);
1266 necp_validate_resolver_answer(uuid_t client_id
, u_int8_t
*query
, u_int32_t query_length
,
1267 u_int8_t
*answer
, u_int32_t answer_length
,
1268 u_int8_t
*tag
, u_int32_t tag_length
)
1270 if (s_necp_resolver_key_state
.digest_info
== NULL
) {
1274 if (query
== NULL
||
1275 query_length
== 0 ||
1277 answer_length
== 0 ||
1283 size_t required_tag_length
= s_necp_resolver_key_state
.digest_info
->output_size
;
1284 if (tag_length
!= required_tag_length
) {
1288 uint8_t actual_tag
[required_tag_length
];
1290 cchmac_ctx_decl(s_necp_resolver_key_state
.digest_info
->state_size
,
1291 s_necp_resolver_key_state
.digest_info
->block_size
, ctx
);
1292 cchmac_init(s_necp_resolver_key_state
.digest_info
, ctx
,
1293 sizeof(s_necp_resolver_key_state
.key
),
1294 s_necp_resolver_key_state
.key
);
1295 necp_sign_update_context(s_necp_resolver_key_state
.digest_info
,
1296 ctx
, client_id
, query
, query_length
,
1297 answer
, answer_length
);
1298 cchmac_final(s_necp_resolver_key_state
.digest_info
, ctx
, actual_tag
);
1300 return cc_cmp_safe(s_necp_resolver_key_state
.digest_info
->output_size
, tag
, actual_tag
) == 0;
1308 necp_log_handle
= os_log_create("com.apple.xnu.net.necp", "necp");
1310 necp_kernel_policy_grp_attr
= lck_grp_attr_alloc_init();
1311 if (necp_kernel_policy_grp_attr
== NULL
) {
1312 NECPLOG0(LOG_ERR
, "lck_grp_attr_alloc_init failed");
1317 necp_kernel_policy_mtx_grp
= lck_grp_alloc_init(NECP_CONTROL_NAME
, necp_kernel_policy_grp_attr
);
1318 if (necp_kernel_policy_mtx_grp
== NULL
) {
1319 NECPLOG0(LOG_ERR
, "lck_grp_alloc_init failed");
1324 necp_kernel_policy_mtx_attr
= lck_attr_alloc_init();
1325 if (necp_kernel_policy_mtx_attr
== NULL
) {
1326 NECPLOG0(LOG_ERR
, "lck_attr_alloc_init failed");
1331 lck_rw_init(&necp_kernel_policy_lock
, necp_kernel_policy_mtx_grp
, necp_kernel_policy_mtx_attr
);
1333 necp_route_rule_grp_attr
= lck_grp_attr_alloc_init();
1334 if (necp_route_rule_grp_attr
== NULL
) {
1335 NECPLOG0(LOG_ERR
, "lck_grp_attr_alloc_init failed");
1340 necp_route_rule_mtx_grp
= lck_grp_alloc_init("necp_route_rule", necp_route_rule_grp_attr
);
1341 if (necp_route_rule_mtx_grp
== NULL
) {
1342 NECPLOG0(LOG_ERR
, "lck_grp_alloc_init failed");
1347 necp_route_rule_mtx_attr
= lck_attr_alloc_init();
1348 if (necp_route_rule_mtx_attr
== NULL
) {
1349 NECPLOG0(LOG_ERR
, "lck_attr_alloc_init failed");
1354 lck_rw_init(&necp_route_rule_lock
, necp_route_rule_mtx_grp
, necp_route_rule_mtx_attr
);
1358 TAILQ_INIT(&necp_session_list
);
1360 LIST_INIT(&necp_kernel_socket_policies
);
1361 LIST_INIT(&necp_kernel_ip_output_policies
);
1363 LIST_INIT(&necp_account_id_list
);
1365 LIST_INIT(&necp_uuid_service_id_list
);
1367 LIST_INIT(&necp_registered_service_list
);
1369 LIST_INIT(&necp_route_rules
);
1370 LIST_INIT(&necp_aggregate_route_rules
);
1372 necp_generate_resolver_key();
1374 necp_uuid_app_id_hashtbl
= hashinit(NECP_UUID_APP_ID_HASH_SIZE
, M_NECP
, &necp_uuid_app_id_hash_mask
);
1375 necp_uuid_app_id_hash_num_buckets
= necp_uuid_app_id_hash_mask
+ 1;
1376 necp_num_uuid_app_id_mappings
= 0;
1377 necp_uuid_app_id_mappings_dirty
= FALSE
;
1379 necp_kernel_application_policies_condition_mask
= 0;
1380 necp_kernel_socket_policies_condition_mask
= 0;
1381 necp_kernel_ip_output_policies_condition_mask
= 0;
1383 necp_kernel_application_policies_count
= 0;
1384 necp_kernel_socket_policies_count
= 0;
1385 necp_kernel_socket_policies_non_app_count
= 0;
1386 necp_kernel_ip_output_policies_count
= 0;
1387 necp_kernel_ip_output_policies_non_id_count
= 0;
1389 necp_kernel_socket_policies_gencount
= 1;
1391 memset(&necp_kernel_socket_policies_map
, 0, sizeof(necp_kernel_socket_policies_map
));
1392 memset(&necp_kernel_ip_output_policies_map
, 0, sizeof(necp_kernel_ip_output_policies_map
));
1393 necp_kernel_socket_policies_app_layer_map
= NULL
;
1395 necp_drop_unentitled_order
= necp_get_first_order_for_priority(necp_drop_unentitled_level
);
1399 if (necp_kernel_policy_mtx_attr
!= NULL
) {
1400 lck_attr_free(necp_kernel_policy_mtx_attr
);
1401 necp_kernel_policy_mtx_attr
= NULL
;
1403 if (necp_kernel_policy_mtx_grp
!= NULL
) {
1404 lck_grp_free(necp_kernel_policy_mtx_grp
);
1405 necp_kernel_policy_mtx_grp
= NULL
;
1407 if (necp_kernel_policy_grp_attr
!= NULL
) {
1408 lck_grp_attr_free(necp_kernel_policy_grp_attr
);
1409 necp_kernel_policy_grp_attr
= NULL
;
1411 if (necp_route_rule_mtx_attr
!= NULL
) {
1412 lck_attr_free(necp_route_rule_mtx_attr
);
1413 necp_route_rule_mtx_attr
= NULL
;
1415 if (necp_route_rule_mtx_grp
!= NULL
) {
1416 lck_grp_free(necp_route_rule_mtx_grp
);
1417 necp_route_rule_mtx_grp
= NULL
;
1419 if (necp_route_rule_grp_attr
!= NULL
) {
1420 lck_grp_attr_free(necp_route_rule_grp_attr
);
1421 necp_route_rule_grp_attr
= NULL
;
1428 necp_post_change_event(struct kev_necp_policies_changed_data
*necp_event_data
)
1430 struct kev_msg ev_msg
;
1431 memset(&ev_msg
, 0, sizeof(ev_msg
));
1433 ev_msg
.vendor_code
= KEV_VENDOR_APPLE
;
1434 ev_msg
.kev_class
= KEV_NETWORK_CLASS
;
1435 ev_msg
.kev_subclass
= KEV_NECP_SUBCLASS
;
1436 ev_msg
.event_code
= KEV_NECP_POLICIES_CHANGED
;
1438 ev_msg
.dv
[0].data_ptr
= necp_event_data
;
1439 ev_msg
.dv
[0].data_length
= sizeof(necp_event_data
->changed_count
);
1440 ev_msg
.dv
[1].data_length
= 0;
1442 kev_post_msg(&ev_msg
);
1446 necp_buffer_write_tlv_validate(u_int8_t
*cursor
, u_int8_t type
, u_int32_t length
,
1447 u_int8_t
*buffer
, u_int32_t buffer_length
)
1449 if (cursor
< buffer
|| (uintptr_t)(cursor
- buffer
) > buffer_length
) {
1450 NECPLOG0(LOG_ERR
, "Cannot write TLV in buffer (invalid cursor)");
1453 u_int8_t
*next_tlv
= (u_int8_t
*)(cursor
+ sizeof(type
) + sizeof(length
) + length
);
1454 if (next_tlv
<= buffer
|| // make sure the next TLV start doesn't overflow
1455 (uintptr_t)(next_tlv
- buffer
) > buffer_length
) { // make sure the next TLV has enough room in buffer
1456 NECPLOG(LOG_ERR
, "Cannot write TLV in buffer (TLV length %u, buffer length %u)",
1457 length
, buffer_length
);
1464 necp_buffer_write_tlv_if_different(u_int8_t
*cursor
, u_int8_t type
,
1465 u_int32_t length
, const void *value
, bool *updated
,
1466 u_int8_t
*buffer
, u_int32_t buffer_length
)
1468 if (!necp_buffer_write_tlv_validate(cursor
, type
, length
, buffer
, buffer_length
)) {
1469 // If we can't fit this TLV, return the current cursor
1472 u_int8_t
*next_tlv
= (u_int8_t
*)(cursor
+ sizeof(type
) + sizeof(length
) + length
);
1473 if (*updated
|| *(u_int8_t
*)(cursor
) != type
) {
1474 *(u_int8_t
*)(cursor
) = type
;
1477 if (*updated
|| *(u_int32_t
*)(void *)(cursor
+ sizeof(type
)) != length
) {
1478 *(u_int32_t
*)(void *)(cursor
+ sizeof(type
)) = length
;
1482 if (*updated
|| memcmp((u_int8_t
*)(cursor
+ sizeof(type
) + sizeof(length
)), value
, length
) != 0) {
1483 memcpy((u_int8_t
*)(cursor
+ sizeof(type
) + sizeof(length
)), value
, length
);
1491 necp_buffer_write_tlv(u_int8_t
*cursor
, u_int8_t type
,
1492 u_int32_t length
, const void *value
,
1493 u_int8_t
*buffer
, u_int32_t buffer_length
)
1495 if (!necp_buffer_write_tlv_validate(cursor
, type
, length
, buffer
, buffer_length
)) {
1498 u_int8_t
*next_tlv
= (u_int8_t
*)(cursor
+ sizeof(type
) + sizeof(length
) + length
);
1499 *(u_int8_t
*)(cursor
) = type
;
1500 *(u_int32_t
*)(void *)(cursor
+ sizeof(type
)) = length
;
1502 memcpy((u_int8_t
*)(cursor
+ sizeof(type
) + sizeof(length
)), value
, length
);
1509 necp_buffer_get_tlv_type(u_int8_t
*buffer
, int tlv_offset
)
1511 u_int8_t
*type
= NULL
;
1513 if (buffer
== NULL
) {
1517 type
= (u_int8_t
*)((u_int8_t
*)buffer
+ tlv_offset
);
1518 return type
? *type
: 0;
1522 necp_buffer_get_tlv_length(u_int8_t
*buffer
, int tlv_offset
)
1524 u_int32_t
*length
= NULL
;
1526 if (buffer
== NULL
) {
1530 length
= (u_int32_t
*)(void *)((u_int8_t
*)buffer
+ tlv_offset
+ sizeof(u_int8_t
));
1531 return length
? *length
: 0;
1535 necp_buffer_get_tlv_value(u_int8_t
*buffer
, int tlv_offset
, u_int32_t
*value_size
)
1537 u_int8_t
*value
= NULL
;
1538 u_int32_t length
= necp_buffer_get_tlv_length(buffer
, tlv_offset
);
1544 *value_size
= length
;
1547 value
= (u_int8_t
*)((u_int8_t
*)buffer
+ tlv_offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
));
1552 necp_buffer_find_tlv(u_int8_t
*buffer
, u_int32_t buffer_length
, int offset
, u_int8_t type
, int *err
, int next
)
1563 int cursor
= offset
;
1565 u_int32_t curr_length
;
1569 if ((((u_int32_t
)cursor
) + sizeof(curr_type
) + sizeof(curr_length
)) > buffer_length
) {
1573 curr_type
= necp_buffer_get_tlv_type(buffer
, cursor
);
1576 curr_type
= NECP_TLV_NIL
;
1578 curr_length
= necp_buffer_get_tlv_length(buffer
, cursor
);
1579 if (curr_length
> buffer_length
- ((u_int32_t
)cursor
+ sizeof(curr_type
) + sizeof(curr_length
))) {
1583 next_cursor
= (cursor
+ sizeof(curr_type
) + sizeof(curr_length
) + curr_length
);
1584 if (curr_type
== type
) {
1585 // check if entire TLV fits inside buffer
1586 if (((u_int32_t
)next_cursor
) <= buffer_length
) {
1595 cursor
= next_cursor
;
1600 necp_find_tlv(u_int8_t
*buffer
, u_int32_t buffer_length
, int offset
, u_int8_t type
, int *err
, int next
)
1603 if (buffer
!= NULL
) {
1604 cursor
= necp_buffer_find_tlv(buffer
, buffer_length
, offset
, type
, err
, next
);
1610 necp_get_tlv_at_offset(u_int8_t
*buffer
, u_int32_t buffer_length
,
1611 int tlv_offset
, u_int32_t out_buffer_length
, void *out_buffer
, u_int32_t
*value_size
)
1613 if (buffer
== NULL
) {
1614 NECPLOG0(LOG_ERR
, "necp_get_tlv_at_offset buffer is NULL");
1618 // Handle buffer parsing
1620 // Validate that buffer has enough room for any TLV
1621 if (tlv_offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
) > buffer_length
) {
1622 NECPLOG(LOG_ERR
, "necp_get_tlv_at_offset buffer_length is too small for TLV (%u < %lu)",
1623 buffer_length
, tlv_offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
));
1627 // Validate that buffer has enough room for this TLV
1628 u_int32_t tlv_length
= necp_buffer_get_tlv_length(buffer
, tlv_offset
);
1629 if (tlv_length
> buffer_length
- (tlv_offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
))) {
1630 NECPLOG(LOG_ERR
, "necp_get_tlv_at_offset buffer_length is too small for TLV of length %u (%u < %lu)",
1631 tlv_length
, buffer_length
, tlv_offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
) + tlv_length
);
1635 if (out_buffer
!= NULL
&& out_buffer_length
> 0) {
1636 // Validate that out buffer is large enough for value
1637 if (out_buffer_length
< tlv_length
) {
1638 NECPLOG(LOG_ERR
, "necp_get_tlv_at_offset out_buffer_length is too small for TLV value (%u < %u)",
1639 out_buffer_length
, tlv_length
);
1643 // Get value pointer
1644 u_int8_t
*tlv_value
= necp_buffer_get_tlv_value(buffer
, tlv_offset
, NULL
);
1645 if (tlv_value
== NULL
) {
1646 NECPLOG0(LOG_ERR
, "necp_get_tlv_at_offset tlv_value is NULL");
1651 memcpy(out_buffer
, tlv_value
, tlv_length
);
1655 if (value_size
!= NULL
) {
1656 *value_size
= tlv_length
;
1663 necp_get_tlv(u_int8_t
*buffer
, u_int32_t buffer_length
,
1664 int offset
, u_int8_t type
, u_int32_t buff_len
, void *buff
, u_int32_t
*value_size
)
1668 int tlv_offset
= necp_find_tlv(buffer
, buffer_length
, offset
, type
, &error
, 0);
1669 if (tlv_offset
< 0) {
1673 return necp_get_tlv_at_offset(buffer
, buffer_length
, tlv_offset
, buff_len
, buff
, value_size
);
1676 // Session Management
1678 static struct necp_session
*
1679 necp_create_session(void)
1681 struct necp_session
*new_session
= NULL
;
1683 MALLOC(new_session
, struct necp_session
*, sizeof(*new_session
), M_NECP
, M_WAITOK
| M_ZERO
);
1684 if (new_session
== NULL
) {
1688 new_session
->necp_fd_type
= necp_fd_type_session
;
1689 new_session
->session_priority
= NECP_SESSION_PRIORITY_UNKNOWN
;
1690 new_session
->dirty
= FALSE
;
1691 LIST_INIT(&new_session
->policies
);
1692 lck_mtx_init(&new_session
->lock
, necp_kernel_policy_mtx_grp
, necp_kernel_policy_mtx_attr
);
1695 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1697 // Find the next available control unit
1698 u_int32_t control_unit
= 1;
1699 struct necp_session
*next_session
= NULL
;
1700 TAILQ_FOREACH(next_session
, &necp_session_list
, chain
) {
1701 if (next_session
->control_unit
> control_unit
) {
1702 // Found a gap, grab this control unit
1706 // Try the next control unit, loop around
1707 control_unit
= next_session
->control_unit
+ 1;
1710 new_session
->control_unit
= control_unit
;
1711 new_session
->session_order
= necp_allocate_new_session_order(new_session
->session_priority
, control_unit
);
1713 if (next_session
!= NULL
) {
1714 TAILQ_INSERT_BEFORE(next_session
, new_session
, chain
);
1716 TAILQ_INSERT_TAIL(&necp_session_list
, new_session
, chain
);
1719 necp_session_count
++;
1720 lck_rw_done(&necp_kernel_policy_lock
);
1723 NECPLOG(LOG_DEBUG
, "Created NECP session, control unit %d", control_unit
);
1731 necp_delete_session(struct necp_session
*session
)
1733 if (session
!= NULL
) {
1734 struct necp_service_registration
*service
= NULL
;
1735 struct necp_service_registration
*temp_service
= NULL
;
1736 LIST_FOREACH_SAFE(service
, &session
->services
, session_chain
, temp_service
) {
1737 LIST_REMOVE(service
, session_chain
);
1738 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1739 LIST_REMOVE(service
, kernel_chain
);
1740 lck_rw_done(&necp_kernel_policy_lock
);
1741 FREE(service
, M_NECP
);
1744 NECPLOG0(LOG_DEBUG
, "Deleted NECP session");
1747 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1748 TAILQ_REMOVE(&necp_session_list
, session
, chain
);
1749 necp_session_count
--;
1750 lck_rw_done(&necp_kernel_policy_lock
);
1752 lck_mtx_destroy(&session
->lock
, necp_kernel_policy_mtx_grp
);
1753 FREE(session
, M_NECP
);
1757 // Session Policy Management
1759 static inline u_int8_t
1760 necp_policy_result_get_type_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1762 return (buffer
&& length
>= sizeof(u_int8_t
)) ? buffer
[0] : 0;
1765 static inline u_int32_t
1766 necp_policy_result_get_parameter_length_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1768 return (buffer
&& length
> sizeof(u_int8_t
)) ? (length
- sizeof(u_int8_t
)) : 0;
1771 static inline u_int8_t
*
1772 necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1774 return (buffer
&& length
> sizeof(u_int8_t
)) ? (buffer
+ sizeof(u_int8_t
)) : NULL
;
1778 necp_policy_result_requires_route_rules(u_int8_t
*buffer
, u_int32_t length
)
1780 u_int8_t type
= necp_policy_result_get_type_from_buffer(buffer
, length
);
1781 if (type
== NECP_POLICY_RESULT_ROUTE_RULES
) {
1788 necp_address_is_valid(struct sockaddr
*address
)
1790 if (address
->sa_family
== AF_INET
) {
1791 return address
->sa_len
== sizeof(struct sockaddr_in
);
1792 } else if (address
->sa_family
== AF_INET6
) {
1793 return address
->sa_len
== sizeof(struct sockaddr_in6
);
1800 necp_policy_result_is_valid(u_int8_t
*buffer
, u_int32_t length
)
1802 bool validated
= FALSE
;
1803 u_int8_t type
= necp_policy_result_get_type_from_buffer(buffer
, length
);
1804 u_int32_t parameter_length
= necp_policy_result_get_parameter_length_from_buffer(buffer
, length
);
1806 case NECP_POLICY_RESULT_PASS
: {
1807 if (parameter_length
== 0 || parameter_length
== sizeof(u_int32_t
)) {
1812 case NECP_POLICY_RESULT_DROP
: {
1813 if (parameter_length
== 0 || parameter_length
== sizeof(u_int32_t
)) {
1818 case NECP_POLICY_RESULT_ROUTE_RULES
:
1819 case NECP_POLICY_RESULT_SCOPED_DIRECT
:
1820 case NECP_POLICY_RESULT_ALLOW_UNENTITLED
: {
1824 case NECP_POLICY_RESULT_SKIP
:
1825 case NECP_POLICY_RESULT_SOCKET_DIVERT
:
1826 case NECP_POLICY_RESULT_SOCKET_FILTER
: {
1827 if (parameter_length
>= sizeof(u_int32_t
)) {
1832 case NECP_POLICY_RESULT_IP_TUNNEL
: {
1833 if (parameter_length
> sizeof(u_int32_t
)) {
1838 case NECP_POLICY_RESULT_SOCKET_SCOPED
: {
1839 if (parameter_length
> 0) {
1844 case NECP_POLICY_RESULT_TRIGGER
:
1845 case NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
:
1846 case NECP_POLICY_RESULT_TRIGGER_SCOPED
:
1847 case NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
:
1848 case NECP_POLICY_RESULT_USE_NETAGENT
:
1849 case NECP_POLICY_RESULT_NETAGENT_SCOPED
:{
1850 if (parameter_length
>= sizeof(uuid_t
)) {
1862 NECPLOG(LOG_DEBUG
, "Policy result type %d, valid %d", type
, validated
);
1868 static inline u_int8_t
1869 necp_policy_condition_get_type_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1871 return (buffer
&& length
>= sizeof(u_int8_t
)) ? buffer
[0] : 0;
1874 static inline u_int8_t
1875 necp_policy_condition_get_flags_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1877 return (buffer
&& length
>= (2 * sizeof(u_int8_t
))) ? buffer
[1] : 0;
1880 static inline u_int32_t
1881 necp_policy_condition_get_value_length_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1883 return (buffer
&& length
>= (2 * sizeof(u_int8_t
))) ? (length
- (2 * sizeof(u_int8_t
))) : 0;
1886 static inline u_int8_t
*
1887 necp_policy_condition_get_value_pointer_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1889 return (buffer
&& length
> (2 * sizeof(u_int8_t
))) ? (buffer
+ (2 * sizeof(u_int8_t
))) : NULL
;
1893 necp_policy_condition_is_default(u_int8_t
*buffer
, u_int32_t length
)
1895 return necp_policy_condition_get_type_from_buffer(buffer
, length
) == NECP_POLICY_CONDITION_DEFAULT
;
1899 necp_policy_condition_is_application(u_int8_t
*buffer
, u_int32_t length
)
1901 return necp_policy_condition_get_type_from_buffer(buffer
, length
) == NECP_POLICY_CONDITION_APPLICATION
;
1905 necp_policy_condition_is_real_application(u_int8_t
*buffer
, u_int32_t length
)
1907 return necp_policy_condition_get_type_from_buffer(buffer
, length
) == NECP_POLICY_CONDITION_REAL_APPLICATION
;
1911 necp_policy_condition_requires_application(u_int8_t
*buffer
, u_int32_t length
)
1913 u_int8_t type
= necp_policy_condition_get_type_from_buffer(buffer
, length
);
1914 return type
== NECP_POLICY_CONDITION_REAL_APPLICATION
;
1918 necp_policy_condition_requires_real_application(u_int8_t
*buffer
, u_int32_t length
)
1920 u_int8_t type
= necp_policy_condition_get_type_from_buffer(buffer
, length
);
1921 u_int32_t condition_length
= necp_policy_condition_get_value_length_from_buffer(buffer
, length
);
1922 return type
== NECP_POLICY_CONDITION_ENTITLEMENT
&& condition_length
> 0;
1926 necp_policy_condition_is_valid(u_int8_t
*buffer
, u_int32_t length
, u_int8_t policy_result_type
)
1928 bool validated
= FALSE
;
1929 bool result_cannot_have_ip_layer
= (policy_result_type
== NECP_POLICY_RESULT_SOCKET_DIVERT
||
1930 policy_result_type
== NECP_POLICY_RESULT_SOCKET_FILTER
||
1931 policy_result_type
== NECP_POLICY_RESULT_TRIGGER
||
1932 policy_result_type
== NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
||
1933 policy_result_type
== NECP_POLICY_RESULT_TRIGGER_SCOPED
||
1934 policy_result_type
== NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
||
1935 policy_result_type
== NECP_POLICY_RESULT_SOCKET_SCOPED
||
1936 policy_result_type
== NECP_POLICY_RESULT_ROUTE_RULES
||
1937 policy_result_type
== NECP_POLICY_RESULT_USE_NETAGENT
||
1938 policy_result_type
== NECP_POLICY_RESULT_NETAGENT_SCOPED
||
1939 policy_result_type
== NECP_POLICY_RESULT_SCOPED_DIRECT
||
1940 policy_result_type
== NECP_POLICY_RESULT_ALLOW_UNENTITLED
) ? TRUE
: FALSE
;
1941 u_int32_t condition_length
= necp_policy_condition_get_value_length_from_buffer(buffer
, length
);
1942 u_int8_t
*condition_value
= necp_policy_condition_get_value_pointer_from_buffer(buffer
, length
);
1943 u_int8_t type
= necp_policy_condition_get_type_from_buffer(buffer
, length
);
1944 u_int8_t flags
= necp_policy_condition_get_flags_from_buffer(buffer
, length
);
1946 case NECP_POLICY_CONDITION_APPLICATION
:
1947 case NECP_POLICY_CONDITION_REAL_APPLICATION
: {
1948 if (!(flags
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
) &&
1949 condition_length
>= sizeof(uuid_t
) &&
1950 condition_value
!= NULL
&&
1951 !uuid_is_null(condition_value
)) {
1956 case NECP_POLICY_CONDITION_DOMAIN
:
1957 case NECP_POLICY_CONDITION_ACCOUNT
:
1958 case NECP_POLICY_CONDITION_BOUND_INTERFACE
:
1959 case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER
: {
1960 if (condition_length
> 0) {
1965 case NECP_POLICY_CONDITION_TRAFFIC_CLASS
: {
1966 if (condition_length
>= sizeof(struct necp_policy_condition_tc_range
)) {
1971 case NECP_POLICY_CONDITION_DEFAULT
:
1972 case NECP_POLICY_CONDITION_ALL_INTERFACES
:
1973 case NECP_POLICY_CONDITION_ENTITLEMENT
:
1974 case NECP_POLICY_CONDITION_PLATFORM_BINARY
:
1975 case NECP_POLICY_CONDITION_HAS_CLIENT
:
1976 case NECP_POLICY_CONDITION_LOCAL_NETWORKS
: {
1977 if (!(flags
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
)) {
1982 case NECP_POLICY_CONDITION_SDK_VERSION
: {
1983 if (!(flags
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
) &&
1984 condition_length
>= sizeof(struct necp_policy_condition_sdk_version
)) {
1989 case NECP_POLICY_CONDITION_IP_PROTOCOL
: {
1990 if (condition_length
>= sizeof(u_int16_t
)) {
1995 case NECP_POLICY_CONDITION_PID
: {
1996 if (condition_length
>= sizeof(pid_t
) &&
1997 condition_value
!= NULL
&&
1998 *((pid_t
*)(void *)condition_value
) != 0) {
2003 case NECP_POLICY_CONDITION_UID
: {
2004 if (condition_length
>= sizeof(uid_t
)) {
2009 case NECP_POLICY_CONDITION_LOCAL_ADDR
:
2010 case NECP_POLICY_CONDITION_REMOTE_ADDR
: {
2011 if (!result_cannot_have_ip_layer
&& condition_length
>= sizeof(struct necp_policy_condition_addr
) &&
2012 necp_address_is_valid(&((struct necp_policy_condition_addr
*)(void *)condition_value
)->address
.sa
)) {
2017 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE
:
2018 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE
: {
2019 if (!result_cannot_have_ip_layer
&& condition_length
>= sizeof(struct necp_policy_condition_addr_range
) &&
2020 necp_address_is_valid(&((struct necp_policy_condition_addr_range
*)(void *)condition_value
)->start_address
.sa
) &&
2021 necp_address_is_valid(&((struct necp_policy_condition_addr_range
*)(void *)condition_value
)->end_address
.sa
)) {
2026 case NECP_POLICY_CONDITION_AGENT_TYPE
: {
2027 if (!(flags
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
) &&
2028 condition_length
>= sizeof(struct necp_policy_condition_agent_type
)) {
2033 case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL
: {
2034 if (condition_length
>= sizeof(u_int16_t
)) {
2039 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR
:
2040 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR
: {
2041 if (condition_length
>= sizeof(struct necp_policy_condition_addr
) &&
2042 necp_address_is_valid(&((struct necp_policy_condition_addr
*)(void *)condition_value
)->address
.sa
)) {
2047 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE
:
2048 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE
: {
2049 if (condition_length
>= sizeof(struct necp_policy_condition_addr_range
) &&
2050 necp_address_is_valid(&((struct necp_policy_condition_addr_range
*)(void *)condition_value
)->start_address
.sa
) &&
2051 necp_address_is_valid(&((struct necp_policy_condition_addr_range
*)(void *)condition_value
)->end_address
.sa
)) {
2056 case NECP_POLICY_CONDITION_CLIENT_FLAGS
: {
2057 if (condition_length
== 0 || condition_length
>= sizeof(u_int32_t
)) {
2062 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY
: {
2066 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY
: {
2070 case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS
: {
2071 if (condition_length
>= sizeof(u_int16_t
)) {
2072 u_int16_t packet_filter_tags
= *(u_int16_t
*)(void *)condition_value
;
2073 if (packet_filter_tags
> 0 && packet_filter_tags
<= NECP_POLICY_CONDITION_PACKET_FILTER_TAG_MAX
) {
2086 NECPLOG(LOG_DEBUG
, "Policy condition type %d, valid %d", type
, validated
);
2093 necp_policy_route_rule_is_default(u_int8_t
*buffer
, u_int32_t length
)
2095 return necp_policy_condition_get_value_length_from_buffer(buffer
, length
) == 0 &&
2096 necp_policy_condition_get_flags_from_buffer(buffer
, length
) == 0;
2100 necp_policy_route_rule_is_valid(u_int8_t
*buffer
, u_int32_t length
)
2102 bool validated
= FALSE
;
2103 u_int8_t type
= necp_policy_condition_get_type_from_buffer(buffer
, length
);
2105 case NECP_ROUTE_RULE_ALLOW_INTERFACE
: {
2109 case NECP_ROUTE_RULE_DENY_INTERFACE
: {
2113 case NECP_ROUTE_RULE_QOS_MARKING
: {
2117 case NECP_ROUTE_RULE_DENY_LQM_ABORT
: {
2128 NECPLOG(LOG_DEBUG
, "Policy route rule type %d, valid %d", type
, validated
);
2135 necp_get_posix_error_for_necp_error(int response_error
)
2137 switch (response_error
) {
2138 case NECP_ERROR_UNKNOWN_PACKET_TYPE
:
2139 case NECP_ERROR_INVALID_TLV
:
2140 case NECP_ERROR_POLICY_RESULT_INVALID
:
2141 case NECP_ERROR_POLICY_CONDITIONS_INVALID
:
2142 case NECP_ERROR_ROUTE_RULES_INVALID
: {
2145 case NECP_ERROR_POLICY_ID_NOT_FOUND
: {
2148 case NECP_ERROR_INVALID_PROCESS
: {
2151 case NECP_ERROR_INTERNAL
:
2158 static necp_policy_id
2159 necp_handle_policy_add(struct necp_session
*session
,
2160 u_int8_t
*tlv_buffer
, size_t tlv_buffer_length
, int offset
, int *return_error
)
2162 bool has_default_condition
= FALSE
;
2163 bool has_non_default_condition
= FALSE
;
2164 bool has_application_condition
= FALSE
;
2165 bool has_real_application_condition
= FALSE
;
2166 bool requires_application_condition
= FALSE
;
2167 bool requires_real_application_condition
= FALSE
;
2168 u_int8_t
*conditions_array
= NULL
;
2169 u_int32_t conditions_array_size
= 0;
2170 int conditions_array_cursor
;
2172 bool has_default_route_rule
= FALSE
;
2173 u_int8_t
*route_rules_array
= NULL
;
2174 u_int32_t route_rules_array_size
= 0;
2175 int route_rules_array_cursor
;
2179 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
2181 necp_policy_order order
= 0;
2182 struct necp_session_policy
*policy
= NULL
;
2183 u_int8_t
*policy_result
= NULL
;
2184 u_int32_t policy_result_size
= 0;
2186 // Read policy order
2187 error
= necp_get_tlv(tlv_buffer
, tlv_buffer_length
, offset
, NECP_TLV_POLICY_ORDER
, sizeof(order
), &order
, NULL
);
2189 NECPLOG(LOG_ERR
, "Failed to get policy order: %d", error
);
2190 response_error
= NECP_ERROR_INVALID_TLV
;
2194 // Read policy result
2195 cursor
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, offset
, NECP_TLV_POLICY_RESULT
, &error
, 0);
2196 if (error
|| cursor
< 0) {
2197 NECPLOG(LOG_ERR
, "Failed to find policy result TLV: %d", error
);
2198 response_error
= NECP_ERROR_INVALID_TLV
;
2201 error
= necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, 0, NULL
, &policy_result_size
);
2202 if (error
|| policy_result_size
== 0) {
2203 NECPLOG(LOG_ERR
, "Failed to get policy result length: %d", error
);
2204 response_error
= NECP_ERROR_INVALID_TLV
;
2207 if (policy_result_size
> NECP_MAX_POLICY_RESULT_SIZE
) {
2208 NECPLOG(LOG_ERR
, "Policy result length too large: %u", policy_result_size
);
2209 response_error
= NECP_ERROR_INVALID_TLV
;
2212 MALLOC(policy_result
, u_int8_t
*, policy_result_size
, M_NECP
, M_WAITOK
);
2213 if (policy_result
== NULL
) {
2214 NECPLOG(LOG_ERR
, "Failed to allocate a policy result buffer (size %d)", policy_result_size
);
2215 response_error
= NECP_ERROR_INTERNAL
;
2218 error
= necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, policy_result_size
, policy_result
, NULL
);
2220 NECPLOG(LOG_ERR
, "Failed to get policy result: %d", error
);
2221 response_error
= NECP_ERROR_POLICY_RESULT_INVALID
;
2224 if (!necp_policy_result_is_valid(policy_result
, policy_result_size
)) {
2225 NECPLOG0(LOG_ERR
, "Failed to validate policy result");
2226 response_error
= NECP_ERROR_POLICY_RESULT_INVALID
;
2230 if (necp_policy_result_requires_route_rules(policy_result
, policy_result_size
)) {
2231 // Read route rules conditions
2232 for (cursor
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, offset
, NECP_TLV_ROUTE_RULE
, &error
, 0);
2234 cursor
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, cursor
, NECP_TLV_ROUTE_RULE
, &error
, 1)) {
2235 u_int32_t route_rule_size
= 0;
2236 necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, 0, NULL
, &route_rule_size
);
2237 if (os_add_overflow(route_rules_array_size
,
2238 (sizeof(u_int8_t
) + sizeof(u_int32_t
) + route_rule_size
),
2239 &route_rules_array_size
)) {
2240 NECPLOG0(LOG_ERR
, "Route rules size overflowed, too large");
2241 response_error
= NECP_ERROR_INVALID_TLV
;
2246 if (route_rules_array_size
== 0) {
2247 NECPLOG0(LOG_ERR
, "Failed to get policy route rules");
2248 response_error
= NECP_ERROR_INVALID_TLV
;
2251 if (route_rules_array_size
> NECP_MAX_ROUTE_RULES_ARRAY_SIZE
) {
2252 NECPLOG(LOG_ERR
, "Route rules length too large: %u", route_rules_array_size
);
2253 response_error
= NECP_ERROR_INVALID_TLV
;
2256 MALLOC(route_rules_array
, u_int8_t
*, route_rules_array_size
, M_NECP
, M_WAITOK
);
2257 if (route_rules_array
== NULL
) {
2258 NECPLOG(LOG_ERR
, "Failed to allocate a policy route rules array (size %d)", route_rules_array_size
);
2259 response_error
= NECP_ERROR_INTERNAL
;
2263 route_rules_array_cursor
= 0;
2264 for (cursor
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, offset
, NECP_TLV_ROUTE_RULE
, &error
, 0);
2266 cursor
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, cursor
, NECP_TLV_ROUTE_RULE
, &error
, 1)) {
2267 u_int8_t route_rule_type
= NECP_TLV_ROUTE_RULE
;
2268 u_int32_t route_rule_size
= 0;
2269 necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, 0, NULL
, &route_rule_size
);
2270 if (route_rule_size
> 0 &&
2271 (sizeof(route_rule_type
) + sizeof(route_rule_size
) + route_rule_size
) <= (route_rules_array_size
- route_rules_array_cursor
)) {
2273 memcpy((route_rules_array
+ route_rules_array_cursor
), &route_rule_type
, sizeof(route_rule_type
));
2274 route_rules_array_cursor
+= sizeof(route_rule_type
);
2277 memcpy((route_rules_array
+ route_rules_array_cursor
), &route_rule_size
, sizeof(route_rule_size
));
2278 route_rules_array_cursor
+= sizeof(route_rule_size
);
2281 necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, route_rule_size
, (route_rules_array
+ route_rules_array_cursor
), NULL
);
2283 if (!necp_policy_route_rule_is_valid((route_rules_array
+ route_rules_array_cursor
), route_rule_size
)) {
2284 NECPLOG0(LOG_ERR
, "Failed to validate policy route rule");
2285 response_error
= NECP_ERROR_ROUTE_RULES_INVALID
;
2289 if (necp_policy_route_rule_is_default((route_rules_array
+ route_rules_array_cursor
), route_rule_size
)) {
2290 if (has_default_route_rule
) {
2291 NECPLOG0(LOG_ERR
, "Failed to validate route rule; contained multiple default route rules");
2292 response_error
= NECP_ERROR_ROUTE_RULES_INVALID
;
2295 has_default_route_rule
= TRUE
;
2298 route_rules_array_cursor
+= route_rule_size
;
2303 // Read policy conditions
2304 for (cursor
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, offset
, NECP_TLV_POLICY_CONDITION
, &error
, 0);
2306 cursor
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, cursor
, NECP_TLV_POLICY_CONDITION
, &error
, 1)) {
2307 u_int32_t condition_size
= 0;
2308 necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, 0, NULL
, &condition_size
);
2310 if (condition_size
> 0) {
2311 if (os_add_overflow(conditions_array_size
,
2312 (sizeof(u_int8_t
) + sizeof(u_int32_t
) + condition_size
),
2313 &conditions_array_size
)) {
2314 NECPLOG0(LOG_ERR
, "Conditions size overflowed, too large");
2315 response_error
= NECP_ERROR_INVALID_TLV
;
2321 if (conditions_array_size
== 0) {
2322 NECPLOG0(LOG_ERR
, "Failed to get policy conditions");
2323 response_error
= NECP_ERROR_INVALID_TLV
;
2326 if (conditions_array_size
> NECP_MAX_CONDITIONS_ARRAY_SIZE
) {
2327 NECPLOG(LOG_ERR
, "Conditions length too large: %u", conditions_array_size
);
2328 response_error
= NECP_ERROR_INVALID_TLV
;
2331 MALLOC(conditions_array
, u_int8_t
*, conditions_array_size
, M_NECP
, M_WAITOK
);
2332 if (conditions_array
== NULL
) {
2333 NECPLOG(LOG_ERR
, "Failed to allocate a policy conditions array (size %d)", conditions_array_size
);
2334 response_error
= NECP_ERROR_INTERNAL
;
2338 conditions_array_cursor
= 0;
2339 for (cursor
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, offset
, NECP_TLV_POLICY_CONDITION
, &error
, 0);
2341 cursor
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, cursor
, NECP_TLV_POLICY_CONDITION
, &error
, 1)) {
2342 u_int8_t condition_type
= NECP_TLV_POLICY_CONDITION
;
2343 u_int32_t condition_size
= 0;
2344 necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, 0, NULL
, &condition_size
);
2345 if (condition_size
> 0 &&
2346 (sizeof(condition_type
) + sizeof(condition_size
) + condition_size
) <= (conditions_array_size
- conditions_array_cursor
)) {
2348 memcpy((conditions_array
+ conditions_array_cursor
), &condition_type
, sizeof(condition_type
));
2349 conditions_array_cursor
+= sizeof(condition_type
);
2352 memcpy((conditions_array
+ conditions_array_cursor
), &condition_size
, sizeof(condition_size
));
2353 conditions_array_cursor
+= sizeof(condition_size
);
2356 necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, condition_size
, (conditions_array
+ conditions_array_cursor
), NULL
);
2357 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
))) {
2358 NECPLOG0(LOG_ERR
, "Failed to validate policy condition");
2359 response_error
= NECP_ERROR_POLICY_CONDITIONS_INVALID
;
2363 if (necp_policy_condition_is_default((conditions_array
+ conditions_array_cursor
), condition_size
)) {
2364 has_default_condition
= TRUE
;
2366 has_non_default_condition
= TRUE
;
2368 if (has_default_condition
&& has_non_default_condition
) {
2369 NECPLOG0(LOG_ERR
, "Failed to validate conditions; contained default and non-default conditions");
2370 response_error
= NECP_ERROR_POLICY_CONDITIONS_INVALID
;
2374 if (necp_policy_condition_is_application((conditions_array
+ conditions_array_cursor
), condition_size
)) {
2375 has_application_condition
= TRUE
;
2378 if (necp_policy_condition_is_real_application((conditions_array
+ conditions_array_cursor
), condition_size
)) {
2379 has_real_application_condition
= TRUE
;
2382 if (necp_policy_condition_requires_application((conditions_array
+ conditions_array_cursor
), condition_size
)) {
2383 requires_application_condition
= TRUE
;
2386 if (necp_policy_condition_requires_real_application((conditions_array
+ conditions_array_cursor
), condition_size
)) {
2387 requires_real_application_condition
= TRUE
;
2390 conditions_array_cursor
+= condition_size
;
2394 if (requires_application_condition
&& !has_application_condition
) {
2395 NECPLOG0(LOG_ERR
, "Failed to validate conditions; did not contain application condition");
2396 response_error
= NECP_ERROR_POLICY_CONDITIONS_INVALID
;
2400 if (requires_real_application_condition
&& !has_real_application_condition
) {
2401 NECPLOG0(LOG_ERR
, "Failed to validate conditions; did not contain real application condition");
2402 response_error
= NECP_ERROR_POLICY_CONDITIONS_INVALID
;
2406 if ((policy
= necp_policy_create(session
, order
, conditions_array
, conditions_array_size
, route_rules_array
, route_rules_array_size
, policy_result
, policy_result_size
)) == NULL
) {
2407 response_error
= NECP_ERROR_INTERNAL
;
2411 return policy
->local_id
;
2414 if (policy_result
!= NULL
) {
2415 FREE(policy_result
, M_NECP
);
2417 if (conditions_array
!= NULL
) {
2418 FREE(conditions_array
, M_NECP
);
2420 if (route_rules_array
!= NULL
) {
2421 FREE(route_rules_array
, M_NECP
);
2424 if (return_error
!= NULL
) {
2425 *return_error
= necp_get_posix_error_for_necp_error(response_error
);
2430 static necp_policy_id
2431 necp_policy_get_new_id(struct necp_session
*session
)
2433 session
->last_policy_id
++;
2434 if (session
->last_policy_id
< 1) {
2435 session
->last_policy_id
= 1;
2438 necp_policy_id newid
= session
->last_policy_id
;
2441 NECPLOG0(LOG_ERR
, "Allocate policy id failed.\n");
2449 * For the policy dump response this is the structure:
2451 * <NECP_PACKET_HEADER>
2453 * type : NECP_TLV_POLICY_DUMP
2458 * type : NECP_TLV_POLICY_ID
2463 * type : NECP_TLV_POLICY_ORDER
2468 * type : NECP_TLV_POLICY_RESULT_STRING
2473 * type : NECP_TLV_POLICY_OWNER
2478 * type : NECP_TLV_POLICY_CONDITION
2483 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
2488 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
2498 * type : NECP_TLV_POLICY_DUMP
2503 * type : NECP_TLV_POLICY_ID
2508 * type : NECP_TLV_POLICY_ORDER
2513 * type : NECP_TLV_POLICY_RESULT_STRING
2518 * type : NECP_TLV_POLICY_OWNER
2523 * type : NECP_TLV_POLICY_CONDITION
2528 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
2533 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
2545 necp_handle_policy_dump_all(user_addr_t out_buffer
, size_t out_buffer_length
)
2547 struct necp_kernel_socket_policy
*policy
= NULL
;
2549 int policy_count
= 0;
2550 u_int8_t
**tlv_buffer_pointers
= NULL
;
2551 u_int32_t
*tlv_buffer_lengths
= NULL
;
2552 u_int32_t total_tlv_len
= 0;
2553 u_int8_t
*result_buf
= NULL
;
2554 u_int8_t
*result_buf_cursor
= result_buf
;
2555 char result_string
[MAX_RESULT_STRING_LEN
];
2556 char proc_name_string
[MAXCOMLEN
+ 1];
2559 bool error_occured
= false;
2560 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
2562 #define REPORT_ERROR(error) error_occured = true; \
2563 response_error = error; \
2566 #define UNLOCK_AND_REPORT_ERROR(lock, error) lck_rw_done(lock); \
2569 errno_t cred_result
= priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES
, 0);
2570 if (cred_result
!= 0) {
2571 NECPLOG0(LOG_ERR
, "Session does not hold the necessary entitlement to get Network Extension Policy information");
2572 REPORT_ERROR(NECP_ERROR_INTERNAL
);
2576 lck_rw_lock_shared(&necp_kernel_policy_lock
);
2579 NECPLOG0(LOG_DEBUG
, "Gathering policies");
2582 policy_count
= necp_kernel_application_policies_count
;
2584 MALLOC(tlv_buffer_pointers
, u_int8_t
* *, sizeof(u_int8_t
*) * policy_count
, M_NECP
, M_NOWAIT
| M_ZERO
);
2585 if (tlv_buffer_pointers
== NULL
) {
2586 NECPLOG(LOG_DEBUG
, "Failed to allocate tlv_buffer_pointers (%lu bytes)", sizeof(u_int8_t
*) * policy_count
);
2587 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock
, NECP_ERROR_INTERNAL
);
2590 MALLOC(tlv_buffer_lengths
, u_int32_t
*, sizeof(u_int32_t
) * policy_count
, M_NECP
, M_NOWAIT
| M_ZERO
);
2591 if (tlv_buffer_lengths
== NULL
) {
2592 NECPLOG(LOG_DEBUG
, "Failed to allocate tlv_buffer_lengths (%lu bytes)", sizeof(u_int32_t
) * policy_count
);
2593 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock
, NECP_ERROR_INTERNAL
);
2596 for (policy_i
= 0; necp_kernel_socket_policies_app_layer_map
!= NULL
&& necp_kernel_socket_policies_app_layer_map
[policy_i
] != NULL
; policy_i
++) {
2597 policy
= necp_kernel_socket_policies_app_layer_map
[policy_i
];
2599 memset(result_string
, 0, MAX_RESULT_STRING_LEN
);
2600 memset(proc_name_string
, 0, MAXCOMLEN
+ 1);
2602 necp_get_result_description(result_string
, policy
->result
, policy
->result_parameter
);
2603 proc_name(policy
->session_pid
, proc_name_string
, MAXCOMLEN
);
2605 u_int16_t proc_name_len
= strlen(proc_name_string
) + 1;
2606 u_int16_t result_string_len
= strlen(result_string
) + 1;
2609 NECPLOG(LOG_DEBUG
, "Policy: process: %s, result: %s", proc_name_string
, result_string
);
2612 u_int32_t total_allocated_bytes
= sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(policy
->id
) + // NECP_TLV_POLICY_ID
2613 sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(policy
->order
) + // NECP_TLV_POLICY_ORDER
2614 sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(policy
->session_order
) + // NECP_TLV_POLICY_SESSION_ORDER
2615 sizeof(u_int8_t
) + sizeof(u_int32_t
) + result_string_len
+ // NECP_TLV_POLICY_RESULT_STRING
2616 sizeof(u_int8_t
) + sizeof(u_int32_t
) + proc_name_len
+ // NECP_TLV_POLICY_OWNER
2617 sizeof(u_int8_t
) + sizeof(u_int32_t
); // NECP_TLV_POLICY_CONDITION
2619 // We now traverse the condition_mask to see how much space we need to allocate
2620 u_int32_t condition_mask
= policy
->condition_mask
;
2621 u_int8_t num_conditions
= 0;
2622 struct necp_string_id_mapping
*account_id_entry
= NULL
;
2623 char if_name
[IFXNAMSIZ
];
2624 u_int32_t condition_tlv_length
= 0;
2625 memset(if_name
, 0, sizeof(if_name
));
2627 if (condition_mask
== NECP_POLICY_CONDITION_DEFAULT
) {
2630 if (condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) {
2633 if (condition_mask
& NECP_KERNEL_CONDITION_HAS_CLIENT
) {
2636 if (condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
2637 snprintf(if_name
, IFXNAMSIZ
, "%s%d", ifnet_name(policy
->cond_bound_interface
), ifnet_unit(policy
->cond_bound_interface
));
2638 condition_tlv_length
+= strlen(if_name
) + 1;
2641 if (condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
2642 condition_tlv_length
+= sizeof(policy
->cond_protocol
);
2645 if (condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
2646 condition_tlv_length
+= sizeof(uuid_t
);
2649 if (condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
2650 condition_tlv_length
+= sizeof(uuid_t
);
2653 if (condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
2654 u_int32_t domain_len
= strlen(policy
->cond_domain
) + 1;
2655 condition_tlv_length
+= domain_len
;
2658 if (condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
2659 account_id_entry
= necp_lookup_string_with_id_locked(&necp_account_id_list
, policy
->cond_account_id
);
2660 u_int32_t account_id_len
= 0;
2661 if (account_id_entry
) {
2662 account_id_len
= account_id_entry
->string
? strlen(account_id_entry
->string
) + 1 : 0;
2664 condition_tlv_length
+= account_id_len
;
2667 if (condition_mask
& NECP_KERNEL_CONDITION_PID
) {
2668 condition_tlv_length
+= sizeof(pid_t
);
2671 if (condition_mask
& NECP_KERNEL_CONDITION_UID
) {
2672 condition_tlv_length
+= sizeof(uid_t
);
2675 if (condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
2676 condition_tlv_length
+= sizeof(struct necp_policy_condition_tc_range
);
2679 if (condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
) {
2682 if (condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) {
2683 u_int32_t entitlement_len
= strlen(policy
->cond_custom_entitlement
) + 1;
2684 condition_tlv_length
+= entitlement_len
;
2687 if (condition_mask
& NECP_KERNEL_CONDITION_PLATFORM_BINARY
) {
2690 if (condition_mask
& NECP_KERNEL_CONDITION_SDK_VERSION
) {
2691 condition_tlv_length
+= sizeof(struct necp_policy_condition_sdk_version
);
2694 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) {
2697 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
2698 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
2699 condition_tlv_length
+= sizeof(struct necp_policy_condition_addr_range
);
2701 condition_tlv_length
+= sizeof(struct necp_policy_condition_addr
);
2705 if (condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
2706 if (condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
2707 condition_tlv_length
+= sizeof(struct necp_policy_condition_addr_range
);
2709 condition_tlv_length
+= sizeof(struct necp_policy_condition_addr
);
2713 if (condition_mask
& NECP_KERNEL_CONDITION_AGENT_TYPE
) {
2714 condition_tlv_length
+= sizeof(struct necp_policy_condition_agent_type
);
2717 if (condition_mask
& NECP_KERNEL_CONDITION_CLIENT_FLAGS
) {
2718 condition_tlv_length
+= sizeof(u_int32_t
);
2721 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_EMPTY
) {
2724 if (condition_mask
& NECP_KERNEL_CONDITION_REMOTE_EMPTY
) {
2727 if (condition_mask
& NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
) {
2728 u_int32_t identifier_len
= strlen(policy
->cond_signing_identifier
) + 1;
2729 condition_tlv_length
+= identifier_len
;
2732 if (condition_mask
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) {
2733 condition_tlv_length
+= sizeof(u_int16_t
);
2738 condition_tlv_length
+= num_conditions
* (sizeof(u_int8_t
) + sizeof(u_int32_t
)); // These are for the condition TLVs. The space for "value" is already accounted for above.
2739 total_allocated_bytes
+= condition_tlv_length
;
2741 u_int8_t
*tlv_buffer
;
2742 MALLOC(tlv_buffer
, u_int8_t
*, total_allocated_bytes
, M_NECP
, M_NOWAIT
| M_ZERO
);
2743 if (tlv_buffer
== NULL
) {
2744 NECPLOG(LOG_DEBUG
, "Failed to allocate tlv_buffer (%u bytes)", total_allocated_bytes
);
2748 u_int8_t
*cursor
= tlv_buffer
;
2749 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ID
, sizeof(policy
->id
), &policy
->id
, tlv_buffer
, total_allocated_bytes
);
2750 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ORDER
, sizeof(necp_policy_order
), &policy
->order
, tlv_buffer
, total_allocated_bytes
);
2751 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_SESSION_ORDER
, sizeof(policy
->session_order
), &policy
->session_order
, tlv_buffer
, total_allocated_bytes
);
2752 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_RESULT_STRING
, result_string_len
, result_string
, tlv_buffer
, total_allocated_bytes
);
2753 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_OWNER
, proc_name_len
, proc_name_string
, tlv_buffer
, total_allocated_bytes
);
2756 u_int8_t q_cond_buf
[N_QUICK
]; // Minor optimization
2758 u_int8_t
*cond_buf
; // To be used for condition TLVs
2759 if (condition_tlv_length
<= N_QUICK
) {
2760 cond_buf
= q_cond_buf
;
2762 MALLOC(cond_buf
, u_int8_t
*, condition_tlv_length
, M_NECP
, M_NOWAIT
);
2763 if (cond_buf
== NULL
) {
2764 NECPLOG(LOG_DEBUG
, "Failed to allocate cond_buffer (%u bytes)", condition_tlv_length
);
2765 FREE(tlv_buffer
, M_NECP
);
2770 memset(cond_buf
, 0, condition_tlv_length
);
2771 u_int8_t
*cond_buf_cursor
= cond_buf
;
2772 if (condition_mask
== NECP_POLICY_CONDITION_DEFAULT
) {
2773 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_DEFAULT
, 0, "", cond_buf
, condition_tlv_length
);
2775 if (condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) {
2776 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_ALL_INTERFACES
, 0, "", cond_buf
, condition_tlv_length
);
2778 if (condition_mask
& NECP_KERNEL_CONDITION_HAS_CLIENT
) {
2779 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_HAS_CLIENT
, 0, "", cond_buf
, condition_tlv_length
);
2781 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) {
2782 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_LOCAL_NETWORKS
, 0, "", cond_buf
, condition_tlv_length
);
2784 if (condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
2785 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_BOUND_INTERFACE
, strlen(if_name
) + 1,
2786 if_name
, cond_buf
, condition_tlv_length
);
2788 if (condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
2789 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_IP_PROTOCOL
, sizeof(policy
->cond_protocol
), &policy
->cond_protocol
,
2790 cond_buf
, condition_tlv_length
);
2792 if (condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
2793 struct necp_uuid_id_mapping
*entry
= necp_uuid_lookup_uuid_with_app_id_locked(policy
->cond_app_id
);
2794 if (entry
!= NULL
) {
2795 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_APPLICATION
, sizeof(entry
->uuid
), entry
->uuid
,
2796 cond_buf
, condition_tlv_length
);
2799 if (condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
2800 struct necp_uuid_id_mapping
*entry
= necp_uuid_lookup_uuid_with_app_id_locked(policy
->cond_real_app_id
);
2801 if (entry
!= NULL
) {
2802 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_REAL_APPLICATION
, sizeof(entry
->uuid
), entry
->uuid
,
2803 cond_buf
, condition_tlv_length
);
2806 if (condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
2807 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_DOMAIN
, strlen(policy
->cond_domain
) + 1, policy
->cond_domain
,
2808 cond_buf
, condition_tlv_length
);
2810 if (condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
2811 if (account_id_entry
!= NULL
) {
2812 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_ACCOUNT
, strlen(account_id_entry
->string
) + 1, account_id_entry
->string
,
2813 cond_buf
, condition_tlv_length
);
2816 if (condition_mask
& NECP_KERNEL_CONDITION_PID
) {
2817 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_PID
, sizeof(policy
->cond_pid
), &policy
->cond_pid
,
2818 cond_buf
, condition_tlv_length
);
2820 if (condition_mask
& NECP_KERNEL_CONDITION_UID
) {
2821 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_UID
, sizeof(policy
->cond_uid
), &policy
->cond_uid
,
2822 cond_buf
, condition_tlv_length
);
2824 if (condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
2825 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_TRAFFIC_CLASS
, sizeof(policy
->cond_traffic_class
), &policy
->cond_traffic_class
,
2826 cond_buf
, condition_tlv_length
);
2828 if (condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
) {
2829 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_ENTITLEMENT
, 0, "",
2830 cond_buf
, condition_tlv_length
);
2832 if (condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) {
2833 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_ENTITLEMENT
, strlen(policy
->cond_custom_entitlement
) + 1, policy
->cond_custom_entitlement
,
2834 cond_buf
, condition_tlv_length
);
2836 if (condition_mask
& NECP_KERNEL_CONDITION_PLATFORM_BINARY
) {
2837 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_PLATFORM_BINARY
, 0, "", cond_buf
, condition_tlv_length
);
2839 if (condition_mask
& NECP_KERNEL_CONDITION_SDK_VERSION
) {
2840 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_SDK_VERSION
,
2841 sizeof(policy
->cond_sdk_version
), &policy
->cond_sdk_version
,
2842 cond_buf
, condition_tlv_length
);
2844 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
2845 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
2846 struct necp_policy_condition_addr_range range
;
2847 memcpy(&range
.start_address
, &policy
->cond_local_start
, sizeof(policy
->cond_local_start
));
2848 memcpy(&range
.end_address
, &policy
->cond_local_end
, sizeof(policy
->cond_local_end
));
2849 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE
, sizeof(range
), &range
,
2850 cond_buf
, condition_tlv_length
);
2852 struct necp_policy_condition_addr addr
;
2853 addr
.prefix
= policy
->cond_local_prefix
;
2854 memcpy(&addr
.address
, &policy
->cond_local_start
, sizeof(policy
->cond_local_start
));
2855 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_LOCAL_ADDR
, sizeof(addr
), &addr
,
2856 cond_buf
, condition_tlv_length
);
2859 if (condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
2860 if (condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
2861 struct necp_policy_condition_addr_range range
;
2862 memcpy(&range
.start_address
, &policy
->cond_remote_start
, sizeof(policy
->cond_remote_start
));
2863 memcpy(&range
.end_address
, &policy
->cond_remote_end
, sizeof(policy
->cond_remote_end
));
2864 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE
, sizeof(range
), &range
,
2865 cond_buf
, condition_tlv_length
);
2867 struct necp_policy_condition_addr addr
;
2868 addr
.prefix
= policy
->cond_remote_prefix
;
2869 memcpy(&addr
.address
, &policy
->cond_remote_start
, sizeof(policy
->cond_remote_start
));
2870 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_REMOTE_ADDR
, sizeof(addr
), &addr
,
2871 cond_buf
, condition_tlv_length
);
2874 if (condition_mask
& NECP_KERNEL_CONDITION_AGENT_TYPE
) {
2875 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_AGENT_TYPE
,
2876 sizeof(policy
->cond_agent_type
), &policy
->cond_agent_type
,
2877 cond_buf
, condition_tlv_length
);
2879 if (condition_mask
& NECP_KERNEL_CONDITION_CLIENT_FLAGS
) {
2880 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_CLIENT_FLAGS
, sizeof(policy
->cond_client_flags
), &policy
->cond_client_flags
, cond_buf
, condition_tlv_length
);
2882 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_EMPTY
) {
2883 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY
, 0, "", cond_buf
, condition_tlv_length
);
2885 if (condition_mask
& NECP_KERNEL_CONDITION_REMOTE_EMPTY
) {
2886 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY
, 0, "", cond_buf
, condition_tlv_length
);
2888 if (condition_mask
& NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
) {
2889 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_SIGNING_IDENTIFIER
, strlen(policy
->cond_signing_identifier
) + 1, policy
->cond_signing_identifier
,
2890 cond_buf
, condition_tlv_length
);
2892 if (condition_mask
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) {
2893 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_PACKET_FILTER_TAGS
, sizeof(policy
->cond_packet_filter_tags
), &policy
->cond_packet_filter_tags
, cond_buf
, condition_tlv_length
);
2897 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_CONDITION
, cond_buf_cursor
- cond_buf
, cond_buf
, tlv_buffer
, total_allocated_bytes
);
2898 if (cond_buf
!= q_cond_buf
) {
2899 FREE(cond_buf
, M_NECP
);
2902 tlv_buffer_pointers
[policy_i
] = tlv_buffer
;
2903 tlv_buffer_lengths
[policy_i
] = (cursor
- tlv_buffer
);
2905 // This is the length of the TLV for NECP_TLV_POLICY_DUMP
2906 total_tlv_len
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + (cursor
- tlv_buffer
);
2910 lck_rw_done(&necp_kernel_policy_lock
);
2913 if (out_buffer
!= 0) {
2914 if (out_buffer_length
< total_tlv_len
+ sizeof(u_int32_t
)) {
2915 NECPLOG(LOG_DEBUG
, "out_buffer_length too small (%lu < %lu)", out_buffer_length
, total_tlv_len
+ sizeof(u_int32_t
));
2916 REPORT_ERROR(NECP_ERROR_INVALID_TLV
);
2919 // Allow malloc to wait, since the total buffer may be large and we are not holding any locks
2920 MALLOC(result_buf
, u_int8_t
*, total_tlv_len
+ sizeof(u_int32_t
), M_NECP
, M_WAITOK
| M_ZERO
);
2921 if (result_buf
== NULL
) {
2922 NECPLOG(LOG_DEBUG
, "Failed to allocate result_buffer (%lu bytes)", total_tlv_len
+ sizeof(u_int32_t
));
2923 REPORT_ERROR(NECP_ERROR_INTERNAL
);
2926 // Add four bytes for total length at the start
2927 memcpy(result_buf
, &total_tlv_len
, sizeof(u_int32_t
));
2930 result_buf_cursor
= result_buf
+ sizeof(u_int32_t
);
2931 for (int i
= 0; i
< policy_count
; i
++) {
2932 if (tlv_buffer_pointers
[i
] != NULL
) {
2933 result_buf_cursor
= necp_buffer_write_tlv(result_buf_cursor
, NECP_TLV_POLICY_DUMP
, tlv_buffer_lengths
[i
], tlv_buffer_pointers
[i
],
2934 result_buf
, total_tlv_len
+ sizeof(u_int32_t
));
2938 int copy_error
= copyout(result_buf
, out_buffer
, total_tlv_len
+ sizeof(u_int32_t
));
2940 NECPLOG(LOG_DEBUG
, "Failed to copy out result_buffer (%lu bytes)", total_tlv_len
+ sizeof(u_int32_t
));
2941 REPORT_ERROR(NECP_ERROR_INTERNAL
);
2947 if (error_occured
) {
2948 error_code
= necp_get_posix_error_for_necp_error(response_error
);
2951 if (result_buf
!= NULL
) {
2952 FREE(result_buf
, M_NECP
);
2955 if (tlv_buffer_pointers
!= NULL
) {
2956 for (int i
= 0; i
< policy_count
; i
++) {
2957 if (tlv_buffer_pointers
[i
] != NULL
) {
2958 FREE(tlv_buffer_pointers
[i
], M_NECP
);
2959 tlv_buffer_pointers
[i
] = NULL
;
2962 FREE(tlv_buffer_pointers
, M_NECP
);
2965 if (tlv_buffer_lengths
!= NULL
) {
2966 FREE(tlv_buffer_lengths
, M_NECP
);
2969 #undef RESET_COND_BUF
2971 #undef UNLOCK_AND_REPORT_ERROR
2976 static struct necp_session_policy
*
2977 necp_policy_create(struct necp_session
*session
, necp_policy_order order
, u_int8_t
*conditions_array
, u_int32_t conditions_array_size
, u_int8_t
*route_rules_array
, u_int32_t route_rules_array_size
, u_int8_t
*result
, u_int32_t result_size
)
2979 struct necp_session_policy
*new_policy
= NULL
;
2980 struct necp_session_policy
*tmp_policy
= NULL
;
2982 if (session
== NULL
|| conditions_array
== NULL
|| result
== NULL
|| result_size
== 0) {
2986 new_policy
= zalloc_flags(necp_session_policy_zone
, Z_WAITOK
| Z_ZERO
);
2987 new_policy
->applied
= FALSE
;
2988 new_policy
->pending_deletion
= FALSE
;
2989 new_policy
->pending_update
= FALSE
;
2990 new_policy
->order
= order
;
2991 new_policy
->conditions
= conditions_array
;
2992 new_policy
->conditions_size
= conditions_array_size
;
2993 new_policy
->route_rules
= route_rules_array
;
2994 new_policy
->route_rules_size
= route_rules_array_size
;
2995 new_policy
->result
= result
;
2996 new_policy
->result_size
= result_size
;
2997 new_policy
->local_id
= necp_policy_get_new_id(session
);
2999 LIST_INSERT_SORTED_ASCENDING(&session
->policies
, new_policy
, chain
, order
, tmp_policy
);
3001 session
->dirty
= TRUE
;
3004 NECPLOG(LOG_DEBUG
, "Created NECP policy, order %d", order
);
3010 static struct necp_session_policy
*
3011 necp_policy_find(struct necp_session
*session
, necp_policy_id policy_id
)
3013 struct necp_session_policy
*policy
= NULL
;
3014 if (policy_id
== 0) {
3018 LIST_FOREACH(policy
, &session
->policies
, chain
) {
3019 if (policy
->local_id
== policy_id
) {
3027 static inline u_int8_t
3028 necp_policy_get_result_type(struct necp_session_policy
*policy
)
3030 return policy
? necp_policy_result_get_type_from_buffer(policy
->result
, policy
->result_size
) : 0;
3033 static inline u_int32_t
3034 necp_policy_get_result_parameter_length(struct necp_session_policy
*policy
)
3036 return policy
? necp_policy_result_get_parameter_length_from_buffer(policy
->result
, policy
->result_size
) : 0;
3040 necp_policy_get_result_parameter(struct necp_session_policy
*policy
, u_int8_t
*parameter_buffer
, u_int32_t parameter_buffer_length
)
3043 u_int32_t parameter_length
= necp_policy_result_get_parameter_length_from_buffer(policy
->result
, policy
->result_size
);
3044 if (parameter_buffer_length
>= parameter_length
) {
3045 u_int8_t
*parameter
= necp_policy_result_get_parameter_pointer_from_buffer(policy
->result
, policy
->result_size
);
3046 if (parameter
&& parameter_buffer
) {
3047 memcpy(parameter_buffer
, parameter
, parameter_length
);
3057 necp_policy_mark_for_deletion(struct necp_session
*session
, struct necp_session_policy
*policy
)
3059 if (session
== NULL
|| policy
== NULL
) {
3063 policy
->pending_deletion
= TRUE
;
3064 session
->dirty
= TRUE
;
3067 NECPLOG0(LOG_DEBUG
, "Marked NECP policy for removal");
3073 necp_policy_mark_all_for_deletion(struct necp_session
*session
)
3075 struct necp_session_policy
*policy
= NULL
;
3076 struct necp_session_policy
*temp_policy
= NULL
;
3078 LIST_FOREACH_SAFE(policy
, &session
->policies
, chain
, temp_policy
) {
3079 necp_policy_mark_for_deletion(session
, policy
);
3086 necp_policy_delete(struct necp_session
*session
, struct necp_session_policy
*policy
)
3088 if (session
== NULL
|| policy
== NULL
) {
3092 LIST_REMOVE(policy
, chain
);
3094 if (policy
->result
) {
3095 FREE(policy
->result
, M_NECP
);
3096 policy
->result
= NULL
;
3099 if (policy
->conditions
) {
3100 FREE(policy
->conditions
, M_NECP
);
3101 policy
->conditions
= NULL
;
3104 if (policy
->route_rules
) {
3105 FREE(policy
->route_rules
, M_NECP
);
3106 policy
->route_rules
= NULL
;
3109 zfree(necp_session_policy_zone
, policy
);
3112 NECPLOG0(LOG_DEBUG
, "Removed NECP policy");
3118 necp_policy_unapply(struct necp_session_policy
*policy
)
3121 if (policy
== NULL
) {
3125 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
3127 // Release local uuid mappings
3128 if (!uuid_is_null(policy
->applied_app_uuid
)) {
3129 bool removed_mapping
= FALSE
;
3130 if (necp_remove_uuid_app_id_mapping(policy
->applied_app_uuid
, &removed_mapping
, TRUE
) && removed_mapping
) {
3131 necp_uuid_app_id_mappings_dirty
= TRUE
;
3132 necp_num_uuid_app_id_mappings
--;
3134 uuid_clear(policy
->applied_app_uuid
);
3136 if (!uuid_is_null(policy
->applied_real_app_uuid
)) {
3137 necp_remove_uuid_app_id_mapping(policy
->applied_real_app_uuid
, NULL
, FALSE
);
3138 uuid_clear(policy
->applied_real_app_uuid
);
3140 if (!uuid_is_null(policy
->applied_result_uuid
)) {
3141 necp_remove_uuid_service_id_mapping(policy
->applied_result_uuid
);
3142 uuid_clear(policy
->applied_result_uuid
);
3145 // Release string mappings
3146 if (policy
->applied_account
!= NULL
) {
3147 necp_remove_string_to_id_mapping(&necp_account_id_list
, policy
->applied_account
);
3148 FREE(policy
->applied_account
, M_NECP
);
3149 policy
->applied_account
= NULL
;
3152 // Release route rule
3153 if (policy
->applied_route_rules_id
!= 0) {
3154 necp_remove_route_rule(&necp_route_rules
, policy
->applied_route_rules_id
);
3155 policy
->applied_route_rules_id
= 0;
3158 // Remove socket policies
3159 for (i
= 0; i
< MAX_KERNEL_SOCKET_POLICIES
; i
++) {
3160 if (policy
->kernel_socket_policies
[i
] != 0) {
3161 necp_kernel_socket_policy_delete(policy
->kernel_socket_policies
[i
]);
3162 policy
->kernel_socket_policies
[i
] = 0;
3166 // Remove IP output policies
3167 for (i
= 0; i
< MAX_KERNEL_IP_OUTPUT_POLICIES
; i
++) {
3168 if (policy
->kernel_ip_output_policies
[i
] != 0) {
3169 necp_kernel_ip_output_policy_delete(policy
->kernel_ip_output_policies
[i
]);
3170 policy
->kernel_ip_output_policies
[i
] = 0;
3174 policy
->applied
= FALSE
;
3179 #define NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION 0
3180 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION 1
3181 #define NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION 2
3182 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS 3
3183 struct necp_policy_result_ip_tunnel
{
3184 u_int32_t secondary_result
;
3185 char interface_name
[IFXNAMSIZ
];
3186 } __attribute__((__packed__
));
3188 struct necp_policy_result_service
{
3191 } __attribute__((__packed__
));
3194 necp_policy_apply(struct necp_session
*session
, struct necp_session_policy
*policy
)
3196 bool socket_only_conditions
= FALSE
;
3197 bool socket_ip_conditions
= FALSE
;
3199 bool socket_layer_non_id_conditions
= FALSE
;
3200 bool ip_output_layer_non_id_conditions
= FALSE
;
3201 bool ip_output_layer_non_id_only
= FALSE
;
3202 bool ip_output_layer_id_condition
= FALSE
;
3203 bool ip_output_layer_tunnel_condition_from_id
= FALSE
;
3204 bool ip_output_layer_tunnel_condition_from_non_id
= FALSE
;
3205 necp_kernel_policy_id cond_ip_output_layer_id
= NECP_KERNEL_POLICY_ID_NONE
;
3207 u_int32_t master_condition_mask
= 0;
3208 u_int32_t master_condition_negated_mask
= 0;
3209 ifnet_t cond_bound_interface
= NULL
;
3210 u_int32_t cond_account_id
= 0;
3211 char *cond_domain
= NULL
;
3212 char *cond_custom_entitlement
= NULL
;
3213 char *cond_signing_identifier
= NULL
;
3216 necp_app_id cond_app_id
= 0;
3217 necp_app_id cond_real_app_id
= 0;
3218 struct necp_policy_condition_tc_range cond_traffic_class
;
3219 cond_traffic_class
.start_tc
= 0;
3220 cond_traffic_class
.end_tc
= 0;
3221 u_int16_t cond_protocol
= 0;
3222 union necp_sockaddr_union cond_local_start
;
3223 union necp_sockaddr_union cond_local_end
;
3224 u_int8_t cond_local_prefix
= 0;
3225 union necp_sockaddr_union cond_remote_start
;
3226 union necp_sockaddr_union cond_remote_end
;
3227 u_int8_t cond_remote_prefix
= 0;
3228 u_int32_t cond_client_flags
= 0;
3229 u_int32_t offset
= 0;
3230 u_int8_t ultimate_result
= 0;
3231 u_int32_t secondary_result
= 0;
3232 struct necp_policy_condition_agent_type cond_agent_type
= {};
3233 struct necp_policy_condition_sdk_version cond_sdk_version
= {};
3234 u_int16_t cond_packet_filter_tags
= 0;
3235 necp_kernel_policy_result_parameter secondary_result_parameter
;
3236 memset(&secondary_result_parameter
, 0, sizeof(secondary_result_parameter
));
3237 u_int32_t cond_last_interface_index
= 0;
3238 necp_kernel_policy_result_parameter ultimate_result_parameter
;
3239 memset(&ultimate_result_parameter
, 0, sizeof(ultimate_result_parameter
));
3241 if (policy
== NULL
) {
3245 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
3247 // Process conditions
3248 while (offset
< policy
->conditions_size
) {
3249 u_int32_t length
= 0;
3250 u_int8_t
*value
= necp_buffer_get_tlv_value(policy
->conditions
, offset
, &length
);
3252 u_int8_t condition_type
= necp_policy_condition_get_type_from_buffer(value
, length
);
3253 u_int8_t condition_flags
= necp_policy_condition_get_flags_from_buffer(value
, length
);
3254 bool condition_is_negative
= condition_flags
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
;
3255 u_int32_t condition_length
= necp_policy_condition_get_value_length_from_buffer(value
, length
);
3256 u_int8_t
*condition_value
= necp_policy_condition_get_value_pointer_from_buffer(value
, length
);
3257 switch (condition_type
) {
3258 case NECP_POLICY_CONDITION_DEFAULT
: {
3259 socket_ip_conditions
= TRUE
;
3262 case NECP_POLICY_CONDITION_ALL_INTERFACES
: {
3263 master_condition_mask
|= NECP_KERNEL_CONDITION_ALL_INTERFACES
;
3264 socket_ip_conditions
= TRUE
;
3267 case NECP_POLICY_CONDITION_HAS_CLIENT
: {
3268 master_condition_mask
|= NECP_KERNEL_CONDITION_HAS_CLIENT
;
3269 socket_only_conditions
= TRUE
;
3272 case NECP_POLICY_CONDITION_ENTITLEMENT
: {
3273 if (condition_length
> 0) {
3274 if (cond_custom_entitlement
== NULL
) {
3275 cond_custom_entitlement
= necp_copy_string((char *)condition_value
, condition_length
);
3276 if (cond_custom_entitlement
!= NULL
) {
3277 master_condition_mask
|= NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
;
3278 socket_only_conditions
= TRUE
;
3282 master_condition_mask
|= NECP_KERNEL_CONDITION_ENTITLEMENT
;
3283 socket_only_conditions
= TRUE
;
3287 case NECP_POLICY_CONDITION_PLATFORM_BINARY
: {
3288 master_condition_mask
|= NECP_KERNEL_CONDITION_PLATFORM_BINARY
;
3289 socket_only_conditions
= TRUE
;
3292 case NECP_POLICY_CONDITION_SDK_VERSION
: {
3293 if (condition_length
>= sizeof(cond_sdk_version
)) {
3294 master_condition_mask
|= NECP_KERNEL_CONDITION_SDK_VERSION
;
3295 memcpy(&cond_sdk_version
, condition_value
, sizeof(cond_sdk_version
));
3296 socket_only_conditions
= TRUE
;
3300 case NECP_POLICY_CONDITION_DOMAIN
: {
3301 // Make sure there is only one such rule
3302 if (condition_length
> 0 && cond_domain
== NULL
) {
3303 cond_domain
= necp_create_trimmed_domain((char *)condition_value
, condition_length
);
3304 if (cond_domain
!= NULL
) {
3305 master_condition_mask
|= NECP_KERNEL_CONDITION_DOMAIN
;
3306 if (condition_is_negative
) {
3307 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_DOMAIN
;
3309 socket_only_conditions
= TRUE
;
3314 case NECP_POLICY_CONDITION_ACCOUNT
: {
3315 // Make sure there is only one such rule
3316 if (condition_length
> 0 && cond_account_id
== 0 && policy
->applied_account
== NULL
) {
3317 char *string
= NULL
;
3318 MALLOC(string
, char *, condition_length
+ 1, M_NECP
, M_WAITOK
);
3319 if (string
!= NULL
) {
3320 memcpy(string
, condition_value
, condition_length
);
3321 string
[condition_length
] = 0;
3322 cond_account_id
= necp_create_string_to_id_mapping(&necp_account_id_list
, string
);
3323 if (cond_account_id
!= 0) {
3324 policy
->applied_account
= string
; // Save the string in parent policy
3325 master_condition_mask
|= NECP_KERNEL_CONDITION_ACCOUNT_ID
;
3326 if (condition_is_negative
) {
3327 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_ACCOUNT_ID
;
3329 socket_only_conditions
= TRUE
;
3331 FREE(string
, M_NECP
);
3337 case NECP_POLICY_CONDITION_APPLICATION
: {
3338 // Make sure there is only one such rule, because we save the uuid in the policy
3339 if (condition_length
>= sizeof(uuid_t
) && cond_app_id
== 0) {
3340 bool allocated_mapping
= FALSE
;
3341 uuid_t application_uuid
;
3342 memcpy(application_uuid
, condition_value
, sizeof(uuid_t
));
3343 cond_app_id
= necp_create_uuid_app_id_mapping(application_uuid
, &allocated_mapping
, TRUE
);
3344 if (cond_app_id
!= 0) {
3345 if (allocated_mapping
) {
3346 necp_uuid_app_id_mappings_dirty
= TRUE
;
3347 necp_num_uuid_app_id_mappings
++;
3349 uuid_copy(policy
->applied_app_uuid
, application_uuid
);
3350 master_condition_mask
|= NECP_KERNEL_CONDITION_APP_ID
;
3351 if (condition_is_negative
) {
3352 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_APP_ID
;
3354 socket_only_conditions
= TRUE
;
3359 case NECP_POLICY_CONDITION_REAL_APPLICATION
: {
3360 // Make sure there is only one such rule, because we save the uuid in the policy
3361 if (condition_length
>= sizeof(uuid_t
) && cond_real_app_id
== 0) {
3362 uuid_t real_application_uuid
;
3363 memcpy(real_application_uuid
, condition_value
, sizeof(uuid_t
));
3364 cond_real_app_id
= necp_create_uuid_app_id_mapping(real_application_uuid
, NULL
, FALSE
);
3365 if (cond_real_app_id
!= 0) {
3366 uuid_copy(policy
->applied_real_app_uuid
, real_application_uuid
);
3367 master_condition_mask
|= NECP_KERNEL_CONDITION_REAL_APP_ID
;
3368 if (condition_is_negative
) {
3369 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REAL_APP_ID
;
3371 socket_only_conditions
= TRUE
;
3376 case NECP_POLICY_CONDITION_PID
: {
3377 if (condition_length
>= sizeof(pid_t
)) {
3378 master_condition_mask
|= NECP_KERNEL_CONDITION_PID
;
3379 if (condition_is_negative
) {
3380 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_PID
;
3382 memcpy(&cond_pid
, condition_value
, sizeof(cond_pid
));
3383 socket_only_conditions
= TRUE
;
3387 case NECP_POLICY_CONDITION_UID
: {
3388 if (condition_length
>= sizeof(uid_t
)) {
3389 master_condition_mask
|= NECP_KERNEL_CONDITION_UID
;
3390 if (condition_is_negative
) {
3391 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_UID
;
3393 memcpy(&cond_uid
, condition_value
, sizeof(cond_uid
));
3394 socket_only_conditions
= TRUE
;
3398 case NECP_POLICY_CONDITION_TRAFFIC_CLASS
: {
3399 if (condition_length
>= sizeof(struct necp_policy_condition_tc_range
)) {
3400 master_condition_mask
|= NECP_KERNEL_CONDITION_TRAFFIC_CLASS
;
3401 if (condition_is_negative
) {
3402 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_TRAFFIC_CLASS
;
3404 memcpy(&cond_traffic_class
, condition_value
, sizeof(cond_traffic_class
));
3405 socket_only_conditions
= TRUE
;
3409 case NECP_POLICY_CONDITION_BOUND_INTERFACE
: {
3410 if (condition_length
<= IFXNAMSIZ
&& condition_length
> 0) {
3411 char interface_name
[IFXNAMSIZ
];
3412 memcpy(interface_name
, condition_value
, condition_length
);
3413 interface_name
[condition_length
- 1] = 0; // Make sure the string is NULL terminated
3414 if (ifnet_find_by_name(interface_name
, &cond_bound_interface
) == 0) {
3415 master_condition_mask
|= NECP_KERNEL_CONDITION_BOUND_INTERFACE
;
3416 if (condition_is_negative
) {
3417 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_BOUND_INTERFACE
;
3420 socket_ip_conditions
= TRUE
;
3424 case NECP_POLICY_CONDITION_IP_PROTOCOL
:
3425 case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL
: {
3426 if (condition_length
>= sizeof(u_int16_t
)) {
3427 master_condition_mask
|= NECP_KERNEL_CONDITION_PROTOCOL
;
3428 if (condition_is_negative
) {
3429 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_PROTOCOL
;
3431 memcpy(&cond_protocol
, condition_value
, sizeof(cond_protocol
));
3432 if (condition_type
== NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL
) {
3433 socket_only_conditions
= TRUE
;
3435 socket_ip_conditions
= TRUE
;
3440 case NECP_POLICY_CONDITION_LOCAL_NETWORKS
: {
3441 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_NETWORKS
;
3442 socket_ip_conditions
= TRUE
;
3445 case NECP_POLICY_CONDITION_LOCAL_ADDR
:
3446 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR
: {
3447 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)condition_value
;
3448 if (!necp_address_is_valid(&address_struct
->address
.sa
)) {
3452 cond_local_prefix
= address_struct
->prefix
;
3453 memcpy(&cond_local_start
, &address_struct
->address
, sizeof(address_struct
->address
));
3454 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_START
;
3455 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_PREFIX
;
3456 if (condition_is_negative
) {
3457 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_START
;
3458 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_PREFIX
;
3460 if (condition_type
== NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR
) {
3461 socket_only_conditions
= TRUE
;
3463 socket_ip_conditions
= TRUE
;
3467 case NECP_POLICY_CONDITION_REMOTE_ADDR
:
3468 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR
: {
3469 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)condition_value
;
3470 if (!necp_address_is_valid(&address_struct
->address
.sa
)) {
3474 cond_remote_prefix
= address_struct
->prefix
;
3475 memcpy(&cond_remote_start
, &address_struct
->address
, sizeof(address_struct
->address
));
3476 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_START
;
3477 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_PREFIX
;
3478 if (condition_is_negative
) {
3479 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_START
;
3480 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_PREFIX
;
3482 if (condition_type
== NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR
) {
3483 socket_only_conditions
= TRUE
;
3485 socket_ip_conditions
= TRUE
;
3489 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE
:
3490 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE
: {
3491 struct necp_policy_condition_addr_range
*address_struct
= (struct necp_policy_condition_addr_range
*)(void *)condition_value
;
3492 if (!necp_address_is_valid(&address_struct
->start_address
.sa
) ||
3493 !necp_address_is_valid(&address_struct
->end_address
.sa
)) {
3497 memcpy(&cond_local_start
, &address_struct
->start_address
, sizeof(address_struct
->start_address
));
3498 memcpy(&cond_local_end
, &address_struct
->end_address
, sizeof(address_struct
->end_address
));
3499 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_START
;
3500 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_END
;
3501 if (condition_is_negative
) {
3502 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_START
;
3503 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_END
;
3505 if (condition_type
== NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE
) {
3506 socket_only_conditions
= TRUE
;
3508 socket_ip_conditions
= TRUE
;
3512 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE
:
3513 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE
: {
3514 struct necp_policy_condition_addr_range
*address_struct
= (struct necp_policy_condition_addr_range
*)(void *)condition_value
;
3515 if (!necp_address_is_valid(&address_struct
->start_address
.sa
) ||
3516 !necp_address_is_valid(&address_struct
->end_address
.sa
)) {
3520 memcpy(&cond_remote_start
, &address_struct
->start_address
, sizeof(address_struct
->start_address
));
3521 memcpy(&cond_remote_end
, &address_struct
->end_address
, sizeof(address_struct
->end_address
));
3522 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_START
;
3523 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_END
;
3524 if (condition_is_negative
) {
3525 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_START
;
3526 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_END
;
3528 if (condition_type
== NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE
) {
3529 socket_only_conditions
= TRUE
;
3531 socket_ip_conditions
= TRUE
;
3535 case NECP_POLICY_CONDITION_AGENT_TYPE
: {
3536 if (condition_length
>= sizeof(cond_agent_type
)) {
3537 master_condition_mask
|= NECP_KERNEL_CONDITION_AGENT_TYPE
;
3538 memcpy(&cond_agent_type
, condition_value
, sizeof(cond_agent_type
));
3539 socket_only_conditions
= TRUE
;
3543 case NECP_POLICY_CONDITION_CLIENT_FLAGS
: {
3544 if (condition_is_negative
) {
3545 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_CLIENT_FLAGS
;
3547 master_condition_mask
|= NECP_KERNEL_CONDITION_CLIENT_FLAGS
;
3548 socket_only_conditions
= TRUE
;
3549 if (condition_length
>= sizeof(u_int32_t
)) {
3550 memcpy(&cond_client_flags
, condition_value
, sizeof(cond_client_flags
));
3552 // Empty means match on fallback traffic
3553 cond_client_flags
= NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC
;
3557 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY
: {
3558 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_EMPTY
;
3559 if (condition_is_negative
) {
3560 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_EMPTY
;
3562 socket_only_conditions
= TRUE
;
3565 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY
: {
3566 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_EMPTY
;
3567 if (condition_is_negative
) {
3568 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_EMPTY
;
3570 socket_only_conditions
= TRUE
;
3573 case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER
: {
3574 if (condition_length
> 0) {
3575 if (cond_signing_identifier
== NULL
) {
3576 cond_signing_identifier
= necp_copy_string((char *)condition_value
, condition_length
);
3577 if (cond_signing_identifier
!= NULL
) {
3578 master_condition_mask
|= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
;
3579 socket_only_conditions
= TRUE
;
3580 if (condition_is_negative
) {
3581 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
;
3588 case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS
: {
3589 if (condition_length
>= sizeof(u_int16_t
)) {
3590 master_condition_mask
|= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
;
3591 if (condition_is_negative
) {
3592 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
;
3594 memcpy(&cond_packet_filter_tags
, condition_value
, sizeof(cond_packet_filter_tags
));
3595 socket_ip_conditions
= TRUE
;
3604 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
3608 ultimate_result
= necp_policy_get_result_type(policy
);
3609 switch (ultimate_result
) {
3610 case NECP_POLICY_RESULT_PASS
: {
3611 u_int32_t pass_flags
= 0;
3612 if (necp_policy_result_get_parameter_length_from_buffer(policy
->result
, policy
->result_size
) > 0) {
3613 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&pass_flags
, sizeof(pass_flags
))) {
3614 ultimate_result_parameter
.pass_flags
= pass_flags
;
3617 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
3618 socket_layer_non_id_conditions
= TRUE
;
3619 ip_output_layer_id_condition
= TRUE
;
3620 } else if (socket_ip_conditions
) {
3621 socket_layer_non_id_conditions
= TRUE
;
3622 ip_output_layer_id_condition
= TRUE
;
3623 ip_output_layer_non_id_conditions
= TRUE
;
3627 case NECP_POLICY_RESULT_DROP
: {
3628 u_int32_t drop_flags
= 0;
3629 if (necp_policy_result_get_parameter_length_from_buffer(policy
->result
, policy
->result_size
) > 0) {
3630 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&drop_flags
, sizeof(drop_flags
))) {
3631 ultimate_result_parameter
.drop_flags
= drop_flags
;
3634 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
3635 socket_layer_non_id_conditions
= TRUE
;
3636 } else if (socket_ip_conditions
) {
3637 socket_layer_non_id_conditions
= TRUE
;
3638 ip_output_layer_non_id_conditions
= TRUE
;
3639 ip_output_layer_non_id_only
= TRUE
; // Only apply drop to packets that didn't go through socket layer
3643 case NECP_POLICY_RESULT_SKIP
: {
3644 u_int32_t skip_policy_order
= 0;
3645 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&skip_policy_order
, sizeof(skip_policy_order
))) {
3646 ultimate_result_parameter
.skip_policy_order
= skip_policy_order
;
3649 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
3650 socket_layer_non_id_conditions
= TRUE
;
3651 ip_output_layer_id_condition
= TRUE
;
3652 } else if (socket_ip_conditions
) {
3653 socket_layer_non_id_conditions
= TRUE
;
3654 ip_output_layer_non_id_conditions
= TRUE
;
3658 case NECP_POLICY_RESULT_SOCKET_DIVERT
:
3659 case NECP_POLICY_RESULT_SOCKET_FILTER
: {
3660 u_int32_t control_unit
= 0;
3661 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&control_unit
, sizeof(control_unit
))) {
3662 ultimate_result_parameter
.flow_divert_control_unit
= control_unit
;
3664 socket_layer_non_id_conditions
= TRUE
;
3667 case NECP_POLICY_RESULT_IP_TUNNEL
: {
3668 struct necp_policy_result_ip_tunnel tunnel_parameters
;
3669 u_int32_t tunnel_parameters_length
= necp_policy_get_result_parameter_length(policy
);
3670 if (tunnel_parameters_length
> sizeof(u_int32_t
) &&
3671 tunnel_parameters_length
<= sizeof(struct necp_policy_result_ip_tunnel
) &&
3672 necp_policy_get_result_parameter(policy
, (u_int8_t
*)&tunnel_parameters
, sizeof(tunnel_parameters
))) {
3673 ifnet_t tunnel_interface
= NULL
;
3674 tunnel_parameters
.interface_name
[tunnel_parameters_length
- sizeof(u_int32_t
) - 1] = 0; // Make sure the string is NULL terminated
3675 if (ifnet_find_by_name(tunnel_parameters
.interface_name
, &tunnel_interface
) == 0) {
3676 ultimate_result_parameter
.tunnel_interface_index
= tunnel_interface
->if_index
;
3677 ifnet_release(tunnel_interface
);
3680 secondary_result
= tunnel_parameters
.secondary_result
;
3681 if (secondary_result
) {
3682 cond_last_interface_index
= ultimate_result_parameter
.tunnel_interface_index
;
3686 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
3687 socket_layer_non_id_conditions
= TRUE
;
3688 ip_output_layer_id_condition
= TRUE
;
3689 if (secondary_result
) {
3690 ip_output_layer_tunnel_condition_from_id
= TRUE
;
3692 } else if (socket_ip_conditions
) {
3693 socket_layer_non_id_conditions
= TRUE
;
3694 ip_output_layer_id_condition
= TRUE
;
3695 ip_output_layer_non_id_conditions
= TRUE
;
3696 if (secondary_result
) {
3697 ip_output_layer_tunnel_condition_from_id
= TRUE
;
3698 ip_output_layer_tunnel_condition_from_non_id
= TRUE
;
3703 case NECP_POLICY_RESULT_TRIGGER
:
3704 case NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
:
3705 case NECP_POLICY_RESULT_TRIGGER_SCOPED
:
3706 case NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
: {
3707 struct necp_policy_result_service service_parameters
;
3708 u_int32_t service_result_length
= necp_policy_get_result_parameter_length(policy
);
3709 bool has_extra_service_data
= FALSE
;
3710 if (service_result_length
>= (sizeof(service_parameters
))) {
3711 has_extra_service_data
= TRUE
;
3713 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&service_parameters
, sizeof(service_parameters
))) {
3714 ultimate_result_parameter
.service
.identifier
= necp_create_uuid_service_id_mapping(service_parameters
.identifier
);
3715 if (ultimate_result_parameter
.service
.identifier
!= 0) {
3716 uuid_copy(policy
->applied_result_uuid
, service_parameters
.identifier
);
3717 socket_layer_non_id_conditions
= TRUE
;
3718 if (has_extra_service_data
) {
3719 ultimate_result_parameter
.service
.data
= service_parameters
.data
;
3721 ultimate_result_parameter
.service
.data
= 0;
3727 case NECP_POLICY_RESULT_USE_NETAGENT
:
3728 case NECP_POLICY_RESULT_NETAGENT_SCOPED
: {
3729 uuid_t netagent_uuid
;
3730 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&netagent_uuid
, sizeof(netagent_uuid
))) {
3731 ultimate_result_parameter
.netagent_id
= necp_create_uuid_service_id_mapping(netagent_uuid
);
3732 if (ultimate_result_parameter
.netagent_id
!= 0) {
3733 uuid_copy(policy
->applied_result_uuid
, netagent_uuid
);
3734 socket_layer_non_id_conditions
= TRUE
;
3739 case NECP_POLICY_RESULT_SOCKET_SCOPED
: {
3740 u_int32_t interface_name_length
= necp_policy_get_result_parameter_length(policy
);
3741 if (interface_name_length
<= IFXNAMSIZ
&& interface_name_length
> 0) {
3742 char interface_name
[IFXNAMSIZ
];
3743 ifnet_t scope_interface
= NULL
;
3744 necp_policy_get_result_parameter(policy
, (u_int8_t
*)interface_name
, interface_name_length
);
3745 interface_name
[interface_name_length
- 1] = 0; // Make sure the string is NULL terminated
3746 if (ifnet_find_by_name(interface_name
, &scope_interface
) == 0) {
3747 ultimate_result_parameter
.scoped_interface_index
= scope_interface
->if_index
;
3748 socket_layer_non_id_conditions
= TRUE
;
3749 ifnet_release(scope_interface
);
3754 case NECP_POLICY_RESULT_SCOPED_DIRECT
: {
3755 socket_layer_non_id_conditions
= TRUE
;
3758 case NECP_POLICY_RESULT_ALLOW_UNENTITLED
: {
3759 socket_layer_non_id_conditions
= TRUE
;
3762 case NECP_POLICY_RESULT_ROUTE_RULES
: {
3763 if (policy
->route_rules
!= NULL
&& policy
->route_rules_size
> 0) {
3764 u_int32_t route_rule_id
= necp_create_route_rule(&necp_route_rules
, policy
->route_rules
, policy
->route_rules_size
);
3765 if (route_rule_id
> 0) {
3766 policy
->applied_route_rules_id
= route_rule_id
;
3767 ultimate_result_parameter
.route_rule_id
= route_rule_id
;
3768 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
3769 socket_layer_non_id_conditions
= TRUE
;
3770 } else if (socket_ip_conditions
) {
3771 socket_layer_non_id_conditions
= TRUE
;
3772 ip_output_layer_non_id_conditions
= TRUE
;
3773 ip_output_layer_non_id_only
= TRUE
; // Only apply route rules to packets that didn't go through socket layer
3784 if (socket_layer_non_id_conditions
) {
3785 necp_kernel_policy_id policy_id
= necp_kernel_socket_policy_add(policy
->order
, session
->session_order
, session
->proc_pid
, master_condition_mask
, master_condition_negated_mask
, cond_app_id
, cond_real_app_id
, cond_custom_entitlement
, 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
, &cond_agent_type
, &cond_sdk_version
, cond_client_flags
, cond_signing_identifier
, cond_packet_filter_tags
, ultimate_result
, ultimate_result_parameter
);
3787 if (policy_id
== 0) {
3788 NECPLOG0(LOG_DEBUG
, "Error applying socket kernel policy");
3792 cond_ip_output_layer_id
= policy_id
;
3793 policy
->kernel_socket_policies
[0] = policy_id
;
3796 if (ip_output_layer_non_id_conditions
) {
3797 u_int32_t condition_mask
= master_condition_mask
;
3798 if (ip_output_layer_non_id_only
) {
3799 condition_mask
|= NECP_KERNEL_CONDITION_POLICY_ID
;
3802 necp_kernel_policy_id policy_id
= necp_kernel_ip_output_policy_add(policy
->order
, NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS
, session
->session_order
, session
->proc_pid
, 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
, cond_packet_filter_tags
, ultimate_result
, ultimate_result_parameter
);
3804 if (policy_id
== 0) {
3805 NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy");
3809 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS
] = policy_id
;
3812 if (ip_output_layer_id_condition
) {
3813 necp_kernel_policy_id policy_id
= necp_kernel_ip_output_policy_add(policy
->order
, NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION
, session
->session_order
, session
->proc_pid
, 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, 0, ultimate_result
, ultimate_result_parameter
);
3815 if (policy_id
== 0) {
3816 NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy");
3820 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION
] = policy_id
;
3823 // Extra policies for IP Output tunnels for when packets loop back
3824 if (ip_output_layer_tunnel_condition_from_id
) {
3825 necp_kernel_policy_id policy_id
= necp_kernel_ip_output_policy_add(policy
->order
, NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION
, session
->session_order
, session
->proc_pid
, 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, 0, secondary_result
, secondary_result_parameter
);
3827 if (policy_id
== 0) {
3828 NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy");
3832 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION
] = policy_id
;
3835 if (ip_output_layer_tunnel_condition_from_id
) {
3836 necp_kernel_policy_id policy_id
= necp_kernel_ip_output_policy_add(policy
->order
, NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION
, session
->session_order
, session
->proc_pid
, 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, 0, secondary_result
, secondary_result_parameter
);
3838 if (policy_id
== 0) {
3839 NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy");
3843 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION
] = policy_id
;
3846 policy
->applied
= TRUE
;
3847 policy
->pending_update
= FALSE
;
3855 necp_policy_apply_all(struct necp_session
*session
)
3857 struct necp_session_policy
*policy
= NULL
;
3858 struct necp_session_policy
*temp_policy
= NULL
;
3859 struct kev_necp_policies_changed_data kev_data
;
3860 kev_data
.changed_count
= 0;
3862 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
3864 // Remove exisiting applied policies
3865 if (session
->dirty
) {
3866 LIST_FOREACH_SAFE(policy
, &session
->policies
, chain
, temp_policy
) {
3867 if (policy
->pending_deletion
) {
3868 if (policy
->applied
) {
3869 necp_policy_unapply(policy
);
3871 // Delete the policy
3872 necp_policy_delete(session
, policy
);
3873 } else if (!policy
->applied
) {
3874 necp_policy_apply(session
, policy
);
3875 } else if (policy
->pending_update
) {
3876 // Must have been applied, but needs an update. Remove and re-add.
3877 necp_policy_unapply(policy
);
3878 necp_policy_apply(session
, policy
);
3882 necp_kernel_socket_policies_update_uuid_table();
3883 necp_kernel_socket_policies_reprocess();
3884 necp_kernel_ip_output_policies_reprocess();
3886 // Clear dirty bit flags
3887 session
->dirty
= FALSE
;
3890 lck_rw_done(&necp_kernel_policy_lock
);
3892 necp_update_all_clients();
3893 necp_post_change_event(&kev_data
);
3896 NECPLOG0(LOG_DEBUG
, "Applied NECP policies");
3900 // Kernel Policy Management
3901 // ---------------------
3902 // Kernel policies are derived from session policies
3903 static necp_kernel_policy_id
3904 necp_kernel_policy_get_new_id(bool socket_level
)
3906 static necp_kernel_policy_id necp_last_kernel_socket_policy_id
= 0;
3907 static necp_kernel_policy_id necp_last_kernel_ip_policy_id
= 0;
3909 necp_kernel_policy_id newid
= NECP_KERNEL_POLICY_ID_NONE
;
3911 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
3914 bool wrapped
= FALSE
;
3916 necp_last_kernel_socket_policy_id
++;
3917 if (necp_last_kernel_socket_policy_id
< NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET
||
3918 necp_last_kernel_socket_policy_id
>= NECP_KERNEL_POLICY_ID_FIRST_VALID_IP
) {
3920 // Already wrapped, give up
3921 NECPLOG0(LOG_ERR
, "Failed to find a free socket kernel policy ID.\n");
3922 return NECP_KERNEL_POLICY_ID_NONE
;
3924 necp_last_kernel_socket_policy_id
= NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET
;
3927 newid
= necp_last_kernel_socket_policy_id
;
3928 } while (necp_kernel_socket_policy_find(newid
) != NULL
); // If already used, keep trying
3930 bool wrapped
= FALSE
;
3932 necp_last_kernel_ip_policy_id
++;
3933 if (necp_last_kernel_ip_policy_id
< NECP_KERNEL_POLICY_ID_FIRST_VALID_IP
) {
3935 // Already wrapped, give up
3936 NECPLOG0(LOG_ERR
, "Failed to find a free IP kernel policy ID.\n");
3937 return NECP_KERNEL_POLICY_ID_NONE
;
3939 necp_last_kernel_ip_policy_id
= NECP_KERNEL_POLICY_ID_FIRST_VALID_IP
;
3942 newid
= necp_last_kernel_ip_policy_id
;
3943 } while (necp_kernel_ip_output_policy_find(newid
) != NULL
); // If already used, keep trying
3946 if (newid
== NECP_KERNEL_POLICY_ID_NONE
) {
3947 NECPLOG0(LOG_ERR
, "Allocate kernel policy id failed.\n");
3948 return NECP_KERNEL_POLICY_ID_NONE
;
3954 #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 | NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT | NECP_KERNEL_CONDITION_AGENT_TYPE | NECP_KERNEL_CONDITION_HAS_CLIENT | NECP_KERNEL_CONDITION_LOCAL_NETWORKS | NECP_KERNEL_CONDITION_CLIENT_FLAGS | NECP_KERNEL_CONDITION_LOCAL_EMPTY | NECP_KERNEL_CONDITION_REMOTE_EMPTY | NECP_KERNEL_CONDITION_PLATFORM_BINARY | NECP_KERNEL_CONDITION_SDK_VERSION | NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER | NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS)
3956 static necp_kernel_policy_id
3957 necp_kernel_socket_policy_add(necp_policy_order order
, u_int32_t session_order
, int session_pid
, u_int32_t condition_mask
, u_int32_t condition_negated_mask
, necp_app_id cond_app_id
, necp_app_id cond_real_app_id
, char *cond_custom_entitlement
, 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
, struct necp_policy_condition_agent_type
*cond_agent_type
, struct necp_policy_condition_sdk_version
*cond_sdk_version
, u_int32_t cond_client_flags
, char *cond_signing_identifier
, u_int16_t cond_packet_filter_tags
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
)
3959 struct necp_kernel_socket_policy
*new_kernel_policy
= NULL
;
3960 struct necp_kernel_socket_policy
*tmp_kernel_policy
= NULL
;
3962 new_kernel_policy
= zalloc_flags(necp_socket_policy_zone
, Z_WAITOK
| Z_ZERO
);
3964 new_kernel_policy
->id
= necp_kernel_policy_get_new_id(true);
3965 new_kernel_policy
->order
= order
;
3966 new_kernel_policy
->session_order
= session_order
;
3967 new_kernel_policy
->session_pid
= session_pid
;
3969 // Sanitize condition mask
3970 new_kernel_policy
->condition_mask
= (condition_mask
& NECP_KERNEL_VALID_SOCKET_CONDITIONS
);
3971 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
)) {
3972 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE
;
3974 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) && !(new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
)) {
3975 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_REAL_APP_ID
;
3977 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) && !(new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
)) {
3978 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
;
3980 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
)) {
3981 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX
;
3983 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
)) {
3984 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX
;
3986 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_EMPTY
) {
3987 new_kernel_policy
->condition_mask
&= ~(NECP_KERNEL_CONDITION_LOCAL_PREFIX
| NECP_KERNEL_CONDITION_LOCAL_END
);
3989 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_EMPTY
)) {
3990 new_kernel_policy
->condition_mask
&= ~(NECP_KERNEL_CONDITION_REMOTE_PREFIX
| NECP_KERNEL_CONDITION_REMOTE_END
);
3992 new_kernel_policy
->condition_negated_mask
= condition_negated_mask
& new_kernel_policy
->condition_mask
;
3994 // Set condition values
3995 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
3996 new_kernel_policy
->cond_app_id
= cond_app_id
;
3998 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
3999 new_kernel_policy
->cond_real_app_id
= cond_real_app_id
;
4001 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) {
4002 new_kernel_policy
->cond_custom_entitlement
= cond_custom_entitlement
;
4003 new_kernel_policy
->cond_custom_entitlement_matched
= necp_boolean_state_unknown
;
4005 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
4006 new_kernel_policy
->cond_account_id
= cond_account_id
;
4008 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
4009 new_kernel_policy
->cond_domain
= cond_domain
;
4010 new_kernel_policy
->cond_domain_dot_count
= necp_count_dots(cond_domain
, strlen(cond_domain
));
4012 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PID
) {
4013 new_kernel_policy
->cond_pid
= cond_pid
;
4015 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_UID
) {
4016 new_kernel_policy
->cond_uid
= cond_uid
;
4018 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
4019 if (cond_bound_interface
) {
4020 ifnet_reference(cond_bound_interface
);
4022 new_kernel_policy
->cond_bound_interface
= cond_bound_interface
;
4024 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
4025 new_kernel_policy
->cond_traffic_class
= cond_traffic_class
;
4027 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
4028 new_kernel_policy
->cond_protocol
= cond_protocol
;
4030 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
4031 memcpy(&new_kernel_policy
->cond_local_start
, cond_local_start
, cond_local_start
->sa
.sa_len
);
4033 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
4034 memcpy(&new_kernel_policy
->cond_local_end
, cond_local_end
, cond_local_end
->sa
.sa_len
);
4036 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
4037 new_kernel_policy
->cond_local_prefix
= cond_local_prefix
;
4039 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
4040 memcpy(&new_kernel_policy
->cond_remote_start
, cond_remote_start
, cond_remote_start
->sa
.sa_len
);
4042 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
4043 memcpy(&new_kernel_policy
->cond_remote_end
, cond_remote_end
, cond_remote_end
->sa
.sa_len
);
4045 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
4046 new_kernel_policy
->cond_remote_prefix
= cond_remote_prefix
;
4048 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_AGENT_TYPE
) {
4049 memcpy(&new_kernel_policy
->cond_agent_type
, cond_agent_type
, sizeof(*cond_agent_type
));
4051 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_SDK_VERSION
) {
4052 memcpy(&new_kernel_policy
->cond_sdk_version
, cond_sdk_version
, sizeof(*cond_sdk_version
));
4054 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_CLIENT_FLAGS
) {
4055 new_kernel_policy
->cond_client_flags
= cond_client_flags
;
4057 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
) {
4058 new_kernel_policy
->cond_signing_identifier
= cond_signing_identifier
;
4060 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) {
4061 new_kernel_policy
->cond_packet_filter_tags
= cond_packet_filter_tags
;
4064 new_kernel_policy
->result
= result
;
4065 memcpy(&new_kernel_policy
->result_parameter
, &result_parameter
, sizeof(result_parameter
));
4068 NECPLOG(LOG_DEBUG
, "Added kernel policy: socket, id=%d, mask=%x\n", new_kernel_policy
->id
, new_kernel_policy
->condition_mask
);
4070 LIST_INSERT_SORTED_TWICE_ASCENDING(&necp_kernel_socket_policies
, new_kernel_policy
, chain
, session_order
, order
, tmp_kernel_policy
);
4072 return new_kernel_policy
? new_kernel_policy
->id
: 0;
4075 static struct necp_kernel_socket_policy
*
4076 necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id
)
4078 struct necp_kernel_socket_policy
*kernel_policy
= NULL
;
4079 struct necp_kernel_socket_policy
*tmp_kernel_policy
= NULL
;
4081 if (policy_id
== 0) {
4085 LIST_FOREACH_SAFE(kernel_policy
, &necp_kernel_socket_policies
, chain
, tmp_kernel_policy
) {
4086 if (kernel_policy
->id
== policy_id
) {
4087 return kernel_policy
;
4095 necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id
)
4097 struct necp_kernel_socket_policy
*policy
= NULL
;
4099 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4101 policy
= necp_kernel_socket_policy_find(policy_id
);
4103 LIST_REMOVE(policy
, chain
);
4105 if (policy
->cond_bound_interface
) {
4106 ifnet_release(policy
->cond_bound_interface
);
4107 policy
->cond_bound_interface
= NULL
;
4110 if (policy
->cond_domain
) {
4111 FREE(policy
->cond_domain
, M_NECP
);
4112 policy
->cond_domain
= NULL
;
4115 if (policy
->cond_custom_entitlement
) {
4116 FREE(policy
->cond_custom_entitlement
, M_NECP
);
4117 policy
->cond_custom_entitlement
= NULL
;
4120 if (policy
->cond_signing_identifier
) {
4121 FREE(policy
->cond_signing_identifier
, M_NECP
);
4122 policy
->cond_signing_identifier
= NULL
;
4125 zfree(necp_socket_policy_zone
, policy
);
4132 static inline const char *
4133 necp_get_result_description(char *result_string
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
)
4135 uuid_string_t uuid_string
;
4137 case NECP_KERNEL_POLICY_RESULT_NONE
: {
4138 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "None");
4141 case NECP_KERNEL_POLICY_RESULT_PASS
: {
4142 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Pass (%X)", result_parameter
.pass_flags
);
4145 case NECP_KERNEL_POLICY_RESULT_SKIP
: {
4146 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Skip (%u)", result_parameter
.skip_policy_order
);
4149 case NECP_KERNEL_POLICY_RESULT_DROP
: {
4150 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Drop (%X)", result_parameter
.drop_flags
);
4153 case NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
: {
4154 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "SocketDivert (%d)", result_parameter
.flow_divert_control_unit
);
4157 case NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER
: {
4158 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "SocketFilter (%d)", result_parameter
.filter_control_unit
);
4161 case NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
: {
4162 ifnet_t interface
= ifindex2ifnet
[result_parameter
.tunnel_interface_index
];
4163 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "IPTunnel (%s%d)", ifnet_name(interface
), ifnet_unit(interface
));
4166 case NECP_KERNEL_POLICY_RESULT_IP_FILTER
: {
4167 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "IPFilter");
4170 case NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
: {
4171 ifnet_t interface
= ifindex2ifnet
[result_parameter
.scoped_interface_index
];
4172 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "SocketScoped (%s%d)", ifnet_name(interface
), ifnet_unit(interface
));
4175 case NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT
: {
4176 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "ScopedDirect");
4179 case NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED
: {
4180 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "AllowUnentitled");
4183 case NECP_KERNEL_POLICY_RESULT_ROUTE_RULES
: {
4185 char interface_names
[MAX_ROUTE_RULE_INTERFACES
][IFXNAMSIZ
];
4186 struct necp_route_rule
*route_rule
= necp_lookup_route_rule_locked(&necp_route_rules
, result_parameter
.route_rule_id
);
4187 if (route_rule
!= NULL
) {
4188 for (index
= 0; index
< MAX_ROUTE_RULE_INTERFACES
; index
++) {
4189 if (route_rule
->exception_if_indices
[index
] != 0) {
4190 ifnet_t interface
= ifindex2ifnet
[route_rule
->exception_if_indices
[index
]];
4191 snprintf(interface_names
[index
], IFXNAMSIZ
, "%s%d", ifnet_name(interface
), ifnet_unit(interface
));
4193 memset(interface_names
[index
], 0, IFXNAMSIZ
);
4196 switch (route_rule
->default_action
) {
4197 case NECP_ROUTE_RULE_DENY_INTERFACE
:
4198 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "RouteRules (Only %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s)",
4199 (route_rule
->cellular_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "Cell " : "",
4200 (route_rule
->wifi_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "WiFi " : "",
4201 (route_rule
->wired_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "Wired " : "",
4202 (route_rule
->expensive_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "Exp " : "",
4203 (route_rule
->constrained_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "Constrained " : "",
4204 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[0] : "",
4205 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
4206 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[1] : "",
4207 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
4208 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[2] : "",
4209 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
4210 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[3] : "",
4211 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
4212 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[4] : "",
4213 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
4214 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[5] : "",
4215 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
4216 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[6] : "",
4217 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
4218 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[7] : "",
4219 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
4220 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[8] : "",
4221 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
4222 (route_rule
->exception_if_actions
[9] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[9] : "");
4224 case NECP_ROUTE_RULE_ALLOW_INTERFACE
:
4225 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "RouteRules (%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s)",
4226 (route_rule
->cellular_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!Cell " : "",
4227 (route_rule
->wifi_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!WiFi " : "",
4228 (route_rule
->wired_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!Wired " : "",
4229 (route_rule
->expensive_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!Exp " : "",
4230 (route_rule
->constrained_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!Constrained " : "",
4231 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
4232 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[0] : "",
4233 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
4234 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[1] : "",
4235 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
4236 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[2] : "",
4237 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
4238 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[3] : "",
4239 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
4240 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[4] : "",
4241 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
4242 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[5] : "",
4243 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
4244 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[6] : "",
4245 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
4246 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[7] : "",
4247 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
4248 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[8] : "",
4249 (route_rule
->exception_if_actions
[9] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
4250 (route_rule
->exception_if_actions
[9] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[9] : "");
4252 case NECP_ROUTE_RULE_QOS_MARKING
:
4253 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "RouteRules (QoSMarking %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s)",
4254 (route_rule
->cellular_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? "Cell " : "",
4255 (route_rule
->wifi_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? "WiFi " : "",
4256 (route_rule
->wired_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? "Wired " : "",
4257 (route_rule
->expensive_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? "Exp " : "",
4258 (route_rule
->constrained_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? "Constrained " : "",
4259 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[0] : "",
4260 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
4261 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[1] : "",
4262 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
4263 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[2] : "",
4264 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
4265 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[3] : "",
4266 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
4267 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[4] : "",
4268 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
4269 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[5] : "",
4270 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
4271 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[6] : "",
4272 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
4273 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[7] : "",
4274 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
4275 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[8] : "",
4276 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
4277 (route_rule
->exception_if_actions
[9] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[9] : "");
4280 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "RouteRules (Unknown)");
4286 case NECP_KERNEL_POLICY_RESULT_USE_NETAGENT
: {
4287 bool found_mapping
= FALSE
;
4288 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.netagent_id
);
4289 if (mapping
!= NULL
) {
4290 uuid_unparse(mapping
->uuid
, uuid_string
);
4291 found_mapping
= TRUE
;
4293 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "UseNetAgent (%s)", found_mapping
? uuid_string
: "Unknown");
4296 case NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED
: {
4297 bool found_mapping
= FALSE
;
4298 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.netagent_id
);
4299 if (mapping
!= NULL
) {
4300 uuid_unparse(mapping
->uuid
, uuid_string
);
4301 found_mapping
= TRUE
;
4303 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "NetAgentScoped (%s)", found_mapping
? uuid_string
: "Unknown");
4306 case NECP_POLICY_RESULT_TRIGGER
: {
4307 bool found_mapping
= FALSE
;
4308 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.service
.identifier
);
4309 if (mapping
!= NULL
) {
4310 uuid_unparse(mapping
->uuid
, uuid_string
);
4311 found_mapping
= TRUE
;
4313 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Trigger (%s.%d)", found_mapping
? uuid_string
: "Unknown", result_parameter
.service
.data
);
4316 case NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
: {
4317 bool found_mapping
= FALSE
;
4318 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.service
.identifier
);
4319 if (mapping
!= NULL
) {
4320 uuid_unparse(mapping
->uuid
, uuid_string
);
4321 found_mapping
= TRUE
;
4323 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "TriggerIfNeeded (%s.%d)", found_mapping
? uuid_string
: "Unknown", result_parameter
.service
.data
);
4326 case NECP_POLICY_RESULT_TRIGGER_SCOPED
: {
4327 bool found_mapping
= FALSE
;
4328 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.service
.identifier
);
4329 if (mapping
!= NULL
) {
4330 uuid_unparse(mapping
->uuid
, uuid_string
);
4331 found_mapping
= TRUE
;
4333 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "TriggerScoped (%s.%d)", found_mapping
? uuid_string
: "Unknown", result_parameter
.service
.data
);
4336 case NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
: {
4337 bool found_mapping
= FALSE
;
4338 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.service
.identifier
);
4339 if (mapping
!= NULL
) {
4340 uuid_unparse(mapping
->uuid
, uuid_string
);
4341 found_mapping
= TRUE
;
4343 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "NoTriggerScoped (%s.%d)", found_mapping
? uuid_string
: "Unknown", result_parameter
.service
.data
);
4347 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Unknown %d (%d)", result
, result_parameter
.tunnel_interface_index
);
4351 return result_string
;
4355 necp_kernel_socket_policies_dump_all(void)
4358 struct necp_kernel_socket_policy
*policy
= NULL
;
4361 char result_string
[MAX_RESULT_STRING_LEN
];
4362 char proc_name_string
[MAXCOMLEN
+ 1];
4363 memset(result_string
, 0, MAX_RESULT_STRING_LEN
);
4364 memset(proc_name_string
, 0, MAXCOMLEN
+ 1);
4366 NECPLOG0(LOG_DEBUG
, "NECP Application Policies:\n");
4367 NECPLOG0(LOG_DEBUG
, "-----------\n");
4368 for (policy_i
= 0; necp_kernel_socket_policies_app_layer_map
!= NULL
&& necp_kernel_socket_policies_app_layer_map
[policy_i
] != NULL
; policy_i
++) {
4369 policy
= necp_kernel_socket_policies_app_layer_map
[policy_i
];
4370 proc_name(policy
->session_pid
, proc_name_string
, MAXCOMLEN
);
4371 NECPLOG(LOG_DEBUG
, "\t%3d. Policy ID: %5d\tProcess: %10.10s\tOrder: %04d.%04d\tMask: %5x\tResult: %s\n", policy_i
, policy
->id
, proc_name_string
, policy
->session_order
, policy
->order
, policy
->condition_mask
, necp_get_result_description(result_string
, policy
->result
, policy
->result_parameter
));
4373 if (necp_kernel_socket_policies_app_layer_map
[0] != NULL
) {
4374 NECPLOG0(LOG_DEBUG
, "-----------\n");
4377 NECPLOG0(LOG_DEBUG
, "NECP Socket Policies:\n");
4378 NECPLOG0(LOG_DEBUG
, "-----------\n");
4379 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
4380 NECPLOG(LOG_DEBUG
, "\tApp Bucket: %d\n", app_i
);
4381 for (policy_i
= 0; necp_kernel_socket_policies_map
[app_i
] != NULL
&& (necp_kernel_socket_policies_map
[app_i
])[policy_i
] != NULL
; policy_i
++) {
4382 policy
= (necp_kernel_socket_policies_map
[app_i
])[policy_i
];
4383 proc_name(policy
->session_pid
, proc_name_string
, MAXCOMLEN
);
4384 NECPLOG(LOG_DEBUG
, "\t%3d. Policy ID: %5d\tProcess: %10.10s\tOrder: %04d.%04d\tMask: %5x\tResult: %s\n", policy_i
, policy
->id
, proc_name_string
, policy
->session_order
, policy
->order
, policy
->condition_mask
, necp_get_result_description(result_string
, policy
->result
, policy
->result_parameter
));
4386 NECPLOG0(LOG_DEBUG
, "-----------\n");
4392 necp_kernel_socket_result_is_trigger_service_type(struct necp_kernel_socket_policy
*kernel_policy
)
4394 return kernel_policy
->result
>= NECP_KERNEL_POLICY_RESULT_TRIGGER
&& kernel_policy
->result
<= NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED
;
4398 necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy
*upper_policy
, struct necp_kernel_socket_policy
*lower_policy
)
4400 if (upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_DROP
) {
4401 // Drop always cancels out lower policies
4403 } else if (upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER
||
4404 upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_ROUTE_RULES
||
4405 upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_USE_NETAGENT
||
4406 upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED
||
4407 upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED
) {
4408 // Filters and route rules never cancel out lower policies
4410 } else if (necp_kernel_socket_result_is_trigger_service_type(upper_policy
)) {
4411 // Trigger/Scoping policies can overlap one another, but not other results
4412 return necp_kernel_socket_result_is_trigger_service_type(lower_policy
);
4413 } else if (upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
4414 if (upper_policy
->session_order
!= lower_policy
->session_order
) {
4415 // A skip cannot override a policy of a different session
4418 if (upper_policy
->result_parameter
.skip_policy_order
== 0 ||
4419 lower_policy
->order
>= upper_policy
->result_parameter
.skip_policy_order
) {
4420 // This policy is beyond the skip
4423 // This policy is inside the skip
4429 // A hard pass, flow divert, tunnel, or scope will currently block out lower policies
4434 necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy
*policy
, struct necp_kernel_socket_policy
**policy_array
, int valid_indices
)
4436 bool can_skip
= FALSE
;
4437 u_int32_t highest_skip_session_order
= 0;
4438 u_int32_t highest_skip_order
= 0;
4440 for (i
= 0; i
< valid_indices
; i
++) {
4441 struct necp_kernel_socket_policy
*compared_policy
= policy_array
[i
];
4443 // For policies in a skip window, we can't mark conflicting policies as unnecessary
4445 if (highest_skip_session_order
!= compared_policy
->session_order
||
4446 (highest_skip_order
!= 0 && compared_policy
->order
>= highest_skip_order
)) {
4447 // If we've moved on to the next session, or passed the skip window
4448 highest_skip_session_order
= 0;
4449 highest_skip_order
= 0;
4452 // If this policy is also a skip, in can increase the skip window
4453 if (compared_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
4454 if (compared_policy
->result_parameter
.skip_policy_order
> highest_skip_order
) {
4455 highest_skip_order
= compared_policy
->result_parameter
.skip_policy_order
;
4462 if (compared_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
4463 // This policy is a skip. Set the skip window accordingly
4465 highest_skip_session_order
= compared_policy
->session_order
;
4466 highest_skip_order
= compared_policy
->result_parameter
.skip_policy_order
;
4469 // The result of the compared policy must be able to block out this policy result
4470 if (!necp_kernel_socket_policy_results_overlap(compared_policy
, policy
)) {
4474 // If new policy matches All Interfaces, compared policy must also
4475 if ((policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && !(compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) {
4479 // If new policy matches Local Networks, compared policy must also
4480 if ((policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) && !(compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
)) {
4484 // Default makes lower policies unecessary always
4485 if (compared_policy
->condition_mask
== 0) {
4489 // Compared must be more general than policy, and include only conditions within policy
4490 if ((policy
->condition_mask
& compared_policy
->condition_mask
) != compared_policy
->condition_mask
) {
4494 // Negative conditions must match for the overlapping conditions
4495 if ((policy
->condition_negated_mask
& compared_policy
->condition_mask
) != (compared_policy
->condition_negated_mask
& compared_policy
->condition_mask
)) {
4499 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
&&
4500 strcmp(compared_policy
->cond_domain
, policy
->cond_domain
) != 0) {
4504 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
&&
4505 strcmp(compared_policy
->cond_custom_entitlement
, policy
->cond_custom_entitlement
) != 0) {
4509 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
&&
4510 compared_policy
->cond_account_id
!= policy
->cond_account_id
) {
4514 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
&&
4515 compared_policy
->cond_policy_id
!= policy
->cond_policy_id
) {
4519 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
&&
4520 compared_policy
->cond_app_id
!= policy
->cond_app_id
) {
4524 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
&&
4525 compared_policy
->cond_real_app_id
!= policy
->cond_real_app_id
) {
4529 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_PID
&&
4530 compared_policy
->cond_pid
!= policy
->cond_pid
) {
4534 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_UID
&&
4535 compared_policy
->cond_uid
!= policy
->cond_uid
) {
4539 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
&&
4540 compared_policy
->cond_bound_interface
!= policy
->cond_bound_interface
) {
4544 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
&&
4545 compared_policy
->cond_protocol
!= policy
->cond_protocol
) {
4549 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_CLIENT_FLAGS
&&
4550 compared_policy
->cond_client_flags
!= policy
->cond_client_flags
) {
4554 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
&&
4555 !(compared_policy
->cond_traffic_class
.start_tc
<= policy
->cond_traffic_class
.start_tc
&&
4556 compared_policy
->cond_traffic_class
.end_tc
>= policy
->cond_traffic_class
.end_tc
)) {
4560 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
4561 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
4562 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
)) {
4565 } else if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
4566 if (compared_policy
->cond_local_prefix
> policy
->cond_local_prefix
||
4567 !necp_is_addr_in_subnet((struct sockaddr
*)&policy
->cond_local_start
, (struct sockaddr
*)&compared_policy
->cond_local_start
, compared_policy
->cond_local_prefix
)) {
4573 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
4574 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
4575 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
)) {
4578 } else if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
4579 if (compared_policy
->cond_remote_prefix
> policy
->cond_remote_prefix
||
4580 !necp_is_addr_in_subnet((struct sockaddr
*)&policy
->cond_remote_start
, (struct sockaddr
*)&compared_policy
->cond_remote_start
, compared_policy
->cond_remote_prefix
)) {
4586 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_AGENT_TYPE
&&
4587 memcmp(&compared_policy
->cond_agent_type
, &policy
->cond_agent_type
, sizeof(policy
->cond_agent_type
)) == 0) {
4591 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_SDK_VERSION
&&
4592 memcmp(&compared_policy
->cond_sdk_version
, &policy
->cond_sdk_version
, sizeof(policy
->cond_sdk_version
)) == 0) {
4596 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
&&
4597 memcmp(&compared_policy
->cond_packet_filter_tags
, &policy
->cond_packet_filter_tags
, sizeof(policy
->cond_packet_filter_tags
)) == 0) {
4608 necp_kernel_socket_policies_reprocess(void)
4611 int bucket_allocation_counts
[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
];
4612 int bucket_current_free_index
[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
];
4613 int app_layer_allocation_count
= 0;
4614 int app_layer_current_free_index
= 0;
4615 struct necp_kernel_socket_policy
*kernel_policy
= NULL
;
4617 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4620 necp_kernel_application_policies_condition_mask
= 0;
4621 necp_kernel_socket_policies_condition_mask
= 0;
4622 necp_kernel_application_policies_count
= 0;
4623 necp_kernel_socket_policies_count
= 0;
4624 necp_kernel_socket_policies_non_app_count
= 0;
4626 // Reset all maps to NULL
4627 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
4628 if (necp_kernel_socket_policies_map
[app_i
] != NULL
) {
4629 FREE(necp_kernel_socket_policies_map
[app_i
], M_NECP
);
4630 necp_kernel_socket_policies_map
[app_i
] = NULL
;
4634 bucket_allocation_counts
[app_i
] = 0;
4636 if (necp_kernel_socket_policies_app_layer_map
!= NULL
) {
4637 FREE(necp_kernel_socket_policies_app_layer_map
, M_NECP
);
4638 necp_kernel_socket_policies_app_layer_map
= NULL
;
4641 // Create masks and counts
4642 LIST_FOREACH(kernel_policy
, &necp_kernel_socket_policies
, chain
) {
4643 // App layer mask/count
4644 necp_kernel_application_policies_condition_mask
|= kernel_policy
->condition_mask
;
4645 necp_kernel_application_policies_count
++;
4646 app_layer_allocation_count
++;
4648 if ((kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_AGENT_TYPE
)) {
4649 // Agent type conditions only apply to app layer
4653 // Update socket layer bucket mask/counts
4654 necp_kernel_socket_policies_condition_mask
|= kernel_policy
->condition_mask
;
4655 necp_kernel_socket_policies_count
++;
4657 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) ||
4658 kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
4659 necp_kernel_socket_policies_non_app_count
++;
4660 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
4661 bucket_allocation_counts
[app_i
]++;
4664 bucket_allocation_counts
[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy
->cond_app_id
)]++;
4669 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
4670 if (bucket_allocation_counts
[app_i
] > 0) {
4671 // Allocate a NULL-terminated array of policy pointers for each bucket
4672 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
);
4673 if (necp_kernel_socket_policies_map
[app_i
] == NULL
) {
4677 // Initialize the first entry to NULL
4678 (necp_kernel_socket_policies_map
[app_i
])[0] = NULL
;
4680 bucket_current_free_index
[app_i
] = 0;
4682 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
);
4683 if (necp_kernel_socket_policies_app_layer_map
== NULL
) {
4686 necp_kernel_socket_policies_app_layer_map
[0] = NULL
;
4689 LIST_FOREACH(kernel_policy
, &necp_kernel_socket_policies
, chain
) {
4690 // Add app layer policies
4691 if (!necp_dedup_policies
|| !necp_kernel_socket_policy_is_unnecessary(kernel_policy
, necp_kernel_socket_policies_app_layer_map
, app_layer_current_free_index
)) {
4692 necp_kernel_socket_policies_app_layer_map
[app_layer_current_free_index
] = kernel_policy
;
4693 app_layer_current_free_index
++;
4694 necp_kernel_socket_policies_app_layer_map
[app_layer_current_free_index
] = NULL
;
4697 if ((kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_AGENT_TYPE
)) {
4698 // Agent type conditions only apply to app layer
4702 // Add socket policies
4703 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) ||
4704 kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
4705 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
4706 if (!necp_dedup_policies
|| !necp_kernel_socket_policy_is_unnecessary(kernel_policy
, necp_kernel_socket_policies_map
[app_i
], bucket_current_free_index
[app_i
])) {
4707 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = kernel_policy
;
4708 bucket_current_free_index
[app_i
]++;
4709 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = NULL
;
4713 app_i
= NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy
->cond_app_id
);
4714 if (!necp_dedup_policies
|| !necp_kernel_socket_policy_is_unnecessary(kernel_policy
, necp_kernel_socket_policies_map
[app_i
], bucket_current_free_index
[app_i
])) {
4715 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = kernel_policy
;
4716 bucket_current_free_index
[app_i
]++;
4717 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = NULL
;
4721 necp_kernel_socket_policies_dump_all();
4722 BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT();
4726 // Free memory, reset masks to 0
4727 necp_kernel_application_policies_condition_mask
= 0;
4728 necp_kernel_socket_policies_condition_mask
= 0;
4729 necp_kernel_application_policies_count
= 0;
4730 necp_kernel_socket_policies_count
= 0;
4731 necp_kernel_socket_policies_non_app_count
= 0;
4732 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
4733 if (necp_kernel_socket_policies_map
[app_i
] != NULL
) {
4734 FREE(necp_kernel_socket_policies_map
[app_i
], M_NECP
);
4735 necp_kernel_socket_policies_map
[app_i
] = NULL
;
4738 if (necp_kernel_socket_policies_app_layer_map
!= NULL
) {
4739 FREE(necp_kernel_socket_policies_app_layer_map
, M_NECP
);
4740 necp_kernel_socket_policies_app_layer_map
= NULL
;
4746 necp_get_new_string_id(void)
4748 static u_int32_t necp_last_string_id
= 0;
4750 u_int32_t newid
= 0;
4752 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4754 bool wrapped
= FALSE
;
4756 necp_last_string_id
++;
4757 if (necp_last_string_id
< 1) {
4759 // Already wrapped, give up
4760 NECPLOG0(LOG_ERR
, "Failed to find a free app UUID.\n");
4763 necp_last_string_id
= 1;
4766 newid
= necp_last_string_id
;
4767 } while (necp_lookup_string_with_id_locked(&necp_account_id_list
, newid
) != NULL
); // If already used, keep trying
4770 NECPLOG0(LOG_ERR
, "Allocate string id failed.\n");
4777 static struct necp_string_id_mapping
*
4778 necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list
*list
, char *string
)
4780 struct necp_string_id_mapping
*searchentry
= NULL
;
4781 struct necp_string_id_mapping
*foundentry
= NULL
;
4783 LIST_FOREACH(searchentry
, list
, chain
) {
4784 if (strcmp(searchentry
->string
, string
) == 0) {
4785 foundentry
= searchentry
;
4793 static struct necp_string_id_mapping
*
4794 necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list
*list
, u_int32_t local_id
)
4796 struct necp_string_id_mapping
*searchentry
= NULL
;
4797 struct necp_string_id_mapping
*foundentry
= NULL
;
4799 LIST_FOREACH(searchentry
, list
, chain
) {
4800 if (searchentry
->id
== local_id
) {
4801 foundentry
= searchentry
;
4810 necp_create_string_to_id_mapping(struct necp_string_id_mapping_list
*list
, char *string
)
4812 u_int32_t string_id
= 0;
4813 struct necp_string_id_mapping
*existing_mapping
= NULL
;
4815 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4817 existing_mapping
= necp_lookup_string_to_id_locked(list
, string
);
4818 if (existing_mapping
!= NULL
) {
4819 string_id
= existing_mapping
->id
;
4820 os_ref_retain_locked(&existing_mapping
->refcount
);
4822 struct necp_string_id_mapping
*new_mapping
= NULL
;
4823 MALLOC(new_mapping
, struct necp_string_id_mapping
*, sizeof(struct necp_string_id_mapping
), M_NECP
, M_WAITOK
);
4824 if (new_mapping
!= NULL
) {
4825 memset(new_mapping
, 0, sizeof(struct necp_string_id_mapping
));
4827 size_t length
= strlen(string
) + 1;
4828 MALLOC(new_mapping
->string
, char *, length
, M_NECP
, M_WAITOK
);
4829 if (new_mapping
->string
!= NULL
) {
4830 memcpy(new_mapping
->string
, string
, length
);
4831 new_mapping
->id
= necp_get_new_string_id();
4832 os_ref_init(&new_mapping
->refcount
, &necp_refgrp
);
4833 LIST_INSERT_HEAD(list
, new_mapping
, chain
);
4834 string_id
= new_mapping
->id
;
4836 FREE(new_mapping
, M_NECP
);
4845 necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list
*list
, char *string
)
4847 struct necp_string_id_mapping
*existing_mapping
= NULL
;
4849 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4851 existing_mapping
= necp_lookup_string_to_id_locked(list
, string
);
4852 if (existing_mapping
!= NULL
) {
4853 if (os_ref_release_locked(&existing_mapping
->refcount
) == 0) {
4854 LIST_REMOVE(existing_mapping
, chain
);
4855 FREE(existing_mapping
->string
, M_NECP
);
4856 FREE(existing_mapping
, M_NECP
);
4864 #define NECP_FIRST_VALID_ROUTE_RULE_ID 1
4865 #define NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID UINT16_MAX
4867 necp_get_new_route_rule_id(bool aggregate
)
4869 static u_int32_t necp_last_route_rule_id
= 0;
4870 static u_int32_t necp_last_aggregate_route_rule_id
= 0;
4872 u_int32_t newid
= 0;
4875 // Main necp_kernel_policy_lock protects non-aggregate rule IDs
4876 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4878 bool wrapped
= FALSE
;
4880 necp_last_route_rule_id
++;
4881 if (necp_last_route_rule_id
< NECP_FIRST_VALID_ROUTE_RULE_ID
||
4882 necp_last_route_rule_id
>= NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID
) {
4884 // Already wrapped, give up
4885 NECPLOG0(LOG_ERR
, "Failed to find a free route rule id.\n");
4888 necp_last_route_rule_id
= NECP_FIRST_VALID_ROUTE_RULE_ID
;
4891 newid
= necp_last_route_rule_id
;
4892 } while (necp_lookup_route_rule_locked(&necp_route_rules
, newid
) != NULL
); // If already used, keep trying
4894 // necp_route_rule_lock protects aggregate rule IDs
4895 LCK_RW_ASSERT(&necp_route_rule_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4897 bool wrapped
= FALSE
;
4899 necp_last_aggregate_route_rule_id
++;
4900 if (necp_last_aggregate_route_rule_id
< NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID
) {
4902 // Already wrapped, give up
4903 NECPLOG0(LOG_ERR
, "Failed to find a free aggregate route rule id.\n");
4906 necp_last_aggregate_route_rule_id
= NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID
;
4909 newid
= necp_last_aggregate_route_rule_id
;
4910 } while (necp_lookup_route_rule_locked(&necp_route_rules
, newid
) != NULL
); // If already used, keep trying
4914 NECPLOG0(LOG_ERR
, "Allocate route rule ID failed.\n");
4921 static struct necp_route_rule
*
4922 necp_lookup_route_rule_locked(struct necp_route_rule_list
*list
, u_int32_t route_rule_id
)
4924 struct necp_route_rule
*searchentry
= NULL
;
4925 struct necp_route_rule
*foundentry
= NULL
;
4927 LIST_FOREACH(searchentry
, list
, chain
) {
4928 if (searchentry
->id
== route_rule_id
) {
4929 foundentry
= searchentry
;
4937 static struct necp_route_rule
*
4938 necp_lookup_route_rule_by_contents_locked(struct necp_route_rule_list
*list
, u_int32_t default_action
, u_int8_t cellular_action
, u_int8_t wifi_action
, u_int8_t wired_action
, u_int8_t expensive_action
, u_int8_t constrained_action
, u_int32_t
*if_indices
, u_int8_t
*if_actions
)
4940 struct necp_route_rule
*searchentry
= NULL
;
4941 struct necp_route_rule
*foundentry
= NULL
;
4943 LIST_FOREACH(searchentry
, list
, chain
) {
4944 if (searchentry
->default_action
== default_action
&&
4945 searchentry
->cellular_action
== cellular_action
&&
4946 searchentry
->wifi_action
== wifi_action
&&
4947 searchentry
->wired_action
== wired_action
&&
4948 searchentry
->expensive_action
== expensive_action
&&
4949 searchentry
->constrained_action
== constrained_action
) {
4950 bool match_failed
= FALSE
;
4955 for (index_a
= 0; index_a
< MAX_ROUTE_RULE_INTERFACES
; index_a
++) {
4956 bool found_index
= FALSE
;
4957 if (searchentry
->exception_if_indices
[index_a
] == 0) {
4961 for (index_b
= 0; index_b
< MAX_ROUTE_RULE_INTERFACES
; index_b
++) {
4962 if (if_indices
[index_b
] == 0) {
4965 if (index_b
>= count_b
) {
4966 count_b
= index_b
+ 1;
4968 if (searchentry
->exception_if_indices
[index_a
] == if_indices
[index_b
] &&
4969 searchentry
->exception_if_actions
[index_a
] == if_actions
[index_b
]) {
4975 match_failed
= TRUE
;
4979 if (!match_failed
&& count_a
== count_b
) {
4980 foundentry
= searchentry
;
4990 necp_create_route_rule(struct necp_route_rule_list
*list
, u_int8_t
*route_rules_array
, u_int32_t route_rules_array_size
)
4993 u_int32_t route_rule_id
= 0;
4994 struct necp_route_rule
*existing_rule
= NULL
;
4995 u_int32_t default_action
= NECP_ROUTE_RULE_ALLOW_INTERFACE
;
4996 u_int8_t cellular_action
= NECP_ROUTE_RULE_NONE
;
4997 u_int8_t wifi_action
= NECP_ROUTE_RULE_NONE
;
4998 u_int8_t wired_action
= NECP_ROUTE_RULE_NONE
;
4999 u_int8_t expensive_action
= NECP_ROUTE_RULE_NONE
;
5000 u_int8_t constrained_action
= NECP_ROUTE_RULE_NONE
;
5001 u_int32_t if_indices
[MAX_ROUTE_RULE_INTERFACES
];
5002 size_t num_valid_indices
= 0;
5003 memset(&if_indices
, 0, sizeof(if_indices
));
5004 u_int8_t if_actions
[MAX_ROUTE_RULE_INTERFACES
];
5005 memset(&if_actions
, 0, sizeof(if_actions
));
5007 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
5009 if (route_rules_array
== NULL
|| route_rules_array_size
== 0) {
5014 while (offset
< route_rules_array_size
) {
5015 ifnet_t rule_interface
= NULL
;
5016 char interface_name
[IFXNAMSIZ
];
5017 u_int32_t length
= 0;
5018 u_int8_t
*value
= necp_buffer_get_tlv_value(route_rules_array
, offset
, &length
);
5020 u_int8_t rule_type
= necp_policy_condition_get_type_from_buffer(value
, length
);
5021 u_int8_t rule_flags
= necp_policy_condition_get_flags_from_buffer(value
, length
);
5022 u_int32_t rule_length
= necp_policy_condition_get_value_length_from_buffer(value
, length
);
5023 u_int8_t
*rule_value
= necp_policy_condition_get_value_pointer_from_buffer(value
, length
);
5025 if (rule_type
== NECP_ROUTE_RULE_NONE
) {
5026 // Don't allow an explicit rule to be None action
5030 if (rule_length
== 0) {
5031 if (rule_flags
& NECP_ROUTE_RULE_FLAG_CELLULAR
) {
5032 cellular_action
= rule_type
;
5034 if (rule_flags
& NECP_ROUTE_RULE_FLAG_WIFI
) {
5035 wifi_action
= rule_type
;
5037 if (rule_flags
& NECP_ROUTE_RULE_FLAG_WIRED
) {
5038 wired_action
= rule_type
;
5040 if (rule_flags
& NECP_ROUTE_RULE_FLAG_EXPENSIVE
) {
5041 expensive_action
= rule_type
;
5043 if (rule_flags
& NECP_ROUTE_RULE_FLAG_CONSTRAINED
) {
5044 constrained_action
= rule_type
;
5046 if (rule_flags
== 0) {
5047 default_action
= rule_type
;
5049 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
5053 if (num_valid_indices
>= MAX_ROUTE_RULE_INTERFACES
) {
5054 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
5058 if (rule_length
<= IFXNAMSIZ
) {
5059 memcpy(interface_name
, rule_value
, rule_length
);
5060 interface_name
[rule_length
- 1] = 0; // Make sure the string is NULL terminated
5061 if (ifnet_find_by_name(interface_name
, &rule_interface
) == 0) {
5062 if_actions
[num_valid_indices
] = rule_type
;
5063 if_indices
[num_valid_indices
++] = rule_interface
->if_index
;
5064 ifnet_release(rule_interface
);
5067 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
5070 existing_rule
= necp_lookup_route_rule_by_contents_locked(list
, default_action
, cellular_action
, wifi_action
, wired_action
, expensive_action
, constrained_action
, if_indices
, if_actions
);
5071 if (existing_rule
!= NULL
) {
5072 route_rule_id
= existing_rule
->id
;
5073 os_ref_retain_locked(&existing_rule
->refcount
);
5075 struct necp_route_rule
*new_rule
= NULL
;
5076 MALLOC(new_rule
, struct necp_route_rule
*, sizeof(struct necp_route_rule
), M_NECP
, M_WAITOK
);
5077 if (new_rule
!= NULL
) {
5078 memset(new_rule
, 0, sizeof(struct necp_route_rule
));
5079 route_rule_id
= new_rule
->id
= necp_get_new_route_rule_id(false);
5080 new_rule
->default_action
= default_action
;
5081 new_rule
->cellular_action
= cellular_action
;
5082 new_rule
->wifi_action
= wifi_action
;
5083 new_rule
->wired_action
= wired_action
;
5084 new_rule
->expensive_action
= expensive_action
;
5085 new_rule
->constrained_action
= constrained_action
;
5086 memcpy(&new_rule
->exception_if_indices
, &if_indices
, sizeof(if_indices
));
5087 memcpy(&new_rule
->exception_if_actions
, &if_actions
, sizeof(if_actions
));
5088 os_ref_init(&new_rule
->refcount
, &necp_refgrp
);
5089 LIST_INSERT_HEAD(list
, new_rule
, chain
);
5092 return route_rule_id
;
5096 necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id
)
5099 lck_rw_lock_exclusive(&necp_route_rule_lock
);
5101 struct necp_aggregate_route_rule
*existing_rule
= NULL
;
5102 struct necp_aggregate_route_rule
*tmp_rule
= NULL
;
5104 LIST_FOREACH_SAFE(existing_rule
, &necp_aggregate_route_rules
, chain
, tmp_rule
) {
5106 for (index
= 0; index
< MAX_AGGREGATE_ROUTE_RULES
; index
++) {
5107 u_int32_t route_rule_id
= existing_rule
->rule_ids
[index
];
5108 if (route_rule_id
== rule_id
) {
5109 LIST_REMOVE(existing_rule
, chain
);
5110 FREE(existing_rule
, M_NECP
);
5116 lck_rw_done(&necp_route_rule_lock
);
5121 necp_remove_route_rule(struct necp_route_rule_list
*list
, u_int32_t route_rule_id
)
5123 struct necp_route_rule
*existing_rule
= NULL
;
5125 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
5127 existing_rule
= necp_lookup_route_rule_locked(list
, route_rule_id
);
5128 if (existing_rule
!= NULL
) {
5129 if (os_ref_release_locked(&existing_rule
->refcount
) == 0) {
5130 necp_remove_aggregate_route_rule_for_id(existing_rule
->id
);
5131 LIST_REMOVE(existing_rule
, chain
);
5132 FREE(existing_rule
, M_NECP
);
5140 static struct necp_aggregate_route_rule
*
5141 necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id
)
5143 struct necp_aggregate_route_rule
*searchentry
= NULL
;
5144 struct necp_aggregate_route_rule
*foundentry
= NULL
;
5146 lck_rw_lock_shared(&necp_route_rule_lock
);
5148 LIST_FOREACH(searchentry
, &necp_aggregate_route_rules
, chain
) {
5149 if (searchentry
->id
== route_rule_id
) {
5150 foundentry
= searchentry
;
5155 lck_rw_done(&necp_route_rule_lock
);
5161 necp_create_aggregate_route_rule(u_int32_t
*rule_ids
)
5163 u_int32_t aggregate_route_rule_id
= 0;
5164 struct necp_aggregate_route_rule
*new_rule
= NULL
;
5165 struct necp_aggregate_route_rule
*existing_rule
= NULL
;
5167 lck_rw_lock_exclusive(&necp_route_rule_lock
);
5169 // Check if the rule already exists
5170 LIST_FOREACH(existing_rule
, &necp_aggregate_route_rules
, chain
) {
5171 if (memcmp(existing_rule
->rule_ids
, rule_ids
, (sizeof(u_int32_t
) * MAX_AGGREGATE_ROUTE_RULES
)) == 0) {
5172 lck_rw_done(&necp_route_rule_lock
);
5173 return existing_rule
->id
;
5177 MALLOC(new_rule
, struct necp_aggregate_route_rule
*, sizeof(struct necp_aggregate_route_rule
), M_NECP
, M_WAITOK
);
5178 if (new_rule
!= NULL
) {
5179 memset(new_rule
, 0, sizeof(struct necp_aggregate_route_rule
));
5180 aggregate_route_rule_id
= new_rule
->id
= necp_get_new_route_rule_id(true);
5181 new_rule
->id
= aggregate_route_rule_id
;
5182 memcpy(new_rule
->rule_ids
, rule_ids
, (sizeof(u_int32_t
) * MAX_AGGREGATE_ROUTE_RULES
));
5183 LIST_INSERT_HEAD(&necp_aggregate_route_rules
, new_rule
, chain
);
5185 lck_rw_done(&necp_route_rule_lock
);
5187 return aggregate_route_rule_id
;
5190 #define NECP_NULL_SERVICE_ID 1
5191 #define NECP_FIRST_VALID_SERVICE_ID 2
5192 #define NECP_FIRST_VALID_APP_ID UINT16_MAX
5194 necp_get_new_uuid_id(bool service
)
5196 static u_int32_t necp_last_service_uuid_id
= 0;
5197 static u_int32_t necp_last_app_uuid_id
= 0;
5199 u_int32_t newid
= 0;
5201 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
5204 bool wrapped
= FALSE
;
5206 necp_last_service_uuid_id
++;
5207 if (necp_last_service_uuid_id
< NECP_FIRST_VALID_SERVICE_ID
||
5208 necp_last_service_uuid_id
>= NECP_FIRST_VALID_APP_ID
) {
5210 // Already wrapped, give up
5211 NECPLOG0(LOG_ERR
, "Failed to find a free service UUID.\n");
5212 return NECP_NULL_SERVICE_ID
;
5214 necp_last_service_uuid_id
= NECP_FIRST_VALID_SERVICE_ID
;
5217 newid
= necp_last_service_uuid_id
;
5218 } while (necp_uuid_lookup_uuid_with_service_id_locked(newid
) != NULL
); // If already used, keep trying
5220 bool wrapped
= FALSE
;
5222 necp_last_app_uuid_id
++;
5223 if (necp_last_app_uuid_id
< NECP_FIRST_VALID_APP_ID
) {
5225 // Already wrapped, give up
5226 NECPLOG0(LOG_ERR
, "Failed to find a free app UUID.\n");
5227 return NECP_NULL_SERVICE_ID
;
5229 necp_last_app_uuid_id
= NECP_FIRST_VALID_APP_ID
;
5232 newid
= necp_last_app_uuid_id
;
5233 } while (necp_uuid_lookup_uuid_with_app_id_locked(newid
) != NULL
); // If already used, keep trying
5236 if (newid
== NECP_NULL_SERVICE_ID
) {
5237 NECPLOG0(LOG_ERR
, "Allocate uuid ID failed.\n");
5238 return NECP_NULL_SERVICE_ID
;
5244 static struct necp_uuid_id_mapping
*
5245 necp_uuid_lookup_app_id_locked(uuid_t uuid
)
5247 struct necp_uuid_id_mapping
*searchentry
= NULL
;
5248 struct necp_uuid_id_mapping
*foundentry
= NULL
;
5250 LIST_FOREACH(searchentry
, APPUUIDHASH(uuid
), chain
) {
5251 if (uuid_compare(searchentry
->uuid
, uuid
) == 0) {
5252 foundentry
= searchentry
;
5260 static struct necp_uuid_id_mapping
*
5261 necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id
)
5263 struct necp_uuid_id_mapping
*searchentry
= NULL
;
5264 struct necp_uuid_id_mapping
*foundentry
= NULL
;
5266 struct necp_uuid_id_mapping_head
*uuid_list_head
= NULL
;
5267 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
--) {
5268 LIST_FOREACH(searchentry
, uuid_list_head
, chain
) {
5269 if (searchentry
->id
== local_id
) {
5270 foundentry
= searchentry
;
5280 necp_create_uuid_app_id_mapping(uuid_t uuid
, bool *allocated_mapping
, bool uuid_policy_table
)
5282 u_int32_t local_id
= 0;
5283 struct necp_uuid_id_mapping
*existing_mapping
= NULL
;
5285 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
5287 if (allocated_mapping
) {
5288 *allocated_mapping
= FALSE
;
5291 existing_mapping
= necp_uuid_lookup_app_id_locked(uuid
);
5292 if (existing_mapping
!= NULL
) {
5293 local_id
= existing_mapping
->id
;
5294 os_ref_retain_locked(&existing_mapping
->refcount
);
5295 if (uuid_policy_table
) {
5296 existing_mapping
->table_usecount
++;
5299 struct necp_uuid_id_mapping
*new_mapping
= NULL
;
5300 MALLOC(new_mapping
, struct necp_uuid_id_mapping
*, sizeof(*new_mapping
), M_NECP
, M_WAITOK
);
5301 if (new_mapping
!= NULL
) {
5302 uuid_copy(new_mapping
->uuid
, uuid
);
5303 new_mapping
->id
= necp_get_new_uuid_id(false);
5304 os_ref_init(&new_mapping
->refcount
, &necp_refgrp
);
5305 if (uuid_policy_table
) {
5306 new_mapping
->table_usecount
= 1;
5308 new_mapping
->table_usecount
= 0;
5311 LIST_INSERT_HEAD(APPUUIDHASH(uuid
), new_mapping
, chain
);
5313 if (allocated_mapping
) {
5314 *allocated_mapping
= TRUE
;
5317 local_id
= new_mapping
->id
;
5325 necp_remove_uuid_app_id_mapping(uuid_t uuid
, bool *removed_mapping
, bool uuid_policy_table
)
5327 struct necp_uuid_id_mapping
*existing_mapping
= NULL
;
5329 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
5331 if (removed_mapping
) {
5332 *removed_mapping
= FALSE
;
5335 existing_mapping
= necp_uuid_lookup_app_id_locked(uuid
);
5336 if (existing_mapping
!= NULL
) {
5337 if (uuid_policy_table
) {
5338 existing_mapping
->table_usecount
--;
5340 if (os_ref_release_locked(&existing_mapping
->refcount
) == 0) {
5341 LIST_REMOVE(existing_mapping
, chain
);
5342 FREE(existing_mapping
, M_NECP
);
5343 if (removed_mapping
) {
5344 *removed_mapping
= TRUE
;
5353 static struct necp_uuid_id_mapping
*
5354 necp_uuid_get_null_service_id_mapping(void)
5356 static struct necp_uuid_id_mapping null_mapping
;
5357 uuid_clear(null_mapping
.uuid
);
5358 null_mapping
.id
= NECP_NULL_SERVICE_ID
;
5360 return &null_mapping
;
5363 static struct necp_uuid_id_mapping
*
5364 necp_uuid_lookup_service_id_locked(uuid_t uuid
)
5366 struct necp_uuid_id_mapping
*searchentry
= NULL
;
5367 struct necp_uuid_id_mapping
*foundentry
= NULL
;
5369 if (uuid_is_null(uuid
)) {
5370 return necp_uuid_get_null_service_id_mapping();
5373 LIST_FOREACH(searchentry
, &necp_uuid_service_id_list
, chain
) {
5374 if (uuid_compare(searchentry
->uuid
, uuid
) == 0) {
5375 foundentry
= searchentry
;
5383 static struct necp_uuid_id_mapping
*
5384 necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id
)
5386 struct necp_uuid_id_mapping
*searchentry
= NULL
;
5387 struct necp_uuid_id_mapping
*foundentry
= NULL
;
5389 if (local_id
== NECP_NULL_SERVICE_ID
) {
5390 return necp_uuid_get_null_service_id_mapping();
5393 LIST_FOREACH(searchentry
, &necp_uuid_service_id_list
, chain
) {
5394 if (searchentry
->id
== local_id
) {
5395 foundentry
= searchentry
;
5404 necp_create_uuid_service_id_mapping(uuid_t uuid
)
5406 u_int32_t local_id
= 0;
5407 struct necp_uuid_id_mapping
*existing_mapping
= NULL
;
5409 if (uuid_is_null(uuid
)) {
5410 return NECP_NULL_SERVICE_ID
;
5413 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
5415 existing_mapping
= necp_uuid_lookup_service_id_locked(uuid
);
5416 if (existing_mapping
!= NULL
) {
5417 local_id
= existing_mapping
->id
;
5418 os_ref_retain_locked(&existing_mapping
->refcount
);
5420 struct necp_uuid_id_mapping
*new_mapping
= NULL
;
5421 MALLOC(new_mapping
, struct necp_uuid_id_mapping
*, sizeof(*new_mapping
), M_NECP
, M_WAITOK
);
5422 if (new_mapping
!= NULL
) {
5423 uuid_copy(new_mapping
->uuid
, uuid
);
5424 new_mapping
->id
= necp_get_new_uuid_id(true);
5425 os_ref_init(&new_mapping
->refcount
, &necp_refgrp
);
5427 LIST_INSERT_HEAD(&necp_uuid_service_id_list
, new_mapping
, chain
);
5429 local_id
= new_mapping
->id
;
5437 necp_remove_uuid_service_id_mapping(uuid_t uuid
)
5439 struct necp_uuid_id_mapping
*existing_mapping
= NULL
;
5441 if (uuid_is_null(uuid
)) {
5445 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
5447 existing_mapping
= necp_uuid_lookup_service_id_locked(uuid
);
5448 if (existing_mapping
!= NULL
) {
5449 if (os_ref_release_locked(&existing_mapping
->refcount
) == 0) {
5450 LIST_REMOVE(existing_mapping
, chain
);
5451 FREE(existing_mapping
, M_NECP
);
5461 necp_kernel_socket_policies_update_uuid_table(void)
5463 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
5465 if (necp_uuid_app_id_mappings_dirty
) {
5466 if (proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_CLEAR
, NULL
, PROC_UUID_NECP_APP_POLICY
) < 0) {
5467 NECPLOG0(LOG_DEBUG
, "Error clearing uuids from policy table\n");
5471 if (necp_num_uuid_app_id_mappings
> 0) {
5472 struct necp_uuid_id_mapping_head
*uuid_list_head
= NULL
;
5473 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
--) {
5474 struct necp_uuid_id_mapping
*mapping
= NULL
;
5475 LIST_FOREACH(mapping
, uuid_list_head
, chain
) {
5476 if (mapping
->table_usecount
> 0 &&
5477 proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_ADD
, mapping
->uuid
, PROC_UUID_NECP_APP_POLICY
) < 0) {
5478 NECPLOG0(LOG_DEBUG
, "Error adding uuid to policy table\n");
5484 necp_uuid_app_id_mappings_dirty
= FALSE
;
5490 #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 | NECP_KERNEL_CONDITION_LOCAL_NETWORKS | NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS)
5491 static necp_kernel_policy_id
5492 necp_kernel_ip_output_policy_add(necp_policy_order order
, necp_policy_order suborder
, u_int32_t session_order
, int session_pid
, 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
, u_int16_t cond_packet_filter_tags
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
)
5494 struct necp_kernel_ip_output_policy
*new_kernel_policy
= NULL
;
5495 struct necp_kernel_ip_output_policy
*tmp_kernel_policy
= NULL
;
5497 new_kernel_policy
= zalloc_flags(necp_ip_policy_zone
, Z_WAITOK
| Z_ZERO
);
5498 new_kernel_policy
->id
= necp_kernel_policy_get_new_id(false);
5499 new_kernel_policy
->suborder
= suborder
;
5500 new_kernel_policy
->order
= order
;
5501 new_kernel_policy
->session_order
= session_order
;
5502 new_kernel_policy
->session_pid
= session_pid
;
5504 // Sanitize condition mask
5505 new_kernel_policy
->condition_mask
= (condition_mask
& NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS
);
5506 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
)) {
5507 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE
;
5509 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
)) {
5510 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX
;
5512 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
)) {
5513 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX
;
5515 new_kernel_policy
->condition_negated_mask
= condition_negated_mask
& new_kernel_policy
->condition_mask
;
5517 // Set condition values
5518 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
) {
5519 new_kernel_policy
->cond_policy_id
= cond_policy_id
;
5521 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
5522 if (cond_bound_interface
) {
5523 ifnet_reference(cond_bound_interface
);
5525 new_kernel_policy
->cond_bound_interface
= cond_bound_interface
;
5527 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LAST_INTERFACE
) {
5528 new_kernel_policy
->cond_last_interface_index
= cond_last_interface_index
;
5530 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
5531 new_kernel_policy
->cond_protocol
= cond_protocol
;
5533 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
5534 memcpy(&new_kernel_policy
->cond_local_start
, cond_local_start
, cond_local_start
->sa
.sa_len
);
5536 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
5537 memcpy(&new_kernel_policy
->cond_local_end
, cond_local_end
, cond_local_end
->sa
.sa_len
);
5539 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
5540 new_kernel_policy
->cond_local_prefix
= cond_local_prefix
;
5542 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
5543 memcpy(&new_kernel_policy
->cond_remote_start
, cond_remote_start
, cond_remote_start
->sa
.sa_len
);
5545 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
5546 memcpy(&new_kernel_policy
->cond_remote_end
, cond_remote_end
, cond_remote_end
->sa
.sa_len
);
5548 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
5549 new_kernel_policy
->cond_remote_prefix
= cond_remote_prefix
;
5551 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) {
5552 new_kernel_policy
->cond_packet_filter_tags
= cond_packet_filter_tags
;
5555 new_kernel_policy
->result
= result
;
5556 memcpy(&new_kernel_policy
->result_parameter
, &result_parameter
, sizeof(result_parameter
));
5559 NECPLOG(LOG_DEBUG
, "Added kernel policy: ip output, id=%d, mask=%x\n", new_kernel_policy
->id
, new_kernel_policy
->condition_mask
);
5561 LIST_INSERT_SORTED_THRICE_ASCENDING(&necp_kernel_ip_output_policies
, new_kernel_policy
, chain
, session_order
, order
, suborder
, tmp_kernel_policy
);
5563 return new_kernel_policy
? new_kernel_policy
->id
: 0;
5566 static struct necp_kernel_ip_output_policy
*
5567 necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id
)
5569 struct necp_kernel_ip_output_policy
*kernel_policy
= NULL
;
5570 struct necp_kernel_ip_output_policy
*tmp_kernel_policy
= NULL
;
5572 if (policy_id
== 0) {
5576 LIST_FOREACH_SAFE(kernel_policy
, &necp_kernel_ip_output_policies
, chain
, tmp_kernel_policy
) {
5577 if (kernel_policy
->id
== policy_id
) {
5578 return kernel_policy
;
5586 necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id
)
5588 struct necp_kernel_ip_output_policy
*policy
= NULL
;
5590 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
5592 policy
= necp_kernel_ip_output_policy_find(policy_id
);
5594 LIST_REMOVE(policy
, chain
);
5596 if (policy
->cond_bound_interface
) {
5597 ifnet_release(policy
->cond_bound_interface
);
5598 policy
->cond_bound_interface
= NULL
;
5601 zfree(necp_ip_policy_zone
, policy
);
5609 necp_kernel_ip_output_policies_dump_all(void)
5612 struct necp_kernel_ip_output_policy
*policy
= NULL
;
5615 char result_string
[MAX_RESULT_STRING_LEN
];
5616 char proc_name_string
[MAXCOMLEN
+ 1];
5617 memset(result_string
, 0, MAX_RESULT_STRING_LEN
);
5618 memset(proc_name_string
, 0, MAXCOMLEN
+ 1);
5620 NECPLOG0(LOG_DEBUG
, "NECP IP Output Policies:\n");
5621 NECPLOG0(LOG_DEBUG
, "-----------\n");
5622 for (id_i
= 0; id_i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; id_i
++) {
5623 NECPLOG(LOG_DEBUG
, " ID Bucket: %d\n", id_i
);
5624 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
++) {
5625 policy
= (necp_kernel_ip_output_policies_map
[id_i
])[policy_i
];
5626 proc_name(policy
->session_pid
, proc_name_string
, MAXCOMLEN
);
5627 NECPLOG(LOG_DEBUG
, "\t%3d. Policy ID: %5d\tProcess: %10.10s\tOrder: %04d.%04d.%d\tMask: %5x\tResult: %s\n", policy_i
, policy
->id
, proc_name_string
, policy
->session_order
, policy
->order
, policy
->suborder
, policy
->condition_mask
, necp_get_result_description(result_string
, policy
->result
, policy
->result_parameter
));
5629 NECPLOG0(LOG_DEBUG
, "-----------\n");
5635 necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy
*upper_policy
, struct necp_kernel_ip_output_policy
*lower_policy
)
5637 if (upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
5638 if (upper_policy
->session_order
!= lower_policy
->session_order
) {
5639 // A skip cannot override a policy of a different session
5642 if (upper_policy
->result_parameter
.skip_policy_order
== 0 ||
5643 lower_policy
->order
>= upper_policy
->result_parameter
.skip_policy_order
) {
5644 // This policy is beyond the skip
5647 // This policy is inside the skip
5653 // All other IP Output policy results (drop, tunnel, hard pass) currently overlap
5658 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
)
5660 bool can_skip
= FALSE
;
5661 u_int32_t highest_skip_session_order
= 0;
5662 u_int32_t highest_skip_order
= 0;
5664 for (i
= 0; i
< valid_indices
; i
++) {
5665 struct necp_kernel_ip_output_policy
*compared_policy
= policy_array
[i
];
5667 // For policies in a skip window, we can't mark conflicting policies as unnecessary
5669 if (highest_skip_session_order
!= compared_policy
->session_order
||
5670 (highest_skip_order
!= 0 && compared_policy
->order
>= highest_skip_order
)) {
5671 // If we've moved on to the next session, or passed the skip window
5672 highest_skip_session_order
= 0;
5673 highest_skip_order
= 0;
5676 // If this policy is also a skip, in can increase the skip window
5677 if (compared_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
5678 if (compared_policy
->result_parameter
.skip_policy_order
> highest_skip_order
) {
5679 highest_skip_order
= compared_policy
->result_parameter
.skip_policy_order
;
5686 if (compared_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
5687 // This policy is a skip. Set the skip window accordingly
5689 highest_skip_session_order
= compared_policy
->session_order
;
5690 highest_skip_order
= compared_policy
->result_parameter
.skip_policy_order
;
5693 // The result of the compared policy must be able to block out this policy result
5694 if (!necp_kernel_ip_output_policy_results_overlap(compared_policy
, policy
)) {
5698 // If new policy matches All Interfaces, compared policy must also
5699 if ((policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && !(compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) {
5703 // If new policy matches Local Networks, compared policy must also
5704 if ((policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) && !(compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
)) {
5708 // Default makes lower policies unecessary always
5709 if (compared_policy
->condition_mask
== 0) {
5713 // Compared must be more general than policy, and include only conditions within policy
5714 if ((policy
->condition_mask
& compared_policy
->condition_mask
) != compared_policy
->condition_mask
) {
5718 // Negative conditions must match for the overlapping conditions
5719 if ((policy
->condition_negated_mask
& compared_policy
->condition_mask
) != (compared_policy
->condition_negated_mask
& compared_policy
->condition_mask
)) {
5723 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
&&
5724 compared_policy
->cond_policy_id
!= policy
->cond_policy_id
) {
5728 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
&&
5729 compared_policy
->cond_bound_interface
!= policy
->cond_bound_interface
) {
5733 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
&&
5734 compared_policy
->cond_protocol
!= policy
->cond_protocol
) {
5738 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
5739 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
5740 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
)) {
5743 } else if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
5744 if (compared_policy
->cond_local_prefix
> policy
->cond_local_prefix
||
5745 !necp_is_addr_in_subnet((struct sockaddr
*)&policy
->cond_local_start
, (struct sockaddr
*)&compared_policy
->cond_local_start
, compared_policy
->cond_local_prefix
)) {
5751 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
5752 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
5753 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
)) {
5756 } else if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
5757 if (compared_policy
->cond_remote_prefix
> policy
->cond_remote_prefix
||
5758 !necp_is_addr_in_subnet((struct sockaddr
*)&policy
->cond_remote_start
, (struct sockaddr
*)&compared_policy
->cond_remote_start
, compared_policy
->cond_remote_prefix
)) {
5771 necp_kernel_ip_output_policies_reprocess(void)
5774 int bucket_allocation_counts
[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
];
5775 int bucket_current_free_index
[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
];
5776 struct necp_kernel_ip_output_policy
*kernel_policy
= NULL
;
5778 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
5781 necp_kernel_ip_output_policies_condition_mask
= 0;
5782 necp_kernel_ip_output_policies_count
= 0;
5783 necp_kernel_ip_output_policies_non_id_count
= 0;
5785 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
5786 if (necp_kernel_ip_output_policies_map
[i
] != NULL
) {
5787 FREE(necp_kernel_ip_output_policies_map
[i
], M_NECP
);
5788 necp_kernel_ip_output_policies_map
[i
] = NULL
;
5792 bucket_allocation_counts
[i
] = 0;
5795 LIST_FOREACH(kernel_policy
, &necp_kernel_ip_output_policies
, chain
) {
5797 necp_kernel_ip_output_policies_condition_mask
|= kernel_policy
->condition_mask
;
5798 necp_kernel_ip_output_policies_count
++;
5800 /* Update bucket counts:
5801 * Non-id and SKIP policies will be added to all buckets
5802 * Add local networks policy to all buckets for incoming IP
5804 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
) ||
5805 (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) ||
5806 kernel_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
5807 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
5808 bucket_allocation_counts
[i
]++;
5811 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
)) {
5812 necp_kernel_ip_output_policies_non_id_count
++;
5814 bucket_allocation_counts
[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy
->cond_policy_id
)]++;
5818 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
5819 if (bucket_allocation_counts
[i
] > 0) {
5820 // Allocate a NULL-terminated array of policy pointers for each bucket
5821 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
);
5822 if (necp_kernel_ip_output_policies_map
[i
] == NULL
) {
5826 // Initialize the first entry to NULL
5827 (necp_kernel_ip_output_policies_map
[i
])[0] = NULL
;
5829 bucket_current_free_index
[i
] = 0;
5832 LIST_FOREACH(kernel_policy
, &necp_kernel_ip_output_policies
, chain
) {
5833 // Insert pointers into map
5834 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
) ||
5835 (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) ||
5836 kernel_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
5837 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
5838 if (!necp_dedup_policies
|| !necp_kernel_ip_output_policy_is_unnecessary(kernel_policy
, necp_kernel_ip_output_policies_map
[i
], bucket_current_free_index
[i
])) {
5839 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = kernel_policy
;
5840 bucket_current_free_index
[i
]++;
5841 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = NULL
;
5845 i
= NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy
->cond_policy_id
);
5846 if (!necp_dedup_policies
|| !necp_kernel_ip_output_policy_is_unnecessary(kernel_policy
, necp_kernel_ip_output_policies_map
[i
], bucket_current_free_index
[i
])) {
5847 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = kernel_policy
;
5848 bucket_current_free_index
[i
]++;
5849 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = NULL
;
5853 necp_kernel_ip_output_policies_dump_all();
5857 // Free memory, reset mask to 0
5858 necp_kernel_ip_output_policies_condition_mask
= 0;
5859 necp_kernel_ip_output_policies_count
= 0;
5860 necp_kernel_ip_output_policies_non_id_count
= 0;
5861 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
5862 if (necp_kernel_ip_output_policies_map
[i
] != NULL
) {
5863 FREE(necp_kernel_ip_output_policies_map
[i
], M_NECP
);
5864 necp_kernel_ip_output_policies_map
[i
] = NULL
;
5870 // Outbound Policy Matching
5871 // ---------------------
5877 static struct substring
5878 necp_trim_dots_and_stars(char *string
, size_t length
)
5880 struct substring sub
;
5881 sub
.string
= string
;
5882 sub
.length
= string
? length
: 0;
5884 while (sub
.length
&& (sub
.string
[0] == '.' || sub
.string
[0] == '*')) {
5889 while (sub
.length
&& (sub
.string
[sub
.length
- 1] == '.' || sub
.string
[sub
.length
- 1] == '*')) {
5897 necp_create_trimmed_domain(char *string
, size_t length
)
5899 char *trimmed_domain
= NULL
;
5900 struct substring sub
= necp_trim_dots_and_stars(string
, length
);
5902 MALLOC(trimmed_domain
, char *, sub
.length
+ 1, M_NECP
, M_WAITOK
);
5903 if (trimmed_domain
== NULL
) {
5907 memcpy(trimmed_domain
, sub
.string
, sub
.length
);
5908 trimmed_domain
[sub
.length
] = 0;
5910 return trimmed_domain
;
5914 necp_count_dots(char *string
, size_t length
)
5919 for (i
= 0; i
< length
; i
++) {
5920 if (string
[i
] == '.') {
5929 necp_check_suffix(struct substring parent
, struct substring suffix
, bool require_dot_before_suffix
)
5931 if (parent
.length
<= suffix
.length
) {
5935 size_t length_difference
= (parent
.length
- suffix
.length
);
5937 if (require_dot_before_suffix
) {
5938 if (((char *)(parent
.string
+ length_difference
- 1))[0] != '.') {
5943 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
5944 return strncasecmp(parent
.string
+ length_difference
, suffix
.string
, suffix
.length
) == 0;
5948 necp_hostname_matches_domain(struct substring hostname_substring
, u_int8_t hostname_dot_count
, char *domain
, u_int8_t domain_dot_count
)
5950 if (hostname_substring
.string
== NULL
|| domain
== NULL
) {
5951 return hostname_substring
.string
== domain
;
5954 struct substring domain_substring
;
5955 domain_substring
.string
= domain
;
5956 domain_substring
.length
= strlen(domain
);
5958 if (hostname_dot_count
== domain_dot_count
) {
5959 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
5960 if (hostname_substring
.length
== domain_substring
.length
&&
5961 strncasecmp(hostname_substring
.string
, domain_substring
.string
, hostname_substring
.length
) == 0) {
5964 } else if (domain_dot_count
< hostname_dot_count
) {
5965 if (necp_check_suffix(hostname_substring
, domain_substring
, TRUE
)) {
5974 net_domain_contains_hostname(char *hostname_string
, char *domain_string
)
5976 if (hostname_string
== NULL
||
5977 domain_string
== NULL
) {
5981 struct substring hostname_substring
;
5982 hostname_substring
.string
= hostname_string
;
5983 hostname_substring
.length
= strlen(hostname_string
);
5985 return necp_hostname_matches_domain(hostname_substring
,
5986 necp_count_dots(hostname_string
, hostname_substring
.length
),
5988 necp_count_dots(domain_string
, strlen(domain_string
)));
5991 #define NECP_MAX_STRING_LEN 1024
5994 necp_copy_string(char *string
, size_t length
)
5996 char *copied_string
= NULL
;
5998 if (length
> NECP_MAX_STRING_LEN
) {
6002 MALLOC(copied_string
, char *, length
+ 1, M_NECP
, M_WAITOK
);
6003 if (copied_string
== NULL
) {
6007 memcpy(copied_string
, string
, length
);
6008 copied_string
[length
] = 0;
6010 return copied_string
;
6014 necp_get_primary_direct_interface_index(void)
6016 u_int32_t interface_index
= IFSCOPE_NONE
;
6018 ifnet_head_lock_shared();
6019 struct ifnet
*ordered_interface
= NULL
;
6020 TAILQ_FOREACH(ordered_interface
, &ifnet_ordered_head
, if_ordered_link
) {
6021 const u_int8_t functional_type
= if_functional_type(ordered_interface
, TRUE
);
6022 if (functional_type
!= IFRTYPE_FUNCTIONAL_UNKNOWN
&&
6023 functional_type
!= IFRTYPE_FUNCTIONAL_LOOPBACK
) {
6024 // All known, non-loopback functional types represent direct physical interfaces (Wi-Fi, Cellular, Wired)
6025 interface_index
= ordered_interface
->if_index
;
6031 return interface_index
;
6035 necp_get_parent_cred_result(proc_t proc
, struct necp_socket_info
*info
)
6037 task_t task
= proc_task(proc
? proc
: current_proc());
6038 coalition_t coal
= task_get_coalition(task
, COALITION_TYPE_JETSAM
);
6040 if (coal
== COALITION_NULL
|| coalition_is_leader(task
, coal
)) {
6041 // No parent, nothing to do
6045 task_t lead_task
= coalition_get_leader(coal
);
6046 if (lead_task
!= NULL
) {
6047 proc_t lead_proc
= get_bsdtask_info(lead_task
);
6048 if (lead_proc
!= NULL
) {
6049 kauth_cred_t lead_cred
= kauth_cred_proc_ref(lead_proc
);
6050 if (lead_cred
!= NULL
) {
6051 errno_t cred_result
= priv_check_cred(lead_cred
, PRIV_NET_PRIVILEGED_NECP_MATCH
, 0);
6052 kauth_cred_unref(&lead_cred
);
6053 info
->cred_result
= cred_result
;
6056 task_deallocate(lead_task
);
6060 // Some processes, due to particular entitlements, require using an NECP client to
6061 // access networking. Returns true if the result should be a Drop.
6063 necp_check_missing_client_drop(proc_t proc
, struct necp_socket_info
*info
)
6065 task_t task
= proc_task(proc
? proc
: current_proc());
6067 if (!info
->has_client
&&
6069 IOTaskHasEntitlement(task
, "com.apple.developer.on-demand-install-capable")) {
6070 // Drop connections that don't use NECP clients and have the
6071 // com.apple.developer.on-demand-install-capable entitlement.
6072 // This effectively restricts those processes to only using
6073 // an NECP-aware path for networking.
6081 necp_check_restricted_multicast_drop(proc_t proc
, struct necp_socket_info
*info
, bool check_minor_version
)
6083 if (!necp_restrict_multicast
|| proc
== NULL
) {
6087 // Check for multicast/broadcast here
6088 if (info
->remote_addr
.sa
.sa_family
== AF_INET
) {
6089 if (!IN_MULTICAST(ntohl(info
->remote_addr
.sin
.sin_addr
.s_addr
)) &&
6090 info
->remote_addr
.sin
.sin_addr
.s_addr
!= INADDR_BROADCAST
) {
6093 } else if (info
->remote_addr
.sa
.sa_family
== AF_INET6
) {
6094 if (!IN6_IS_ADDR_MULTICAST(&info
->remote_addr
.sin6
.sin6_addr
)) {
6102 if (necp_is_platform_binary(proc
)) {
6106 const uint32_t platform
= proc_platform(proc
);
6107 const uint32_t sdk
= proc_sdk(proc
);
6109 // Enforce for iOS, linked on or after version 14
6110 // If the caller set `check_minor_version`, only enforce starting at 14.TBD
6111 if (platform
!= PLATFORM_IOS
||
6115 (check_minor_version
&& (sdk
>> 16) == 14 && ((sdk
>> 8) & 0xff) < TBD
)) {
6117 (check_minor_version
)) {
6122 // Allow entitled processes to use multicast
6123 task_t task
= proc_task(proc
);
6125 IOTaskHasEntitlement(task
, "com.apple.developer.networking.multicast")) {
6129 const uint32_t min_sdk
= proc_min_sdk(proc
);
6130 NECPLOG(LOG_INFO
, "Dropping unentitled multicast (SDK 0x%x, min 0x%x)", sdk
, min_sdk
);
6135 #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 | NECP_KERNEL_CONDITION_LOCAL_EMPTY | NECP_KERNEL_CONDITION_REMOTE_EMPTY | NECP_KERNEL_CONDITION_LOCAL_NETWORKS)
6137 necp_application_fillout_info_locked(uuid_t application_uuid
, uuid_t real_application_uuid
, uuid_t responsible_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
, union necp_sockaddr_union
*local_addr
, union necp_sockaddr_union
*remote_addr
, u_int16_t local_port
, u_int16_t remote_port
, bool has_client
, proc_t proc
, proc_t responsible_proc
, u_int32_t drop_order
, u_int32_t client_flags
, struct necp_socket_info
*info
)
6139 memset(info
, 0, sizeof(struct necp_socket_info
));
6143 info
->protocol
= protocol
;
6144 info
->bound_interface_index
= bound_interface_index
;
6145 info
->traffic_class
= traffic_class
;
6146 info
->has_client
= has_client
;
6147 info
->drop_order
= drop_order
;
6148 info
->client_flags
= client_flags
;
6150 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_APP_ID
&& !uuid_is_null(application_uuid
)) {
6151 struct necp_uuid_id_mapping
*existing_mapping
= necp_uuid_lookup_app_id_locked(application_uuid
);
6152 if (existing_mapping
) {
6153 info
->application_id
= existing_mapping
->id
;
6157 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
&& !uuid_is_null(real_application_uuid
)) {
6158 if (uuid_compare(application_uuid
, real_application_uuid
) == 0) {
6159 info
->real_application_id
= info
->application_id
;
6161 struct necp_uuid_id_mapping
*existing_mapping
= necp_uuid_lookup_app_id_locked(real_application_uuid
);
6162 if (existing_mapping
) {
6163 info
->real_application_id
= existing_mapping
->id
;
6168 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_APP_ID
&& !uuid_is_null(responsible_application_uuid
)) {
6169 struct necp_uuid_id_mapping
*existing_mapping
= necp_uuid_lookup_app_id_locked(responsible_application_uuid
);
6170 if (existing_mapping
!= NULL
) {
6171 info
->real_application_id
= info
->application_id
;
6172 info
->application_id
= existing_mapping
->id
;
6173 info
->used_responsible_pid
= true;
6177 if (info
->used_responsible_pid
) {
6178 proc
= responsible_proc
;
6181 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
&& proc
!= NULL
) {
6182 info
->cred_result
= priv_check_cred(proc_ucred(proc
), PRIV_NET_PRIVILEGED_NECP_MATCH
, 0);
6183 if (info
->cred_result
!= 0) {
6184 // Process does not have entitlement, check the parent process
6185 necp_get_parent_cred_result(proc
, info
);
6189 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_PLATFORM_BINARY
&& proc
!= NULL
) {
6190 info
->is_platform_binary
= necp_is_platform_binary(proc
) ? true : false;
6193 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
&& account
!= NULL
) {
6194 struct necp_string_id_mapping
*existing_mapping
= necp_lookup_string_to_id_locked(&necp_account_id_list
, account
);
6195 if (existing_mapping
) {
6196 info
->account_id
= existing_mapping
->id
;
6200 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
6201 info
->domain
= domain
;
6204 if (necp_restrict_multicast
||
6205 (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_ADDRESS_TYPE_CONDITIONS
)) {
6206 if (local_addr
&& local_addr
->sa
.sa_len
> 0) {
6207 memcpy(&info
->local_addr
, local_addr
, local_addr
->sa
.sa_len
);
6208 if (local_port
!= 0) {
6209 info
->local_addr
.sin6
.sin6_port
= local_port
;
6211 } else if (local_port
!= 0) {
6212 info
->local_addr
.sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
6213 info
->local_addr
.sin6
.sin6_family
= AF_INET6
;
6214 info
->local_addr
.sin6
.sin6_port
= local_port
;
6216 if (remote_addr
&& remote_addr
->sa
.sa_len
> 0) {
6217 memcpy(&info
->remote_addr
, remote_addr
, remote_addr
->sa
.sa_len
);
6218 if (remote_port
!= 0) {
6219 info
->remote_addr
.sin6
.sin6_port
= remote_port
;
6221 } else if (remote_port
!= 0) {
6222 info
->remote_addr
.sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
6223 info
->remote_addr
.sin6
.sin6_family
= AF_INET6
;
6224 info
->remote_addr
.sin6
.sin6_port
= remote_port
;
6230 necp_send_application_interface_denied_event(pid_t pid
, uuid_t proc_uuid
, u_int32_t if_functional_type
)
6232 struct kev_netpolicy_ifdenied ev_ifdenied
;
6234 bzero(&ev_ifdenied
, sizeof(ev_ifdenied
));
6236 ev_ifdenied
.ev_data
.epid
= pid
;
6237 uuid_copy(ev_ifdenied
.ev_data
.euuid
, proc_uuid
);
6238 ev_ifdenied
.ev_if_functional_type
= if_functional_type
;
6240 netpolicy_post_msg(KEV_NETPOLICY_IFDENIED
, &ev_ifdenied
.ev_data
, sizeof(ev_ifdenied
));
6244 necp_send_network_denied_event(pid_t pid
, uuid_t proc_uuid
, u_int32_t network_type
)
6246 struct kev_netpolicy_netdenied ev_netdenied
= {};
6248 bzero(&ev_netdenied
, sizeof(ev_netdenied
));
6250 ev_netdenied
.ev_data
.epid
= pid
;
6251 uuid_copy(ev_netdenied
.ev_data
.euuid
, proc_uuid
);
6252 ev_netdenied
.ev_network_type
= network_type
;
6254 netpolicy_post_msg(KEV_NETPOLICY_NETDENIED
, &ev_netdenied
.ev_data
, sizeof(ev_netdenied
));
6257 extern char *proc_name_address(void *p
);
6259 #define NECP_VERIFY_DELEGATION_ENTITLEMENT(_p, _d) \
6260 if (!has_checked_delegation_entitlement) { \
6261 has_delegation_entitlement = (priv_check_cred(proc_ucred(_p), PRIV_NET_PRIVILEGED_SOCKET_DELEGATE, 0) == 0); \
6262 has_checked_delegation_entitlement = TRUE; \
6264 if (!has_delegation_entitlement) { \
6265 NECPLOG(LOG_ERR, "%s(%d) does not hold the necessary entitlement to delegate network traffic for other processes by %s", \
6266 proc_name_address(_p), proc_pid(_p), _d); \
6271 necp_application_find_policy_match_internal(proc_t proc
,
6272 u_int8_t
*parameters
,
6273 u_int32_t parameters_size
,
6274 struct necp_aggregate_result
*returned_result
,
6277 u_int required_interface_index
,
6278 const union necp_sockaddr_union
*override_local_addr
,
6279 const union necp_sockaddr_union
*override_remote_addr
,
6280 struct necp_client_endpoint
*returned_v4_gateway
,
6281 struct necp_client_endpoint
*returned_v6_gateway
,
6282 struct rtentry
**returned_route
, bool ignore_address
,
6284 uuid_t
*returned_override_euuid
)
6289 struct necp_kernel_socket_policy
*matched_policy
= NULL
;
6290 struct necp_socket_info info
;
6291 necp_kernel_policy_filter filter_control_unit
= 0;
6292 necp_kernel_policy_result service_action
= 0;
6293 necp_kernel_policy_service service
= { 0, 0 };
6295 u_int16_t protocol
= 0;
6296 u_int32_t bound_interface_index
= required_interface_index
;
6297 u_int32_t traffic_class
= 0;
6298 u_int32_t client_flags
= 0;
6299 union necp_sockaddr_union local_addr
;
6300 union necp_sockaddr_union remote_addr
;
6301 bool no_remote_addr
= FALSE
;
6302 u_int8_t remote_family
= 0;
6303 bool no_local_addr
= FALSE
;
6304 u_int16_t local_port
= 0;
6305 u_int16_t remote_port
= 0;
6306 necp_drop_all_bypass_check_result_t drop_all_bypass
= NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
;
6308 if (override_local_addr
) {
6309 memcpy(&local_addr
, override_local_addr
, sizeof(local_addr
));
6311 memset(&local_addr
, 0, sizeof(local_addr
));
6313 if (override_remote_addr
) {
6314 memcpy(&remote_addr
, override_remote_addr
, sizeof(remote_addr
));
6316 memset(&remote_addr
, 0, sizeof(remote_addr
));
6319 // Initialize UID, PID, and UUIDs to the current process
6320 uid_t uid
= kauth_cred_getuid(proc_ucred(proc
));
6321 pid_t pid
= proc_pid(proc
);
6322 uuid_t application_uuid
;
6323 uuid_clear(application_uuid
);
6324 uuid_t real_application_uuid
;
6325 uuid_clear(real_application_uuid
);
6326 proc_getexecutableuuid(proc
, real_application_uuid
, sizeof(real_application_uuid
));
6327 uuid_copy(application_uuid
, real_application_uuid
);
6328 uuid_t responsible_application_uuid
;
6329 uuid_clear(responsible_application_uuid
);
6331 char *domain
= NULL
;
6332 char *account
= NULL
;
6334 #define NECP_MAX_REQUIRED_AGENTS 16
6335 u_int32_t num_required_agent_types
= 0;
6336 struct necp_client_parameter_netagent_type required_agent_types
[NECP_MAX_REQUIRED_AGENTS
];
6337 memset(&required_agent_types
, 0, sizeof(required_agent_types
));
6339 u_int32_t netagent_ids
[NECP_MAX_NETAGENTS
];
6340 u_int32_t netagent_use_flags
[NECP_MAX_NETAGENTS
];
6341 memset(&netagent_ids
, 0, sizeof(netagent_ids
));
6342 memset(&netagent_use_flags
, 0, sizeof(netagent_use_flags
));
6343 int netagent_cursor
;
6345 bool has_checked_delegation_entitlement
= FALSE
;
6346 bool has_delegation_entitlement
= FALSE
;
6348 proc_t responsible_proc
= PROC_NULL
;
6349 proc_t effective_proc
= proc
;
6350 bool release_eproc
= false;
6352 u_int32_t flow_divert_aggregate_unit
= 0;
6354 if (returned_result
== NULL
) {
6358 if (returned_v4_gateway
!= NULL
) {
6359 memset(returned_v4_gateway
, 0, sizeof(struct necp_client_endpoint
));
6362 if (returned_v6_gateway
!= NULL
) {
6363 memset(returned_v6_gateway
, 0, sizeof(struct necp_client_endpoint
));
6366 if (returned_override_euuid
!= NULL
) {
6367 uuid_clear(*returned_override_euuid
);
6370 memset(returned_result
, 0, sizeof(struct necp_aggregate_result
));
6372 u_int32_t drop_order
= necp_process_drop_order(proc_ucred(proc
));
6374 necp_kernel_policy_result drop_dest_policy_result
= NECP_KERNEL_POLICY_RESULT_NONE
;
6376 lck_rw_lock_shared(&necp_kernel_policy_lock
);
6377 if (necp_kernel_application_policies_count
== 0) {
6378 if (necp_drop_all_order
> 0 || drop_order
> 0) {
6379 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6380 lck_rw_done(&necp_kernel_policy_lock
);
6384 lck_rw_done(&necp_kernel_policy_lock
);
6386 while ((offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)) <= parameters_size
) {
6387 u_int8_t type
= necp_buffer_get_tlv_type(parameters
, offset
);
6388 u_int32_t length
= necp_buffer_get_tlv_length(parameters
, offset
);
6390 if (length
> (parameters_size
- (offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)))) {
6391 // If the length is larger than what can fit in the remaining parameters size, bail
6392 NECPLOG(LOG_ERR
, "Invalid TLV length (%u)", length
);
6397 u_int8_t
*value
= necp_buffer_get_tlv_value(parameters
, offset
, NULL
);
6398 if (value
!= NULL
) {
6400 case NECP_CLIENT_PARAMETER_APPLICATION
: {
6401 if (length
>= sizeof(uuid_t
)) {
6402 if (uuid_compare(application_uuid
, value
) == 0) {
6407 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc
, "euuid");
6409 uuid_copy(application_uuid
, value
);
6413 case NECP_CLIENT_PARAMETER_REAL_APPLICATION
: {
6414 if (length
>= sizeof(uuid_t
)) {
6415 if (uuid_compare(real_application_uuid
, value
) == 0) {
6420 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc
, "uuid");
6422 uuid_copy(real_application_uuid
, value
);
6426 case NECP_CLIENT_PARAMETER_PID
: {
6427 if (length
>= sizeof(pid_t
)) {
6428 if (memcmp(&pid
, value
, sizeof(pid_t
)) == 0) {
6433 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc
, "pid");
6435 memcpy(&pid
, value
, sizeof(pid_t
));
6439 case NECP_CLIENT_PARAMETER_UID
: {
6440 if (length
>= sizeof(uid_t
)) {
6441 if (memcmp(&uid
, value
, sizeof(uid_t
)) == 0) {
6446 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc
, "uid");
6448 memcpy(&uid
, value
, sizeof(uid_t
));
6452 case NECP_CLIENT_PARAMETER_DOMAIN
: {
6453 domain
= (char *)value
;
6454 domain
[length
- 1] = 0;
6457 case NECP_CLIENT_PARAMETER_ACCOUNT
: {
6458 account
= (char *)value
;
6459 account
[length
- 1] = 0;
6462 case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS
: {
6463 if (length
>= sizeof(u_int32_t
)) {
6464 memcpy(&traffic_class
, value
, sizeof(u_int32_t
));
6468 case NECP_CLIENT_PARAMETER_IP_PROTOCOL
: {
6469 if (length
>= sizeof(u_int16_t
)) {
6470 memcpy(&protocol
, value
, sizeof(u_int16_t
));
6471 } else if (length
>= sizeof(u_int8_t
)) {
6472 memcpy(&protocol
, value
, sizeof(u_int8_t
));
6476 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE
: {
6477 if (length
<= IFXNAMSIZ
&& length
> 0) {
6478 ifnet_t bound_interface
= NULL
;
6479 char interface_name
[IFXNAMSIZ
];
6480 memcpy(interface_name
, value
, length
);
6481 interface_name
[length
- 1] = 0; // Make sure the string is NULL terminated
6482 if (ifnet_find_by_name(interface_name
, &bound_interface
) == 0) {
6483 bound_interface_index
= bound_interface
->if_index
;
6484 ifnet_release(bound_interface
);
6489 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS
: {
6490 if (ignore_address
|| override_local_addr
) {
6494 if (length
>= sizeof(struct necp_policy_condition_addr
)) {
6495 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)value
;
6496 if (necp_address_is_valid(&address_struct
->address
.sa
)) {
6497 memcpy(&local_addr
, &address_struct
->address
, sizeof(address_struct
->address
));
6502 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS
: {
6503 if (ignore_address
|| override_remote_addr
) {
6507 if (length
>= sizeof(struct necp_policy_condition_addr
)) {
6508 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)value
;
6509 if (necp_address_is_valid(&address_struct
->address
.sa
)) {
6510 memcpy(&remote_addr
, &address_struct
->address
, sizeof(address_struct
->address
));
6515 case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT
: {
6516 if (ignore_address
|| override_local_addr
) {
6520 if (length
>= sizeof(struct necp_client_endpoint
)) {
6521 struct necp_client_endpoint
*endpoint
= (struct necp_client_endpoint
*)(void *)value
;
6522 if (endpoint
->u
.endpoint
.endpoint_family
== AF_UNSPEC
&&
6523 endpoint
->u
.endpoint
.endpoint_port
!= 0) {
6525 local_port
= endpoint
->u
.endpoint
.endpoint_port
;
6530 case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT
: {
6531 if (ignore_address
|| override_remote_addr
) {
6535 if (length
>= sizeof(struct necp_client_endpoint
)) {
6536 struct necp_client_endpoint
*endpoint
= (struct necp_client_endpoint
*)(void *)value
;
6537 if (endpoint
->u
.endpoint
.endpoint_family
== AF_UNSPEC
&&
6538 endpoint
->u
.endpoint
.endpoint_port
!= 0) {
6540 remote_port
= endpoint
->u
.endpoint
.endpoint_port
;
6545 case NECP_CLIENT_PARAMETER_FLAGS
: {
6546 if (length
>= sizeof(client_flags
)) {
6547 memcpy(&client_flags
, value
, sizeof(client_flags
));
6551 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE
:
6552 case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE
: {
6553 if (num_required_agent_types
>= NECP_MAX_REQUIRED_AGENTS
) {
6556 if (length
>= sizeof(struct necp_client_parameter_netagent_type
)) {
6557 memcpy(&required_agent_types
[num_required_agent_types
], value
, sizeof(struct necp_client_parameter_netagent_type
));
6558 num_required_agent_types
++;
6569 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
6572 // Check for loopback exception
6573 if (necp_pass_loopback
> 0 && necp_is_loopback(&local_addr
.sa
, &remote_addr
.sa
, NULL
, NULL
, bound_interface_index
)) {
6574 returned_result
->policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6575 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_PASS
;
6576 returned_result
->routed_interface_index
= lo_ifp
->if_index
;
6577 *flags
|= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL
| NECP_CLIENT_RESULT_FLAG_IS_DIRECT
);
6581 if (proc_pid(effective_proc
) != pid
) {
6582 proc_t found_proc
= proc_find(pid
);
6583 if (found_proc
!= PROC_NULL
) {
6584 effective_proc
= found_proc
;
6585 release_eproc
= true;
6588 #if defined(XNU_TARGET_OS_OSX)
6589 if (effective_proc
->p_responsible_pid
> 0 && effective_proc
->p_responsible_pid
!= pid
) {
6590 responsible_proc
= proc_find(effective_proc
->p_responsible_pid
);
6591 if (responsible_proc
!= PROC_NULL
) {
6592 proc_getexecutableuuid(responsible_proc
, responsible_application_uuid
, sizeof(responsible_application_uuid
));
6595 #endif /* defined(XNU_TARGET_OS_OSX) */
6598 lck_rw_lock_shared(&necp_kernel_policy_lock
);
6600 u_int32_t route_rule_id_array
[MAX_AGGREGATE_ROUTE_RULES
];
6601 size_t route_rule_id_array_count
= 0;
6602 necp_application_fillout_info_locked(application_uuid
, real_application_uuid
, responsible_application_uuid
, account
, domain
, pid
, uid
, protocol
, bound_interface_index
, traffic_class
, &local_addr
, &remote_addr
, local_port
, remote_port
, has_client
, effective_proc
, responsible_proc
, drop_order
, client_flags
, &info
);
6603 matched_policy
= necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_app_layer_map
, &info
, &filter_control_unit
, route_rule_id_array
, &route_rule_id_array_count
, MAX_AGGREGATE_ROUTE_RULES
, &service_action
, &service
, netagent_ids
, netagent_use_flags
, NECP_MAX_NETAGENTS
, required_agent_types
, num_required_agent_types
, info
.used_responsible_pid
? responsible_proc
: effective_proc
, 0, NULL
, NULL
, &drop_dest_policy_result
, &drop_all_bypass
, &flow_divert_aggregate_unit
);
6604 if (matched_policy
) {
6605 returned_result
->policy_id
= matched_policy
->id
;
6606 returned_result
->routing_result
= matched_policy
->result
;
6607 memcpy(&returned_result
->routing_result_parameter
, &matched_policy
->result_parameter
, sizeof(returned_result
->routing_result_parameter
));
6608 if (returned_override_euuid
!= NULL
&& info
.used_responsible_pid
&& !(matched_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
)) {
6609 uuid_copy(*returned_override_euuid
, responsible_application_uuid
);
6612 bool drop_all
= false;
6613 if (necp_drop_all_order
> 0 || info
.drop_order
> 0 || drop_dest_policy_result
== NECP_KERNEL_POLICY_RESULT_DROP
) {
6614 // Mark socket as a drop if drop_all is set
6616 if (drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
) {
6617 drop_all_bypass
= necp_check_drop_all_bypass_result(proc
);
6620 if (drop_all
&& drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
) {
6621 returned_result
->policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6622 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6624 returned_result
->policy_id
= 0;
6625 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_NONE
;
6628 if (necp_check_missing_client_drop(proc
, &info
) ||
6629 necp_check_restricted_multicast_drop(proc
, &info
, false)) {
6631 returned_result
->policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6632 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6634 if (filter_control_unit
== NECP_FILTER_UNIT_NO_FILTER
) {
6635 returned_result
->filter_control_unit
= 0;
6637 returned_result
->filter_control_unit
= filter_control_unit
;
6640 if (flow_divert_aggregate_unit
> 0) {
6641 returned_result
->flow_divert_aggregate_unit
= flow_divert_aggregate_unit
;
6644 returned_result
->service_action
= service_action
;
6646 // Handle trigger service
6647 if (service
.identifier
!= 0) {
6648 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(service
.identifier
);
6649 if (mapping
!= NULL
) {
6650 struct necp_service_registration
*service_registration
= NULL
;
6651 uuid_copy(returned_result
->service_uuid
, mapping
->uuid
);
6652 returned_result
->service_data
= service
.data
;
6653 if (service
.identifier
== NECP_NULL_SERVICE_ID
) {
6654 // NULL service is always 'registered'
6655 returned_result
->service_flags
|= NECP_SERVICE_FLAGS_REGISTERED
;
6657 LIST_FOREACH(service_registration
, &necp_registered_service_list
, kernel_chain
) {
6658 if (service
.identifier
== service_registration
->service_id
) {
6659 returned_result
->service_flags
|= NECP_SERVICE_FLAGS_REGISTERED
;
6668 for (netagent_cursor
= 0; netagent_cursor
< NECP_MAX_NETAGENTS
; netagent_cursor
++) {
6669 struct necp_uuid_id_mapping
*mapping
= NULL
;
6670 u_int32_t netagent_id
= netagent_ids
[netagent_cursor
];
6671 if (netagent_id
== 0) {
6674 mapping
= necp_uuid_lookup_uuid_with_service_id_locked(netagent_id
);
6675 if (mapping
!= NULL
) {
6676 uuid_copy(returned_result
->netagents
[netagent_cursor
], mapping
->uuid
);
6677 returned_result
->netagent_use_flags
[netagent_cursor
] = netagent_use_flags
[netagent_cursor
];
6681 // Do routing evaluation
6682 u_int output_bound_interface
= bound_interface_index
;
6683 if (returned_result
->routing_result
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
) {
6684 output_bound_interface
= returned_result
->routing_result_parameter
.scoped_interface_index
;
6685 } else if (returned_result
->routing_result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
) {
6686 output_bound_interface
= returned_result
->routing_result_parameter
.tunnel_interface_index
;
6687 } else if (returned_result
->routing_result
== NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT
) {
6688 output_bound_interface
= necp_get_primary_direct_interface_index();
6689 if (output_bound_interface
== IFSCOPE_NONE
) {
6690 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6692 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
;
6693 returned_result
->routing_result_parameter
.scoped_interface_index
= output_bound_interface
;
6697 if (returned_result
->routing_result
== NECP_KERNEL_POLICY_RESULT_DROP
&&
6698 returned_result
->routing_result_parameter
.drop_flags
& NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK
) {
6699 // Trigger the event that we dropped due to a local network policy
6700 necp_send_network_denied_event(pid
, application_uuid
, NETPOLICY_NETWORKTYPE_LOCAL
);
6701 if (reason
!= NULL
) {
6702 *reason
= NECP_CLIENT_RESULT_REASON_LOCAL_NETWORK_PROHIBITED
;
6706 if (local_addr
.sa
.sa_len
== 0 ||
6707 (local_addr
.sa
.sa_family
== AF_INET
&& local_addr
.sin
.sin_addr
.s_addr
== 0) ||
6708 (local_addr
.sa
.sa_family
== AF_INET6
&& IN6_IS_ADDR_UNSPECIFIED(&local_addr
.sin6
.sin6_addr
))) {
6709 no_local_addr
= TRUE
;
6712 if (remote_addr
.sa
.sa_len
== 0 ||
6713 (remote_addr
.sa
.sa_family
== AF_INET
&& remote_addr
.sin
.sin_addr
.s_addr
== 0) ||
6714 (remote_addr
.sa
.sa_family
== AF_INET6
&& IN6_IS_ADDR_UNSPECIFIED(&remote_addr
.sin6
.sin6_addr
))) {
6715 no_remote_addr
= TRUE
;
6716 remote_family
= remote_addr
.sa
.sa_family
;
6719 returned_result
->routed_interface_index
= 0;
6720 struct rtentry
*rt
= NULL
;
6721 if (!no_local_addr
&& (client_flags
& NECP_CLIENT_PARAMETER_FLAG_LISTENER
) != 0) {
6722 // Treat the output bound interface as the routed interface for local address
6723 // validation later.
6724 returned_result
->routed_interface_index
= output_bound_interface
;
6726 if (no_remote_addr
) {
6727 memset(&remote_addr
, 0, sizeof(remote_addr
));
6728 if (remote_family
== AF_INET6
) {
6729 // Reset address to ::
6730 remote_addr
.sa
.sa_family
= AF_INET6
;
6731 remote_addr
.sa
.sa_len
= sizeof(struct sockaddr_in6
);
6733 // Reset address to 0.0.0.0
6734 remote_addr
.sa
.sa_family
= AF_INET
;
6735 remote_addr
.sa
.sa_len
= sizeof(struct sockaddr_in
);
6739 rt
= rtalloc1_scoped((struct sockaddr
*)&remote_addr
, 0, 0,
6740 output_bound_interface
);
6742 if (remote_addr
.sa
.sa_family
== AF_INET
&& rt
!= NULL
&&
6743 IS_INTF_CLAT46(rt
->rt_ifp
)) {
6746 returned_result
->routed_interface_index
= 0;
6749 if (no_remote_addr
&& remote_family
== AF_UNSPEC
&&
6750 (rt
== NULL
|| rt
->rt_ifp
== NULL
)) {
6751 // Route lookup for default IPv4 failed, try IPv6
6753 // Cleanup old route if necessary
6759 // Reset address to ::
6760 memset(&remote_addr
, 0, sizeof(remote_addr
));
6761 remote_addr
.sa
.sa_family
= AF_INET6
;
6762 remote_addr
.sa
.sa_len
= sizeof(struct sockaddr_in6
);
6765 rt
= rtalloc1_scoped((struct sockaddr
*)&remote_addr
, 0, 0,
6766 output_bound_interface
);
6770 rt
->rt_ifp
!= NULL
) {
6771 returned_result
->routed_interface_index
= rt
->rt_ifp
->if_index
;
6773 * For local addresses, we allow the interface scope to be
6774 * either the loopback interface or the interface hosting the
6777 if (bound_interface_index
!= IFSCOPE_NONE
&&
6778 rt
->rt_ifa
!= NULL
&& rt
->rt_ifa
->ifa_ifp
&&
6779 (output_bound_interface
== lo_ifp
->if_index
||
6780 rt
->rt_ifp
->if_index
== lo_ifp
->if_index
||
6781 rt
->rt_ifa
->ifa_ifp
->if_index
== bound_interface_index
)) {
6782 struct sockaddr_storage dst
;
6783 unsigned int ifscope
= bound_interface_index
;
6786 * Transform dst into the internal routing table form
6788 (void) sa_copy((struct sockaddr
*)&remote_addr
,
6791 if ((rt
->rt_ifp
->if_index
== lo_ifp
->if_index
) ||
6792 rt_ifa_is_dst((struct sockaddr
*)&dst
, rt
->rt_ifa
)) {
6793 returned_result
->routed_interface_index
=
6794 bound_interface_index
;
6800 if (returned_result
->routed_interface_index
!= 0 &&
6801 returned_result
->routed_interface_index
!= lo_ifp
->if_index
&& // Loopback can accept any local address
6803 // Transform local_addr into the ifaddr form
6804 // IPv6 Scope IDs are always embedded in the ifaddr list
6805 struct sockaddr_storage local_address_sanitized
;
6806 u_int ifscope
= IFSCOPE_NONE
;
6807 (void)sa_copy(&local_addr
.sa
, &local_address_sanitized
, &ifscope
);
6808 SIN(&local_address_sanitized
)->sin_port
= 0;
6809 if (local_address_sanitized
.ss_family
== AF_INET6
) {
6810 SIN6(&local_address_sanitized
)->sin6_scope_id
= 0;
6813 // Validate local address on routed interface
6814 struct ifaddr
*ifa
= ifa_ifwithaddr_scoped((struct sockaddr
*)&local_address_sanitized
, returned_result
->routed_interface_index
);
6816 // Interface address not found, reject route
6817 returned_result
->routed_interface_index
= 0;
6823 ifaddr_release(ifa
);
6828 if (flags
!= NULL
) {
6829 if ((client_flags
& NECP_CLIENT_PARAMETER_FLAG_LISTENER
) == 0) {
6830 // Check for local/direct
6831 bool is_local
= FALSE
;
6832 if (rt
!= NULL
&& (rt
->rt_flags
& RTF_LOCAL
)) {
6834 } else if (returned_result
->routed_interface_index
!= 0 &&
6836 // Clean up the address before comparison with interface addresses
6838 // Transform remote_addr into the ifaddr form
6839 // IPv6 Scope IDs are always embedded in the ifaddr list
6840 struct sockaddr_storage remote_address_sanitized
;
6841 u_int ifscope
= IFSCOPE_NONE
;
6842 (void)sa_copy(&remote_addr
.sa
, &remote_address_sanitized
, &ifscope
);
6843 SIN(&remote_address_sanitized
)->sin_port
= 0;
6844 if (remote_address_sanitized
.ss_family
== AF_INET6
) {
6845 SIN6(&remote_address_sanitized
)->sin6_scope_id
= 0;
6848 // Check if remote address is an interface address
6849 struct ifaddr
*ifa
= ifa_ifwithaddr((struct sockaddr
*)&remote_address_sanitized
);
6850 if (ifa
!= NULL
&& ifa
->ifa_ifp
!= NULL
) {
6851 u_int if_index_for_remote_addr
= ifa
->ifa_ifp
->if_index
;
6852 if (if_index_for_remote_addr
== returned_result
->routed_interface_index
||
6853 if_index_for_remote_addr
== lo_ifp
->if_index
) {
6858 ifaddr_release(ifa
);
6864 *flags
|= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL
| NECP_CLIENT_RESULT_FLAG_IS_DIRECT
);
6867 !(rt
->rt_flags
& RTF_GATEWAY
) &&
6868 (rt
->rt_ifa
&& rt
->rt_ifa
->ifa_ifp
&& !(rt
->rt_ifa
->ifa_ifp
->if_flags
& IFF_POINTOPOINT
))) {
6869 // Route is directly accessible
6870 *flags
|= NECP_CLIENT_RESULT_FLAG_IS_DIRECT
;
6875 rt
->rt_ifp
!= NULL
) {
6876 // Check probe status
6877 if (rt
->rt_ifp
->if_eflags
& IFEF_PROBE_CONNECTIVITY
) {
6878 *flags
|= NECP_CLIENT_RESULT_FLAG_PROBE_CONNECTIVITY
;
6881 if (rt
->rt_ifp
->if_type
== IFT_CELLULAR
) {
6882 struct if_cellular_status_v1
*ifsr
;
6884 ifnet_lock_shared(rt
->rt_ifp
);
6885 lck_rw_lock_exclusive(&rt
->rt_ifp
->if_link_status_lock
);
6887 if (rt
->rt_ifp
->if_link_status
!= NULL
) {
6888 ifsr
= &rt
->rt_ifp
->if_link_status
->ifsr_u
.ifsr_cell
.if_cell_u
.if_status_v1
;
6890 if (ifsr
->valid_bitmask
& IF_CELL_UL_MSS_RECOMMENDED_VALID
) {
6891 if (ifsr
->mss_recommended
== IF_CELL_UL_MSS_RECOMMENDED_NONE
) {
6892 returned_result
->mss_recommended
= NECP_CLIENT_RESULT_RECOMMENDED_MSS_NONE
;
6893 } else if (ifsr
->mss_recommended
== IF_CELL_UL_MSS_RECOMMENDED_MEDIUM
) {
6894 returned_result
->mss_recommended
= NECP_CLIENT_RESULT_RECOMMENDED_MSS_MEDIUM
;
6895 } else if (ifsr
->mss_recommended
== IF_CELL_UL_MSS_RECOMMENDED_LOW
) {
6896 returned_result
->mss_recommended
= NECP_CLIENT_RESULT_RECOMMENDED_MSS_LOW
;
6900 lck_rw_done(&rt
->rt_ifp
->if_link_status_lock
);
6901 ifnet_lock_done(rt
->rt_ifp
);
6904 // Check link quality
6905 if ((client_flags
& NECP_CLIENT_PARAMETER_FLAG_DISCRETIONARY
) &&
6906 (rt
->rt_ifp
->if_interface_state
.valid_bitmask
& IF_INTERFACE_STATE_LQM_STATE_VALID
) &&
6907 rt
->rt_ifp
->if_interface_state
.lqm_state
== IFNET_LQM_THRESH_ABORT
) {
6908 *flags
|= NECP_CLIENT_RESULT_FLAG_LINK_QUALITY_ABORT
;
6911 // Check QoS marking (fastlane)
6912 for (size_t route_rule_index
= 0; route_rule_index
< route_rule_id_array_count
; route_rule_index
++) {
6913 if (necp_update_qos_marking(rt
->rt_ifp
, route_rule_id_array
[route_rule_index
])) {
6914 *flags
|= NECP_CLIENT_RESULT_FLAG_ALLOW_QOS_MARKING
;
6915 // If the route can use QoS markings, stop iterating route rules
6920 if (IFNET_IS_LOW_POWER(rt
->rt_ifp
)) {
6921 *flags
|= NECP_CLIENT_RESULT_FLAG_INTERFACE_LOW_POWER
;
6924 if (traffic_class
== SO_TC_BK_SYS
) {
6925 // Block BK_SYS traffic if interface is throttled
6926 u_int32_t throttle_level
= 0;
6927 if (ifnet_get_throttle(rt
->rt_ifp
, &throttle_level
) == 0) {
6928 if (throttle_level
== IFNET_THROTTLE_OPPORTUNISTIC
) {
6929 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6930 memset(&returned_result
->routing_result_parameter
, 0, sizeof(returned_result
->routing_result_parameter
));
6937 if (returned_result
->routed_interface_index
!= 0) {
6938 union necp_sockaddr_union default_address
;
6939 struct rtentry
*v4Route
= NULL
;
6940 struct rtentry
*v6Route
= NULL
;
6942 memset(&default_address
, 0, sizeof(default_address
));
6944 // Reset address to 0.0.0.0
6945 default_address
.sa
.sa_family
= AF_INET
;
6946 default_address
.sa
.sa_len
= sizeof(struct sockaddr_in
);
6947 v4Route
= rtalloc1_scoped((struct sockaddr
*)&default_address
, 0, 0,
6948 returned_result
->routed_interface_index
);
6950 // Reset address to ::
6951 default_address
.sa
.sa_family
= AF_INET6
;
6952 default_address
.sa
.sa_len
= sizeof(struct sockaddr_in6
);
6953 v6Route
= rtalloc1_scoped((struct sockaddr
*)&default_address
, 0, 0,
6954 returned_result
->routed_interface_index
);
6956 if (v4Route
!= NULL
) {
6957 if (v4Route
->rt_ifp
!= NULL
&& !IS_INTF_CLAT46(v4Route
->rt_ifp
)) {
6958 *flags
|= NECP_CLIENT_RESULT_FLAG_HAS_IPV4
;
6960 if (returned_v4_gateway
!= NULL
&&
6961 v4Route
->rt_gateway
!= NULL
&&
6962 v4Route
->rt_gateway
->sa_len
== sizeof(returned_v4_gateway
->u
.sin
)) {
6963 memcpy(&returned_v4_gateway
->u
.sin
, v4Route
->rt_gateway
, sizeof(returned_v4_gateway
->u
.sin
));
6964 memset(&returned_v4_gateway
->u
.sin
.sin_zero
, 0, sizeof(returned_v4_gateway
->u
.sin
.sin_zero
));
6970 if (v6Route
!= NULL
) {
6971 if (v6Route
->rt_ifp
!= NULL
) {
6972 *flags
|= NECP_CLIENT_RESULT_FLAG_HAS_IPV6
;
6974 if (ifnet_get_nat64prefix(v6Route
->rt_ifp
, NULL
) == 0) {
6975 *flags
|= NECP_CLIENT_RESULT_FLAG_HAS_NAT64
;
6978 if (returned_v6_gateway
!= NULL
&&
6979 v6Route
->rt_gateway
!= NULL
&&
6980 v6Route
->rt_gateway
->sa_len
== sizeof(returned_v6_gateway
->u
.sin6
)) {
6981 memcpy(&returned_v6_gateway
->u
.sin6
, v6Route
->rt_gateway
, sizeof(returned_v6_gateway
->u
.sin6
));
6989 for (size_t route_rule_index
= 0; route_rule_index
< route_rule_id_array_count
; route_rule_index
++) {
6990 u_int32_t interface_type_denied
= IFRTYPE_FUNCTIONAL_UNKNOWN
;
6991 bool route_is_allowed
= necp_route_is_allowed(rt
, NULL
, route_rule_id_array
[route_rule_index
], &interface_type_denied
);
6992 if (!route_is_allowed
) {
6993 // If the route is blocked, treat the lookup as a drop
6994 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6995 memset(&returned_result
->routing_result_parameter
, 0, sizeof(returned_result
->routing_result_parameter
));
6997 if (interface_type_denied
!= IFRTYPE_FUNCTIONAL_UNKNOWN
) {
6998 if (reason
!= NULL
) {
6999 if (interface_type_denied
== IFRTYPE_FUNCTIONAL_CELLULAR
) {
7000 *reason
= NECP_CLIENT_RESULT_REASON_CELLULAR_DENIED
;
7001 } else if (interface_type_denied
== IFRTYPE_FUNCTIONAL_WIFI_INFRA
) {
7002 *reason
= NECP_CLIENT_RESULT_REASON_WIFI_DENIED
;
7005 necp_send_application_interface_denied_event(pid
, application_uuid
, interface_type_denied
);
7007 // If the route gets denied, stop matching rules
7012 if (rt
!= NULL
&& rt
->rt_ifp
!= NULL
) {
7013 const bool expensive_prohibited
= ((client_flags
& NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE
) &&
7014 IFNET_IS_EXPENSIVE(rt
->rt_ifp
));
7015 const bool constrained_prohibited
= ((client_flags
& NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED
) &&
7016 IFNET_IS_CONSTRAINED(rt
->rt_ifp
));
7017 if (reason
!= NULL
) {
7018 if (expensive_prohibited
) {
7019 *reason
= NECP_CLIENT_RESULT_REASON_EXPENSIVE_PROHIBITED
;
7020 } else if (constrained_prohibited
) {
7021 *reason
= NECP_CLIENT_RESULT_REASON_CONSTRAINED_PROHIBITED
;
7024 if (expensive_prohibited
|| constrained_prohibited
) {
7025 // If the client flags prohibited a property of the interface, treat it as a drop
7026 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
7027 memset(&returned_result
->routing_result_parameter
, 0, sizeof(returned_result
->routing_result_parameter
));
7032 if (returned_route
!= NULL
) {
7033 *returned_route
= rt
;
7040 lck_rw_done(&necp_kernel_policy_lock
);
7042 if (release_eproc
&& effective_proc
!= PROC_NULL
) {
7043 proc_rele(effective_proc
);
7045 #if defined(XNU_TARGET_OS_OSX)
7046 if (responsible_proc
!= PROC_NULL
) {
7047 proc_rele(responsible_proc
);
7055 necp_is_route_local(union necp_sockaddr_union
*remote_addr
)
7057 bool no_remote_addr
= FALSE
;
7058 u_int8_t remote_family
= 0;
7059 struct rtentry
*rt
= NULL
;
7060 bool is_local
= FALSE
;
7062 if (remote_addr
== NULL
) {
7066 if (remote_addr
->sa
.sa_len
== 0 ||
7067 (remote_addr
->sa
.sa_family
== AF_INET
&& remote_addr
->sin
.sin_addr
.s_addr
== 0) ||
7068 (remote_addr
->sa
.sa_family
== AF_INET6
&& IN6_IS_ADDR_UNSPECIFIED(&remote_addr
->sin6
.sin6_addr
))) {
7069 no_remote_addr
= TRUE
;
7070 remote_family
= remote_addr
->sa
.sa_family
;
7073 if (no_remote_addr
) {
7074 memset(remote_addr
, 0, sizeof(union necp_sockaddr_union
));
7075 if (remote_family
== AF_INET6
) {
7076 // Reset address to ::
7077 remote_addr
->sa
.sa_family
= AF_INET6
;
7078 remote_addr
->sa
.sa_len
= sizeof(struct sockaddr_in6
);
7080 // Reset address to 0.0.0.0
7081 remote_addr
->sa
.sa_family
= AF_INET
;
7082 remote_addr
->sa
.sa_len
= sizeof(struct sockaddr_in
);
7086 // Lookup route regardless of the scoped interface to check if
7087 // remote address is in a local network.
7088 rt
= rtalloc1_scoped((struct sockaddr
*)remote_addr
, 0, 0, 0);
7093 if (remote_addr
->sa
.sa_family
== AF_INET
&& IS_INTF_CLAT46(rt
->rt_ifp
)) {
7096 is_local
= IS_NECP_DEST_IN_LOCAL_NETWORKS(rt
);
7106 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
, struct necp_client_parameter_netagent_type
*required_agent_types
, u_int32_t num_required_agent_types
, bool has_client
, uint32_t client_flags
, int is_platform_binary
, proc_t proc
, u_int16_t pf_tag
, struct rtentry
*rt
)
7108 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) {
7109 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
7110 u_int32_t cond_bound_interface_index
= kernel_policy
->cond_bound_interface
? kernel_policy
->cond_bound_interface
->if_index
: 0;
7111 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
7112 if (bound_interface_index
== cond_bound_interface_index
) {
7113 // No match, matches forbidden interface
7117 if (bound_interface_index
!= cond_bound_interface_index
) {
7118 // No match, does not match required interface
7123 if (bound_interface_index
!= 0) {
7124 // No match, requires a non-bound packet
7130 if (kernel_policy
->condition_mask
== 0) {
7134 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
7135 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
7136 if (app_id
== kernel_policy
->cond_app_id
) {
7137 // No match, matches forbidden application
7141 if (app_id
!= kernel_policy
->cond_app_id
) {
7142 // No match, does not match required application
7147 // Check signing identifier only after APP ID matched
7148 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
||
7149 kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
) {
7150 u_int8_t matched
= necp_boolean_state_false
;
7151 const char *signing_id
= cs_identity_get(proc
? proc
: current_proc());
7153 if (signing_id
!= NULL
) {
7154 size_t signing_id_size
= strlen(signing_id
) + 1;
7155 if (memcmp(signing_id
, kernel_policy
->cond_signing_identifier
, signing_id_size
) == 0) {
7156 matched
= necp_boolean_state_true
;
7160 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
) {
7161 if (matched
== necp_boolean_state_true
) {
7165 if (matched
!= necp_boolean_state_true
) {
7172 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
7173 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
7174 if (real_app_id
== kernel_policy
->cond_real_app_id
) {
7175 // No match, matches forbidden application
7179 if (real_app_id
!= kernel_policy
->cond_real_app_id
) {
7180 // No match, does not match required application
7186 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_HAS_CLIENT
) {
7192 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
) {
7193 if (cred_result
!= 0) {
7194 // Process is missing entitlement
7199 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PLATFORM_BINARY
) {
7200 if (is_platform_binary
== 0) {
7201 // Process is not platform binary
7206 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_SDK_VERSION
) {
7208 if (kernel_policy
->cond_sdk_version
.platform
!= 0) {
7209 if (kernel_policy
->cond_sdk_version
.platform
!= proc_platform(proc
)) {
7210 // Process does not match platform
7215 if (kernel_policy
->cond_sdk_version
.min_version
!= 0) {
7216 if (kernel_policy
->cond_sdk_version
.min_version
> proc_min_sdk(proc
)) {
7217 // Process min version is older than required min version
7222 if (kernel_policy
->cond_sdk_version
.version
!= 0) {
7223 if (kernel_policy
->cond_sdk_version
.version
> proc_sdk(proc
)) {
7224 // Process SDK version is older than required version
7231 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) {
7232 if (kernel_policy
->cond_custom_entitlement_matched
== necp_boolean_state_false
) {
7233 // Process is missing entitlement based on previous check
7235 } else if (kernel_policy
->cond_custom_entitlement_matched
== necp_boolean_state_unknown
) {
7236 if (kernel_policy
->cond_custom_entitlement
!= NULL
) {
7238 // No process found, cannot check entitlement
7241 task_t task
= proc_task(proc
);
7243 !IOTaskHasEntitlement(task
, kernel_policy
->cond_custom_entitlement
)) {
7244 // Process is missing custom entitlement
7245 kernel_policy
->cond_custom_entitlement_matched
= necp_boolean_state_false
;
7248 kernel_policy
->cond_custom_entitlement_matched
= necp_boolean_state_true
;
7254 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
7255 bool domain_matches
= necp_hostname_matches_domain(domain
, domain_dot_count
, kernel_policy
->cond_domain
, kernel_policy
->cond_domain_dot_count
);
7256 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
7257 if (domain_matches
) {
7258 // No match, matches forbidden domain
7262 if (!domain_matches
) {
7263 // No match, does not match required domain
7269 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
7270 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
7271 if (account_id
== kernel_policy
->cond_account_id
) {
7272 // No match, matches forbidden account
7276 if (account_id
!= kernel_policy
->cond_account_id
) {
7277 // No match, does not match required account
7283 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PID
) {
7284 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_PID
) {
7285 if (pid
== kernel_policy
->cond_pid
) {
7286 // No match, matches forbidden pid
7290 if (pid
!= kernel_policy
->cond_pid
) {
7291 // No match, does not match required pid
7297 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_UID
) {
7298 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_UID
) {
7299 if (uid
== kernel_policy
->cond_uid
) {
7300 // No match, matches forbidden uid
7304 if (uid
!= kernel_policy
->cond_uid
) {
7305 // No match, does not match required uid
7311 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
7312 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
7313 if (traffic_class
>= kernel_policy
->cond_traffic_class
.start_tc
&&
7314 traffic_class
<= kernel_policy
->cond_traffic_class
.end_tc
) {
7315 // No match, matches forbidden traffic class
7319 if (traffic_class
< kernel_policy
->cond_traffic_class
.start_tc
||
7320 traffic_class
> kernel_policy
->cond_traffic_class
.end_tc
) {
7321 // No match, does not match required traffic class
7327 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
7328 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
7329 if (protocol
== kernel_policy
->cond_protocol
) {
7330 // No match, matches forbidden protocol
7334 if (protocol
!= kernel_policy
->cond_protocol
) {
7335 // No match, does not match required protocol
7341 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_AGENT_TYPE
) {
7342 bool matches_agent_type
= FALSE
;
7343 for (u_int32_t i
= 0; i
< num_required_agent_types
; i
++) {
7344 struct necp_client_parameter_netagent_type
*required_agent_type
= &required_agent_types
[i
];
7345 if ((strlen(kernel_policy
->cond_agent_type
.agent_domain
) == 0 ||
7346 strncmp(required_agent_type
->netagent_domain
, kernel_policy
->cond_agent_type
.agent_domain
, NETAGENT_DOMAINSIZE
) == 0) &&
7347 (strlen(kernel_policy
->cond_agent_type
.agent_type
) == 0 ||
7348 strncmp(required_agent_type
->netagent_type
, kernel_policy
->cond_agent_type
.agent_type
, NETAGENT_TYPESIZE
) == 0)) {
7349 // Found a required agent that matches
7350 matches_agent_type
= TRUE
;
7354 if (!matches_agent_type
) {
7359 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) {
7360 bool is_local
= FALSE
;
7363 is_local
= IS_NECP_DEST_IN_LOCAL_NETWORKS(rt
);
7365 is_local
= necp_is_route_local(remote
);
7369 // Either no route to validate or no match for local networks
7374 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
7375 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
7376 bool inRange
= necp_is_addr_in_range((struct sockaddr
*)local
, (struct sockaddr
*)&kernel_policy
->cond_local_start
, (struct sockaddr
*)&kernel_policy
->cond_local_end
);
7377 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
7386 } else if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
7387 bool inSubnet
= necp_is_addr_in_subnet((struct sockaddr
*)local
, (struct sockaddr
*)&kernel_policy
->cond_local_start
, kernel_policy
->cond_local_prefix
);
7388 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
7400 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
7401 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
7402 bool inRange
= necp_is_addr_in_range((struct sockaddr
*)remote
, (struct sockaddr
*)&kernel_policy
->cond_remote_start
, (struct sockaddr
*)&kernel_policy
->cond_remote_end
);
7403 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
7412 } else if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
7413 bool inSubnet
= necp_is_addr_in_subnet((struct sockaddr
*)remote
, (struct sockaddr
*)&kernel_policy
->cond_remote_start
, kernel_policy
->cond_remote_prefix
);
7414 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
7426 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_CLIENT_FLAGS
) {
7427 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_CLIENT_FLAGS
) {
7428 if ((client_flags
& kernel_policy
->cond_client_flags
) == kernel_policy
->cond_client_flags
) {
7429 // Flags do match, and condition is negative, fail.
7433 if ((client_flags
& kernel_policy
->cond_client_flags
) != kernel_policy
->cond_client_flags
) {
7434 // Flags do not match, fail.
7440 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_EMPTY
) {
7441 bool isEmpty
= necp_addr_is_empty((struct sockaddr
*)local
);
7442 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_EMPTY
) {
7453 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_EMPTY
) {
7454 bool isEmpty
= necp_addr_is_empty((struct sockaddr
*)remote
);
7455 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_EMPTY
) {
7466 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) {
7467 bool tags_matched
= false;
7468 if (kernel_policy
->cond_packet_filter_tags
& NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP
) {
7469 if (pf_tag
== PF_TAG_ID_STACK_DROP
) {
7470 tags_matched
= true;
7474 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) {
7479 if (!tags_matched
) {
7488 static inline u_int32_t
7489 necp_socket_calc_flowhash_locked(struct necp_socket_info
*info
)
7491 return net_flowhash(info
, sizeof(*info
), necp_kernel_socket_policies_gencount
);
7495 necp_socket_fillout_info_locked(struct inpcb
*inp
, struct sockaddr
*override_local_addr
, struct sockaddr
*override_remote_addr
, u_int32_t override_bound_interface
, u_int32_t drop_order
, proc_t
*socket_proc
, struct necp_socket_info
*info
)
7497 struct socket
*so
= NULL
;
7498 proc_t sock_proc
= NULL
;
7499 proc_t curr_proc
= current_proc();
7501 memset(info
, 0, sizeof(struct necp_socket_info
));
7503 so
= inp
->inp_socket
;
7505 info
->drop_order
= drop_order
;
7507 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_PID
) {
7508 info
->pid
= ((so
->so_flags
& SOF_DELEGATED
) ? so
->e_pid
: so
->last_pid
);
7511 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_UID
) {
7512 info
->uid
= kauth_cred_getuid(so
->so_cred
);
7515 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
7516 info
->traffic_class
= so
->so_traffic_class
;
7519 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_HAS_CLIENT
) {
7520 info
->has_client
= !uuid_is_null(inp
->necp_client_uuid
);
7523 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_CLIENT_FLAGS
) {
7524 info
->client_flags
= 0;
7525 if (INP_NO_CONSTRAINED(inp
)) {
7526 info
->client_flags
|= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED
;
7528 if (INP_NO_EXPENSIVE(inp
)) {
7529 info
->client_flags
|= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE
;
7531 if (inp
->inp_socket
->so_flags1
& SOF1_CELLFALLBACK
) {
7532 info
->client_flags
|= NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC
;
7534 if (inp
->inp_socket
->so_flags1
& SOF1_INBOUND
) {
7535 info
->client_flags
|= NECP_CLIENT_PARAMETER_FLAG_INBOUND
;
7537 if (inp
->inp_socket
->so_options
& SO_ACCEPTCONN
||
7538 inp
->inp_flags2
& INP2_EXTERNAL_PORT
) {
7539 info
->client_flags
|= NECP_CLIENT_PARAMETER_FLAG_LISTENER
;
7543 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
7544 if (inp
->inp_ip_p
) {
7545 info
->protocol
= inp
->inp_ip_p
;
7547 info
->protocol
= SOCK_PROTO(so
);
7551 if (inp
->inp_flags2
& INP2_WANT_APP_POLICY
&& necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
7552 u_int32_t responsible_application_id
= 0;
7554 struct necp_uuid_id_mapping
*existing_mapping
= necp_uuid_lookup_app_id_locked(((so
->so_flags
& SOF_DELEGATED
) ? so
->e_uuid
: so
->last_uuid
));
7555 if (existing_mapping
) {
7556 info
->application_id
= existing_mapping
->id
;
7559 #if defined(XNU_TARGET_OS_OSX)
7560 if (so
->so_rpid
> 0) {
7561 existing_mapping
= necp_uuid_lookup_app_id_locked(so
->so_ruuid
);
7562 if (existing_mapping
!= NULL
) {
7563 responsible_application_id
= existing_mapping
->id
;
7568 if (responsible_application_id
> 0) {
7569 info
->real_application_id
= info
->application_id
;
7570 info
->application_id
= responsible_application_id
;
7571 info
->used_responsible_pid
= true;
7572 } else if (!(so
->so_flags
& SOF_DELEGATED
)) {
7573 info
->real_application_id
= info
->application_id
;
7574 } else if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
7575 struct necp_uuid_id_mapping
*real_existing_mapping
= necp_uuid_lookup_app_id_locked(so
->last_uuid
);
7576 if (real_existing_mapping
) {
7577 info
->real_application_id
= real_existing_mapping
->id
;
7581 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
) {
7582 info
->cred_result
= priv_check_cred(so
->so_cred
, PRIV_NET_PRIVILEGED_NECP_MATCH
, 0);
7583 if (info
->cred_result
!= 0) {
7584 // Process does not have entitlement, check the parent process
7585 necp_get_parent_cred_result(NULL
, info
);
7591 #if defined(XNU_TARGET_OS_OSX)
7592 info
->used_responsible_pid
? so
->so_rpid
:
7594 ((so
->so_flags
& SOF_DELEGATED
) ? so
->e_pid
: so
->last_pid
);
7595 if (socket_pid
&& (socket_pid
!= proc_pid(curr_proc
))) {
7596 sock_proc
= proc_find(socket_pid
);
7598 *socket_proc
= sock_proc
;
7602 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_PLATFORM_BINARY
) {
7603 info
->is_platform_binary
= necp_is_platform_binary(sock_proc
? sock_proc
: curr_proc
) ? true : false;
7606 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
&& inp
->inp_necp_attributes
.inp_account
!= NULL
) {
7607 struct necp_string_id_mapping
*existing_mapping
= necp_lookup_string_to_id_locked(&necp_account_id_list
, inp
->inp_necp_attributes
.inp_account
);
7608 if (existing_mapping
) {
7609 info
->account_id
= existing_mapping
->id
;
7613 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
7614 info
->domain
= inp
->inp_necp_attributes
.inp_domain
;
7617 if (override_bound_interface
) {
7618 info
->bound_interface_index
= override_bound_interface
;
7620 if ((inp
->inp_flags
& INP_BOUND_IF
) && inp
->inp_boundifp
) {
7621 info
->bound_interface_index
= inp
->inp_boundifp
->if_index
;
7625 if (necp_restrict_multicast
||
7626 (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_ADDRESS_TYPE_CONDITIONS
)) {
7627 if (override_local_addr
!= NULL
) {
7628 if (override_local_addr
->sa_family
== AF_INET6
&& override_local_addr
->sa_len
<= sizeof(struct sockaddr_in6
)) {
7629 memcpy(&info
->local_addr
, override_local_addr
, override_local_addr
->sa_len
);
7630 if (IN6_IS_ADDR_V4MAPPED(&(info
->local_addr
.sin6
.sin6_addr
))) {
7631 struct sockaddr_in sin
;
7632 in6_sin6_2_sin(&sin
, &(info
->local_addr
.sin6
));
7633 memset(&info
->local_addr
, 0, sizeof(union necp_sockaddr_union
));
7634 memcpy(&info
->local_addr
, &sin
, sin
.sin_len
);
7636 } else if (override_local_addr
->sa_family
== AF_INET
&& override_local_addr
->sa_len
<= sizeof(struct sockaddr_in
)) {
7637 memcpy(&info
->local_addr
, override_local_addr
, override_local_addr
->sa_len
);
7640 if (inp
->inp_vflag
& INP_IPV4
) {
7641 ((struct sockaddr_in
*)&info
->local_addr
)->sin_family
= AF_INET
;
7642 ((struct sockaddr_in
*)&info
->local_addr
)->sin_len
= sizeof(struct sockaddr_in
);
7643 ((struct sockaddr_in
*)&info
->local_addr
)->sin_port
= inp
->inp_lport
;
7644 memcpy(&((struct sockaddr_in
*)&info
->local_addr
)->sin_addr
, &inp
->inp_laddr
, sizeof(struct in_addr
));
7645 } else if (inp
->inp_vflag
& INP_IPV6
) {
7646 ((struct sockaddr_in6
*)&info
->local_addr
)->sin6_family
= AF_INET6
;
7647 ((struct sockaddr_in6
*)&info
->local_addr
)->sin6_len
= sizeof(struct sockaddr_in6
);
7648 ((struct sockaddr_in6
*)&info
->local_addr
)->sin6_port
= inp
->inp_lport
;
7649 memcpy(&((struct sockaddr_in6
*)&info
->local_addr
)->sin6_addr
, &inp
->in6p_laddr
, sizeof(struct in6_addr
));
7653 if (override_remote_addr
!= NULL
) {
7654 if (override_remote_addr
->sa_family
== AF_INET6
&& override_remote_addr
->sa_len
<= sizeof(struct sockaddr_in6
)) {
7655 memcpy(&info
->remote_addr
, override_remote_addr
, override_remote_addr
->sa_len
);
7656 if (IN6_IS_ADDR_V4MAPPED(&(info
->remote_addr
.sin6
.sin6_addr
))) {
7657 struct sockaddr_in sin
;
7658 in6_sin6_2_sin(&sin
, &(info
->remote_addr
.sin6
));
7659 memset(&info
->remote_addr
, 0, sizeof(union necp_sockaddr_union
));
7660 memcpy(&info
->remote_addr
, &sin
, sin
.sin_len
);
7662 } else if (override_remote_addr
->sa_family
== AF_INET
&& override_remote_addr
->sa_len
<= sizeof(struct sockaddr_in
)) {
7663 memcpy(&info
->remote_addr
, override_remote_addr
, override_remote_addr
->sa_len
);
7666 if (inp
->inp_vflag
& INP_IPV4
) {
7667 ((struct sockaddr_in
*)&info
->remote_addr
)->sin_family
= AF_INET
;
7668 ((struct sockaddr_in
*)&info
->remote_addr
)->sin_len
= sizeof(struct sockaddr_in
);
7669 ((struct sockaddr_in
*)&info
->remote_addr
)->sin_port
= inp
->inp_fport
;
7670 memcpy(&((struct sockaddr_in
*)&info
->remote_addr
)->sin_addr
, &inp
->inp_faddr
, sizeof(struct in_addr
));
7671 } else if (inp
->inp_vflag
& INP_IPV6
) {
7672 ((struct sockaddr_in6
*)&info
->remote_addr
)->sin6_family
= AF_INET6
;
7673 ((struct sockaddr_in6
*)&info
->remote_addr
)->sin6_len
= sizeof(struct sockaddr_in6
);
7674 ((struct sockaddr_in6
*)&info
->remote_addr
)->sin6_port
= inp
->inp_fport
;
7675 memcpy(&((struct sockaddr_in6
*)&info
->remote_addr
)->sin6_addr
, &inp
->in6p_faddr
, sizeof(struct in6_addr
));
7681 static inline struct necp_kernel_socket_policy
*
7682 necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy
**policy_search_array
, struct necp_socket_info
*info
,
7683 necp_kernel_policy_filter
*return_filter
,
7684 u_int32_t
*return_route_rule_id_array
, size_t *return_route_rule_id_array_count
, size_t route_rule_id_array_count
,
7685 necp_kernel_policy_result
*return_service_action
, necp_kernel_policy_service
*return_service
,
7686 u_int32_t
*return_netagent_array
, u_int32_t
*return_netagent_use_flags_array
, size_t netagent_array_count
,
7687 struct necp_client_parameter_netagent_type
*required_agent_types
,
7688 u_int32_t num_required_agent_types
, proc_t proc
, u_int16_t pf_tag
, necp_kernel_policy_id
*skip_policy_id
, struct rtentry
*rt
,
7689 necp_kernel_policy_result
*return_drop_dest_policy_result
, necp_drop_all_bypass_check_result_t
*return_drop_all_bypass
,
7690 u_int32_t
*return_flow_divert_aggregate_unit
)
7692 struct necp_kernel_socket_policy
*matched_policy
= NULL
;
7693 u_int32_t skip_order
= 0;
7694 u_int32_t skip_session_order
= 0;
7695 size_t route_rule_id_count
= 0;
7697 size_t netagent_cursor
= 0;
7698 necp_drop_all_bypass_check_result_t drop_all_bypass
= NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
;
7699 if (return_drop_all_bypass
!= NULL
) {
7700 *return_drop_all_bypass
= drop_all_bypass
;
7703 // Pre-process domain for quick matching
7704 struct substring domain_substring
= necp_trim_dots_and_stars(info
->domain
, info
->domain
? strlen(info
->domain
) : 0);
7705 u_int8_t domain_dot_count
= necp_count_dots(domain_substring
.string
, domain_substring
.length
);
7707 if (return_filter
!= NULL
) {
7711 if (return_route_rule_id_array_count
!= NULL
) {
7712 *return_route_rule_id_array_count
= 0;
7715 if (return_service_action
!= NULL
) {
7716 *return_service_action
= 0;
7719 if (return_service
!= NULL
) {
7720 return_service
->identifier
= 0;
7721 return_service
->data
= 0;
7724 // Do not subject layer-2 filter to NECP policies, return a PASS policy
7725 if (necp_pass_interpose
> 0 && info
->client_flags
& NECP_CLIENT_PARAMETER_FLAG_INTERPOSE
) {
7726 return &pass_policy
;
7729 *return_drop_dest_policy_result
= NECP_KERNEL_POLICY_RESULT_NONE
;
7731 if (policy_search_array
!= NULL
) {
7732 for (i
= 0; policy_search_array
[i
] != NULL
; i
++) {
7733 if (necp_drop_all_order
!= 0 && policy_search_array
[i
]->session_order
>= necp_drop_all_order
) {
7734 // We've hit a drop all rule
7735 if (drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
) {
7736 drop_all_bypass
= necp_check_drop_all_bypass_result(proc
);
7737 if (return_drop_all_bypass
!= NULL
) {
7738 *return_drop_all_bypass
= drop_all_bypass
;
7741 if (drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
) {
7745 if (necp_drop_dest_policy
.entry_count
!= 0 &&
7746 necp_address_matches_drop_dest_policy(&info
->remote_addr
, policy_search_array
[i
]->session_order
)) {
7747 // We've hit a drop by destination address rule
7748 *return_drop_dest_policy_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
7751 if (info
->drop_order
!= 0 && policy_search_array
[i
]->session_order
>= info
->drop_order
) {
7752 // We've hit a drop order for this socket
7755 if (skip_session_order
&& policy_search_array
[i
]->session_order
>= skip_session_order
) {
7758 skip_session_order
= 0;
7761 if (policy_search_array
[i
]->order
< skip_order
) {
7767 skip_session_order
= 0;
7769 } else if (skip_session_order
) {
7774 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
, required_agent_types
, num_required_agent_types
, info
->has_client
, info
->client_flags
, info
->is_platform_binary
, proc
, pf_tag
, rt
)) {
7775 if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER
) {
7776 if (return_filter
&& *return_filter
!= NECP_FILTER_UNIT_NO_FILTER
) {
7777 necp_kernel_policy_filter control_unit
= policy_search_array
[i
]->result_parameter
.filter_control_unit
;
7778 if (control_unit
== NECP_FILTER_UNIT_NO_FILTER
) {
7779 *return_filter
= control_unit
;
7781 *return_filter
|= control_unit
;
7783 if (necp_debug
> 1) {
7784 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
);
7788 } else if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_ROUTE_RULES
) {
7789 if (return_route_rule_id_array
&& route_rule_id_count
< route_rule_id_array_count
) {
7790 return_route_rule_id_array
[route_rule_id_count
++] = policy_search_array
[i
]->result_parameter
.route_rule_id
;
7791 if (necp_debug
> 1) {
7792 NECPLOG(LOG_DEBUG
, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) Route Rule %d", info
->application_id
, info
->real_application_id
, info
->bound_interface_index
, info
->protocol
, policy_search_array
[i
]->result_parameter
.route_rule_id
);
7796 } else if (necp_kernel_socket_result_is_trigger_service_type(policy_search_array
[i
])) {
7797 if (return_service_action
&& *return_service_action
== 0) {
7798 *return_service_action
= policy_search_array
[i
]->result
;
7799 if (necp_debug
> 1) {
7800 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
);
7803 if (return_service
&& return_service
->identifier
== 0) {
7804 return_service
->identifier
= policy_search_array
[i
]->result_parameter
.service
.identifier
;
7805 return_service
->data
= policy_search_array
[i
]->result_parameter
.service
.data
;
7806 if (necp_debug
> 1) {
7807 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
);
7811 } else if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_USE_NETAGENT
||
7812 policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED
) {
7813 if (return_netagent_array
!= NULL
&&
7814 netagent_cursor
< netagent_array_count
) {
7815 return_netagent_array
[netagent_cursor
] = policy_search_array
[i
]->result_parameter
.netagent_id
;
7816 if (return_netagent_use_flags_array
!= NULL
&&
7817 policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED
) {
7818 return_netagent_use_flags_array
[netagent_cursor
] |= NECP_AGENT_USE_FLAG_SCOPE
;
7821 if (necp_debug
> 1) {
7822 NECPLOG(LOG_DEBUG
, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) %s Netagent %d",
7823 info
->application_id
, info
->real_application_id
, info
->bound_interface_index
, info
->protocol
,
7824 policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_USE_NETAGENT
? "Use" : "Scope",
7825 policy_search_array
[i
]->result_parameter
.netagent_id
);
7829 } else if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
) {
7830 u_int32_t control_unit
= policy_search_array
[i
]->result_parameter
.flow_divert_control_unit
;
7831 if (control_unit
& FLOW_DIVERT_IS_TRANSPARENT
) {
7832 /* For transparent proxies, accumulate the control unit and continue to the next policy */
7833 if (return_flow_divert_aggregate_unit
!= NULL
) {
7834 *return_flow_divert_aggregate_unit
|= (control_unit
& ~FLOW_DIVERT_IS_TRANSPARENT
);
7835 if (necp_debug
> 1) {
7836 NECPLOG(LOG_DEBUG
, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) flow divert %u", info
->application_id
, info
->real_application_id
, info
->bound_interface_index
, info
->protocol
, control_unit
);
7843 // Matched policy is a skip. Do skip and continue.
7844 if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
7845 skip_order
= policy_search_array
[i
]->result_parameter
.skip_policy_order
;
7846 skip_session_order
= policy_search_array
[i
]->session_order
+ 1;
7847 if (skip_policy_id
&& *skip_policy_id
== NECP_KERNEL_POLICY_ID_NONE
) {
7848 *skip_policy_id
= policy_search_array
[i
]->id
;
7853 // Matched an allow unentitled, which clears any drop order
7854 if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED
) {
7855 info
->drop_order
= 0;
7859 // Passed all tests, found a match
7860 matched_policy
= policy_search_array
[i
];
7866 if (return_route_rule_id_array_count
!= NULL
) {
7867 *return_route_rule_id_array_count
= route_rule_id_count
;
7869 return matched_policy
;
7873 necp_socket_uses_interface(struct inpcb
*inp
, u_int32_t interface_index
)
7875 bool found_match
= FALSE
;
7877 ifaddr_t
*addresses
= NULL
;
7878 union necp_sockaddr_union address_storage
;
7880 int family
= AF_INET
;
7881 ifnet_t interface
= ifindex2ifnet
[interface_index
];
7883 if (inp
== NULL
|| interface
== NULL
) {
7887 if (inp
->inp_vflag
& INP_IPV4
) {
7889 } else if (inp
->inp_vflag
& INP_IPV6
) {
7893 result
= ifnet_get_address_list_family(interface
, &addresses
, family
);
7895 NECPLOG(LOG_ERR
, "Failed to get address list for %s%d", ifnet_name(interface
), ifnet_unit(interface
));
7899 for (i
= 0; addresses
[i
] != NULL
; i
++) {
7900 if (ifaddr_address(addresses
[i
], &address_storage
.sa
, sizeof(address_storage
)) == 0) {
7901 if (family
== AF_INET
) {
7902 if (memcmp(&address_storage
.sin
.sin_addr
, &inp
->inp_laddr
, sizeof(inp
->inp_laddr
)) == 0) {
7906 } else if (family
== AF_INET6
) {
7907 if (memcmp(&address_storage
.sin6
.sin6_addr
, &inp
->in6p_laddr
, sizeof(inp
->in6p_laddr
)) == 0) {
7916 ifnet_free_address_list(addresses
);
7922 necp_socket_is_connected(struct inpcb
*inp
)
7924 return inp
->inp_socket
->so_state
& (SS_ISCONNECTING
| SS_ISCONNECTED
| SS_ISDISCONNECTING
);
7928 necp_socket_bypass(struct sockaddr
*override_local_addr
, struct sockaddr
*override_remote_addr
, struct inpcb
*inp
)
7930 if (necp_pass_loopback
> 0 && necp_is_loopback(override_local_addr
, override_remote_addr
, inp
, NULL
, IFSCOPE_NONE
)) {
7932 } else if (necp_is_intcoproc(inp
, NULL
)) {
7940 necp_socket_ip_tunnel_tso(struct inpcb
*inp
)
7942 u_int tunnel_interface_index
= inp
->inp_policyresult
.results
.result_parameter
.tunnel_interface_index
;
7943 ifnet_t tunnel_interface
= NULL
;
7945 ifnet_head_lock_shared();
7946 tunnel_interface
= ifindex2ifnet
[tunnel_interface_index
];
7949 if (tunnel_interface
!= NULL
) {
7950 tcp_set_tso(intotcpcb(inp
), tunnel_interface
);
7954 necp_kernel_policy_id
7955 necp_socket_find_policy_match(struct inpcb
*inp
, struct sockaddr
*override_local_addr
, struct sockaddr
*override_remote_addr
, u_int32_t override_bound_interface
)
7957 struct socket
*so
= NULL
;
7958 necp_kernel_policy_filter filter_control_unit
= 0;
7959 struct necp_kernel_socket_policy
*matched_policy
= NULL
;
7960 necp_kernel_policy_id matched_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
7961 necp_kernel_policy_result service_action
= 0;
7962 necp_kernel_policy_service service
= { 0, 0 };
7963 u_int32_t drop_dest_policy_result
= NECP_KERNEL_POLICY_RESULT_NONE
;
7964 necp_drop_all_bypass_check_result_t drop_all_bypass
= NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
;
7965 proc_t socket_proc
= NULL
;
7967 u_int32_t netagent_ids
[NECP_MAX_NETAGENTS
];
7968 memset(&netagent_ids
, 0, sizeof(netagent_ids
));
7969 int netagent_cursor
;
7971 struct necp_socket_info info
;
7973 u_int32_t flow_divert_aggregate_unit
= 0;
7976 return NECP_KERNEL_POLICY_ID_NONE
;
7979 // Ignore invalid addresses
7980 if (override_local_addr
!= NULL
&&
7981 !necp_address_is_valid(override_local_addr
)) {
7982 override_local_addr
= NULL
;
7984 if (override_remote_addr
!= NULL
&&
7985 !necp_address_is_valid(override_remote_addr
)) {
7986 override_remote_addr
= NULL
;
7989 so
= inp
->inp_socket
;
7991 u_int32_t drop_order
= necp_process_drop_order(so
->so_cred
);
7993 // Don't lock. Possible race condition, but we don't want the performance hit.
7994 if (necp_kernel_socket_policies_count
== 0 ||
7995 (!(inp
->inp_flags2
& INP2_WANT_APP_POLICY
) && necp_kernel_socket_policies_non_app_count
== 0)) {
7996 if (necp_drop_all_order
> 0 || drop_order
> 0) {
7997 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
7998 inp
->inp_policyresult
.skip_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
7999 inp
->inp_policyresult
.policy_gencount
= 0;
8000 inp
->inp_policyresult
.app_id
= 0;
8001 inp
->inp_policyresult
.flowhash
= 0;
8002 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
8003 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= 0;
8004 inp
->inp_policyresult
.results
.route_rule_id
= 0;
8005 if (necp_socket_bypass(override_local_addr
, override_remote_addr
, inp
)) {
8006 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_PASS
;
8008 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_DROP
;
8011 return NECP_KERNEL_POLICY_ID_NONE
;
8014 // Check for loopback exception
8015 if (necp_socket_bypass(override_local_addr
, override_remote_addr
, inp
)) {
8016 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
) {
8017 // If the previous policy result was "socket scoped", un-scope the socket.
8018 inp
->inp_flags
&= ~INP_BOUND_IF
;
8019 inp
->inp_boundifp
= NULL
;
8021 // Mark socket as a pass
8022 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8023 inp
->inp_policyresult
.skip_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8024 inp
->inp_policyresult
.policy_gencount
= 0;
8025 inp
->inp_policyresult
.app_id
= 0;
8026 inp
->inp_policyresult
.flowhash
= 0;
8027 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
8028 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= 0;
8029 inp
->inp_policyresult
.results
.route_rule_id
= 0;
8030 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_PASS
;
8031 return NECP_KERNEL_POLICY_ID_NONE
;
8035 lck_rw_lock_shared(&necp_kernel_policy_lock
);
8036 necp_socket_fillout_info_locked(inp
, override_local_addr
, override_remote_addr
, override_bound_interface
, drop_order
, &socket_proc
, &info
);
8039 u_int32_t flowhash
= necp_socket_calc_flowhash_locked(&info
);
8040 if (inp
->inp_policyresult
.policy_id
!= NECP_KERNEL_POLICY_ID_NONE
&&
8041 inp
->inp_policyresult
.policy_gencount
== necp_kernel_socket_policies_gencount
&&
8042 inp
->inp_policyresult
.flowhash
== flowhash
) {
8043 // If already matched this socket on this generation of table, skip
8046 lck_rw_done(&necp_kernel_policy_lock
);
8049 proc_rele(socket_proc
);
8052 return inp
->inp_policyresult
.policy_id
;
8055 inp
->inp_policyresult
.app_id
= info
.application_id
;
8057 // Match socket to policy
8058 necp_kernel_policy_id skip_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
8059 u_int32_t route_rule_id_array
[MAX_AGGREGATE_ROUTE_RULES
];
8060 size_t route_rule_id_array_count
= 0;
8061 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
, route_rule_id_array
, &route_rule_id_array_count
, MAX_AGGREGATE_ROUTE_RULES
, &service_action
, &service
, netagent_ids
, NULL
, NECP_MAX_NETAGENTS
, NULL
, 0, socket_proc
? socket_proc
: current_proc(), 0, &skip_policy_id
, inp
->inp_route
.ro_rt
, &drop_dest_policy_result
, &drop_all_bypass
, &flow_divert_aggregate_unit
);
8063 // If the socket matched a scoped service policy, mark as Drop if not registered.
8064 // This covers the cases in which a service is required (on demand) but hasn't started yet.
8065 if ((service_action
== NECP_KERNEL_POLICY_RESULT_TRIGGER_SCOPED
||
8066 service_action
== NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED
) &&
8067 service
.identifier
!= 0 &&
8068 service
.identifier
!= NECP_NULL_SERVICE_ID
) {
8069 bool service_is_registered
= FALSE
;
8070 struct necp_service_registration
*service_registration
= NULL
;
8071 LIST_FOREACH(service_registration
, &necp_registered_service_list
, kernel_chain
) {
8072 if (service
.identifier
== service_registration
->service_id
) {
8073 service_is_registered
= TRUE
;
8077 if (!service_is_registered
) {
8078 // Mark socket as a drop if service is not registered
8079 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8080 inp
->inp_policyresult
.skip_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8081 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
8082 inp
->inp_policyresult
.flowhash
= flowhash
;
8083 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
8084 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= 0;
8085 inp
->inp_policyresult
.results
.route_rule_id
= 0;
8086 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_DROP
;
8088 if (necp_debug
> 1) {
8089 NECPLOG(LOG_DEBUG
, "Socket Policy: (BoundInterface %d Proto %d) Dropping packet because service is not registered", info
.bound_interface_index
, info
.protocol
);
8093 lck_rw_done(&necp_kernel_policy_lock
);
8096 proc_rele(socket_proc
);
8099 return NECP_KERNEL_POLICY_ID_NONE
;
8103 for (netagent_cursor
= 0; netagent_cursor
< NECP_MAX_NETAGENTS
; netagent_cursor
++) {
8104 struct necp_uuid_id_mapping
*mapping
= NULL
;
8105 u_int32_t netagent_id
= netagent_ids
[netagent_cursor
];
8106 if (netagent_id
== 0) {
8109 mapping
= necp_uuid_lookup_uuid_with_service_id_locked(netagent_id
);
8110 if (mapping
!= NULL
) {
8111 u_int32_t agent_flags
= 0;
8112 agent_flags
= netagent_get_flags(mapping
->uuid
);
8113 if (agent_flags
& NETAGENT_FLAG_REGISTERED
) {
8114 if (agent_flags
& NETAGENT_FLAG_ACTIVE
) {
8116 } else if ((agent_flags
& NETAGENT_FLAG_VOLUNTARY
) == 0) {
8117 if (agent_flags
& NETAGENT_FLAG_KERNEL_ACTIVATED
) {
8118 int trigger_error
= 0;
8119 trigger_error
= netagent_kernel_trigger(mapping
->uuid
);
8120 if (necp_debug
> 1) {
8121 NECPLOG(LOG_DEBUG
, "Socket Policy: Triggering inactive agent, error %d", trigger_error
);
8125 // Mark socket as a drop if required agent is not active
8126 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8127 inp
->inp_policyresult
.skip_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8128 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
8129 inp
->inp_policyresult
.flowhash
= flowhash
;
8130 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
8131 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= 0;
8132 inp
->inp_policyresult
.results
.route_rule_id
= 0;
8133 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_DROP
;
8135 if (necp_debug
> 1) {
8136 NECPLOG(LOG_DEBUG
, "Socket Policy: (BoundInterface %d Proto %d) Dropping packet because agent is not active", info
.bound_interface_index
, info
.protocol
);
8140 lck_rw_done(&necp_kernel_policy_lock
);
8143 proc_rele(socket_proc
);
8146 return NECP_KERNEL_POLICY_ID_NONE
;
8152 u_int32_t route_rule_id
= 0;
8153 if (route_rule_id_array_count
== 1) {
8154 route_rule_id
= route_rule_id_array
[0];
8155 } else if (route_rule_id_array_count
> 1) {
8156 route_rule_id
= necp_create_aggregate_route_rule(route_rule_id_array
);
8159 bool reset_tcp_tunnel_interface
= false;
8160 bool send_local_network_denied_event
= false;
8161 if (matched_policy
) {
8162 matched_policy_id
= matched_policy
->id
;
8163 inp
->inp_policyresult
.policy_id
= matched_policy
->id
;
8164 inp
->inp_policyresult
.skip_policy_id
= skip_policy_id
;
8165 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
8166 inp
->inp_policyresult
.flowhash
= flowhash
;
8167 inp
->inp_policyresult
.results
.filter_control_unit
= filter_control_unit
;
8168 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= flow_divert_aggregate_unit
;
8169 inp
->inp_policyresult
.results
.route_rule_id
= route_rule_id
;
8170 inp
->inp_policyresult
.results
.result
= matched_policy
->result
;
8171 memcpy(&inp
->inp_policyresult
.results
.result_parameter
, &matched_policy
->result_parameter
, sizeof(matched_policy
->result_parameter
));
8173 if (info
.used_responsible_pid
&& (matched_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
)) {
8174 inp
->inp_policyresult
.app_id
= info
.real_application_id
;
8177 if (necp_socket_is_connected(inp
) &&
8178 (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_DROP
||
8179 (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&& !necp_socket_uses_interface(inp
, matched_policy
->result_parameter
.tunnel_interface_index
)))) {
8181 NECPLOG(LOG_DEBUG
, "Marking socket in state %d as defunct", so
->so_state
);
8183 sosetdefunct(current_proc(), so
, SHUTDOWN_SOCKET_LEVEL_NECP
| SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL
, TRUE
);
8184 } else if (necp_socket_is_connected(inp
) &&
8185 matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&&
8186 info
.protocol
== IPPROTO_TCP
) {
8187 // Reset TCP socket interface based parameters if tunnel policy changes
8188 reset_tcp_tunnel_interface
= true;
8191 if (necp_debug
> 1) {
8192 NECPLOG(LOG_DEBUG
, "Socket Policy: %p (BoundInterface %d Proto %d) Policy %d Result %d Parameter %d", inp
->inp_socket
, info
.bound_interface_index
, info
.protocol
, matched_policy
->id
, matched_policy
->result
, matched_policy
->result_parameter
.tunnel_interface_index
);
8195 if (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_DROP
&&
8196 matched_policy
->result_parameter
.drop_flags
& NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK
) {
8197 // Trigger the event that we dropped due to a local network policy
8198 send_local_network_denied_event
= true;
8201 bool drop_all
= false;
8202 if (necp_drop_all_order
> 0 || info
.drop_order
> 0 || drop_dest_policy_result
== NECP_KERNEL_POLICY_RESULT_DROP
) {
8203 // Mark socket as a drop if set
8205 if (drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
) {
8206 drop_all_bypass
= necp_check_drop_all_bypass_result(socket_proc
? socket_proc
: current_proc());
8209 if (drop_all
&& drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
) {
8210 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8211 inp
->inp_policyresult
.skip_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8212 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
8213 inp
->inp_policyresult
.flowhash
= flowhash
;
8214 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
8215 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= 0;
8216 inp
->inp_policyresult
.results
.route_rule_id
= 0;
8217 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_DROP
;
8219 // Mark non-matching socket so we don't re-check it
8220 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8221 inp
->inp_policyresult
.skip_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8222 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
8223 inp
->inp_policyresult
.flowhash
= flowhash
;
8224 inp
->inp_policyresult
.results
.filter_control_unit
= filter_control_unit
; // We may have matched a filter, so mark it!
8225 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= flow_divert_aggregate_unit
;
8226 inp
->inp_policyresult
.results
.route_rule_id
= route_rule_id
; // We may have matched a route rule, so mark it!
8227 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_NONE
;
8231 if (necp_check_missing_client_drop(socket_proc
? socket_proc
: current_proc(), &info
) ||
8232 necp_check_restricted_multicast_drop(socket_proc
? socket_proc
: current_proc(), &info
, false)) {
8234 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8235 inp
->inp_policyresult
.skip_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8236 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
8237 inp
->inp_policyresult
.flowhash
= flowhash
;
8238 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
8239 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= 0;
8240 inp
->inp_policyresult
.results
.route_rule_id
= 0;
8241 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_DROP
;
8245 lck_rw_done(&necp_kernel_policy_lock
);
8247 if (reset_tcp_tunnel_interface
) {
8248 // Update MSS when not holding the policy lock to avoid recursive locking
8249 tcp_mtudisc(inp
, 0);
8251 // Update TSO flag based on the tunnel interface
8252 necp_socket_ip_tunnel_tso(inp
);
8255 if (send_local_network_denied_event
) {
8256 necp_send_network_denied_event(((so
->so_flags
& SOF_DELEGATED
) ? so
->e_pid
: so
->last_pid
),
8257 ((so
->so_flags
& SOF_DELEGATED
) ? so
->e_uuid
: so
->last_uuid
),
8258 NETPOLICY_NETWORKTYPE_LOCAL
);
8262 proc_rele(socket_proc
);
8265 return matched_policy_id
;
8269 necp_ip_output_check_policy(struct necp_kernel_ip_output_policy
*kernel_policy
, necp_kernel_policy_id socket_policy_id
, necp_kernel_policy_id socket_skip_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
, struct rtentry
*rt
, u_int16_t pf_tag
)
8271 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) {
8272 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
8273 u_int32_t cond_bound_interface_index
= kernel_policy
->cond_bound_interface
? kernel_policy
->cond_bound_interface
->if_index
: 0;
8274 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
8275 if (bound_interface_index
== cond_bound_interface_index
) {
8276 // No match, matches forbidden interface
8280 if (bound_interface_index
!= cond_bound_interface_index
) {
8281 // No match, does not match required interface
8286 if (bound_interface_index
!= 0) {
8287 // No match, requires a non-bound packet
8293 if (kernel_policy
->condition_mask
== 0) {
8297 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
) {
8298 necp_kernel_policy_id matched_policy_id
=
8299 kernel_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
? socket_skip_policy_id
: socket_policy_id
;
8300 if (matched_policy_id
!= kernel_policy
->cond_policy_id
) {
8301 // No match, does not match required id
8306 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LAST_INTERFACE
) {
8307 if (last_interface_index
!= kernel_policy
->cond_last_interface_index
) {
8312 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
8313 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
8314 if (protocol
== kernel_policy
->cond_protocol
) {
8315 // No match, matches forbidden protocol
8319 if (protocol
!= kernel_policy
->cond_protocol
) {
8320 // No match, does not match required protocol
8326 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) {
8327 bool is_local
= FALSE
;
8330 is_local
= IS_NECP_DEST_IN_LOCAL_NETWORKS(rt
);
8332 is_local
= necp_is_route_local(remote
);
8336 // Either no route to validate or no match for local networks
8341 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
8342 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
8343 bool inRange
= necp_is_addr_in_range((struct sockaddr
*)local
, (struct sockaddr
*)&kernel_policy
->cond_local_start
, (struct sockaddr
*)&kernel_policy
->cond_local_end
);
8344 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
8353 } else if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
8354 bool inSubnet
= necp_is_addr_in_subnet((struct sockaddr
*)local
, (struct sockaddr
*)&kernel_policy
->cond_local_start
, kernel_policy
->cond_local_prefix
);
8355 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
8367 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
8368 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
8369 bool inRange
= necp_is_addr_in_range((struct sockaddr
*)remote
, (struct sockaddr
*)&kernel_policy
->cond_remote_start
, (struct sockaddr
*)&kernel_policy
->cond_remote_end
);
8370 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
8379 } else if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
8380 bool inSubnet
= necp_is_addr_in_subnet((struct sockaddr
*)remote
, (struct sockaddr
*)&kernel_policy
->cond_remote_start
, kernel_policy
->cond_remote_prefix
);
8381 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
8393 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) {
8394 bool tags_matched
= false;
8396 if (kernel_policy
->cond_packet_filter_tags
& NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP
) {
8397 if ((pf_tag
& PF_TAG_ID_STACK_DROP
) == PF_TAG_ID_STACK_DROP
) {
8398 tags_matched
= true;
8401 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) {
8406 if (!tags_matched
) {
8416 static inline struct necp_kernel_ip_output_policy
*
8417 necp_ip_output_find_policy_match_locked(necp_kernel_policy_id socket_policy_id
, necp_kernel_policy_id socket_skip_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
, struct rtentry
*rt
, u_int16_t pf_tag
, u_int32_t
*return_route_rule_id
, necp_kernel_policy_result
*return_drop_dest_policy_result
, necp_drop_all_bypass_check_result_t
*return_drop_all_bypass
)
8419 u_int32_t skip_order
= 0;
8420 u_int32_t skip_session_order
= 0;
8421 struct necp_kernel_ip_output_policy
*matched_policy
= NULL
;
8422 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
)];
8423 u_int32_t route_rule_id_array
[MAX_AGGREGATE_ROUTE_RULES
];
8424 size_t route_rule_id_count
= 0;
8425 necp_drop_all_bypass_check_result_t drop_all_bypass
= NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
;
8426 if (return_drop_all_bypass
!= NULL
) {
8427 *return_drop_all_bypass
= drop_all_bypass
;
8430 if (return_route_rule_id
!= NULL
) {
8431 *return_route_rule_id
= 0;
8434 *return_drop_dest_policy_result
= NECP_KERNEL_POLICY_RESULT_NONE
;
8436 if (policy_search_array
!= NULL
) {
8437 for (int i
= 0; policy_search_array
[i
] != NULL
; i
++) {
8438 if (necp_drop_all_order
!= 0 && policy_search_array
[i
]->session_order
>= necp_drop_all_order
) {
8439 // We've hit a drop all rule
8440 if (drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
) {
8441 drop_all_bypass
= necp_check_drop_all_bypass_result(NULL
);
8442 if (return_drop_all_bypass
!= NULL
) {
8443 *return_drop_all_bypass
= drop_all_bypass
;
8446 if (drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
) {
8450 if (necp_drop_dest_policy
.entry_count
> 0 &&
8451 necp_address_matches_drop_dest_policy(remote_addr
, policy_search_array
[i
]->session_order
)) {
8452 // We've hit a drop by destination address rule
8453 *return_drop_dest_policy_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
8456 if (skip_session_order
&& policy_search_array
[i
]->session_order
>= skip_session_order
) {
8459 skip_session_order
= 0;
8462 if (policy_search_array
[i
]->order
< skip_order
) {
8468 skip_session_order
= 0;
8470 } else if (skip_session_order
) {
8475 if (necp_ip_output_check_policy(policy_search_array
[i
], socket_policy_id
, socket_skip_policy_id
, bound_interface_index
, last_interface_index
, protocol
, local_addr
, remote_addr
, rt
, pf_tag
)) {
8476 if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_ROUTE_RULES
) {
8477 if (return_route_rule_id
!= NULL
&& route_rule_id_count
< MAX_AGGREGATE_ROUTE_RULES
) {
8478 route_rule_id_array
[route_rule_id_count
++] = policy_search_array
[i
]->result_parameter
.route_rule_id
;
8481 } else if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
8482 skip_order
= policy_search_array
[i
]->result_parameter
.skip_policy_order
;
8483 skip_session_order
= policy_search_array
[i
]->session_order
+ 1;
8487 // Passed all tests, found a match
8488 matched_policy
= policy_search_array
[i
];
8494 if (route_rule_id_count
== 1) {
8495 *return_route_rule_id
= route_rule_id_array
[0];
8496 } else if (route_rule_id_count
> 1) {
8497 *return_route_rule_id
= necp_create_aggregate_route_rule(route_rule_id_array
);
8500 return matched_policy
;
8504 necp_output_bypass(struct mbuf
*packet
)
8506 if (necp_pass_loopback
> 0 && necp_is_loopback(NULL
, NULL
, NULL
, packet
, IFSCOPE_NONE
)) {
8509 if (necp_pass_keepalives
> 0 && necp_get_is_keepalive_from_packet(packet
)) {
8512 if (necp_is_intcoproc(NULL
, packet
)) {
8518 necp_kernel_policy_id
8519 necp_ip_output_find_policy_match(struct mbuf
*packet
, int flags
, struct ip_out_args
*ipoa
, struct rtentry
*rt
,
8520 necp_kernel_policy_result
*result
, necp_kernel_policy_result_parameter
*result_parameter
)
8522 struct ip
*ip
= NULL
;
8523 int hlen
= sizeof(struct ip
);
8524 necp_kernel_policy_id socket_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
8525 necp_kernel_policy_id socket_skip_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
8526 necp_kernel_policy_id matched_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
8527 struct necp_kernel_ip_output_policy
*matched_policy
= NULL
;
8528 u_int16_t protocol
= 0;
8529 u_int32_t bound_interface_index
= 0;
8530 u_int32_t last_interface_index
= 0;
8531 union necp_sockaddr_union local_addr
;
8532 union necp_sockaddr_union remote_addr
;
8533 u_int32_t drop_dest_policy_result
= NECP_KERNEL_POLICY_RESULT_NONE
;
8534 necp_drop_all_bypass_check_result_t drop_all_bypass
= NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
;
8535 u_int16_t pf_tag
= 0;
8541 if (result_parameter
) {
8542 memset(result_parameter
, 0, sizeof(*result_parameter
));
8545 if (packet
== NULL
) {
8546 return NECP_KERNEL_POLICY_ID_NONE
;
8549 socket_policy_id
= necp_get_policy_id_from_packet(packet
);
8550 socket_skip_policy_id
= necp_get_skip_policy_id_from_packet(packet
);
8551 pf_tag
= necp_get_packet_filter_tags_from_packet(packet
);
8553 // Exit early for an empty list
8554 // Don't lock. Possible race condition, but we don't want the performance hit.
8555 if (necp_kernel_ip_output_policies_count
== 0 ||
8556 (socket_policy_id
== NECP_KERNEL_POLICY_ID_NONE
&& necp_kernel_ip_output_policies_non_id_count
== 0 && necp_drop_dest_policy
.entry_count
== 0)) {
8557 if (necp_drop_all_order
> 0) {
8558 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8560 if (necp_output_bypass(packet
)) {
8561 *result
= NECP_KERNEL_POLICY_RESULT_PASS
;
8563 *result
= NECP_KERNEL_POLICY_RESULT_DROP
;
8568 return matched_policy_id
;
8571 // Check for loopback exception
8572 if (necp_output_bypass(packet
)) {
8573 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8575 *result
= NECP_KERNEL_POLICY_RESULT_PASS
;
8577 return matched_policy_id
;
8580 last_interface_index
= necp_get_last_interface_index_from_packet(packet
);
8582 // Process packet to get relevant fields
8583 ip
= mtod(packet
, struct ip
*);
8585 hlen
= _IP_VHL_HL(ip
->ip_vhl
) << 2;
8587 hlen
= ip
->ip_hl
<< 2;
8590 protocol
= ip
->ip_p
;
8592 if ((flags
& IP_OUTARGS
) && (ipoa
!= NULL
) &&
8593 (ipoa
->ipoa_flags
& IPOAF_BOUND_IF
) &&
8594 ipoa
->ipoa_boundif
!= IFSCOPE_NONE
) {
8595 bound_interface_index
= ipoa
->ipoa_boundif
;
8598 local_addr
.sin
.sin_family
= AF_INET
;
8599 local_addr
.sin
.sin_len
= sizeof(struct sockaddr_in
);
8600 memcpy(&local_addr
.sin
.sin_addr
, &ip
->ip_src
, sizeof(ip
->ip_src
));
8602 remote_addr
.sin
.sin_family
= AF_INET
;
8603 remote_addr
.sin
.sin_len
= sizeof(struct sockaddr_in
);
8604 memcpy(&((struct sockaddr_in
*)&remote_addr
)->sin_addr
, &ip
->ip_dst
, sizeof(ip
->ip_dst
));
8609 if ((int)(hlen
+ sizeof(th
)) <= packet
->m_pkthdr
.len
) {
8610 m_copydata(packet
, hlen
, sizeof(th
), (u_int8_t
*)&th
);
8611 ((struct sockaddr_in
*)&local_addr
)->sin_port
= th
.th_sport
;
8612 ((struct sockaddr_in
*)&remote_addr
)->sin_port
= th
.th_dport
;
8618 if ((int)(hlen
+ sizeof(uh
)) <= packet
->m_pkthdr
.len
) {
8619 m_copydata(packet
, hlen
, sizeof(uh
), (u_int8_t
*)&uh
);
8620 ((struct sockaddr_in
*)&local_addr
)->sin_port
= uh
.uh_sport
;
8621 ((struct sockaddr_in
*)&remote_addr
)->sin_port
= uh
.uh_dport
;
8626 ((struct sockaddr_in
*)&local_addr
)->sin_port
= 0;
8627 ((struct sockaddr_in
*)&remote_addr
)->sin_port
= 0;
8632 // Match packet to policy
8633 lck_rw_lock_shared(&necp_kernel_policy_lock
);
8634 u_int32_t route_rule_id
= 0;
8635 matched_policy
= necp_ip_output_find_policy_match_locked(socket_policy_id
, socket_skip_policy_id
, bound_interface_index
, last_interface_index
, protocol
, &local_addr
, &remote_addr
, rt
, pf_tag
, &route_rule_id
, &drop_dest_policy_result
, &drop_all_bypass
);
8636 if (matched_policy
) {
8637 matched_policy_id
= matched_policy
->id
;
8639 *result
= matched_policy
->result
;
8642 if (result_parameter
) {
8643 memcpy(result_parameter
, &matched_policy
->result_parameter
, sizeof(matched_policy
->result_parameter
));
8646 if (route_rule_id
!= 0 &&
8647 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
== 0) {
8648 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
= route_rule_id
;
8651 if (necp_debug
> 1) {
8652 NECPLOG(LOG_DEBUG
, "IP Output: (ID %d BoundInterface %d LastInterface %d Proto %d) Policy %d Result %d Parameter %d Route Rule %u", socket_policy_id
, bound_interface_index
, last_interface_index
, protocol
, matched_policy
->id
, matched_policy
->result
, matched_policy
->result_parameter
.tunnel_interface_index
, route_rule_id
);
8655 bool drop_all
= false;
8657 * Apply drop-all only to packets which have never matched a primary policy (check
8658 * if the packet saved policy id is none or falls within the socket policy id range).
8660 if (socket_policy_id
< NECP_KERNEL_POLICY_ID_FIRST_VALID_IP
&&
8661 (necp_drop_all_order
> 0 || drop_dest_policy_result
== NECP_KERNEL_POLICY_RESULT_DROP
)) {
8663 if (drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
) {
8664 drop_all_bypass
= necp_check_drop_all_bypass_result(NULL
);
8667 if (drop_all
&& drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
) {
8668 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8670 *result
= NECP_KERNEL_POLICY_RESULT_DROP
;
8672 } else if (route_rule_id
!= 0 &&
8673 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
== 0) {
8674 // If we matched a route rule, mark it
8675 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
= route_rule_id
;
8679 lck_rw_done(&necp_kernel_policy_lock
);
8681 return matched_policy_id
;
8684 necp_kernel_policy_id
8685 necp_ip6_output_find_policy_match(struct mbuf
*packet
, int flags
, struct ip6_out_args
*ip6oa
, struct rtentry
*rt
,
8686 necp_kernel_policy_result
*result
, necp_kernel_policy_result_parameter
*result_parameter
)
8688 struct ip6_hdr
*ip6
= NULL
;
8691 necp_kernel_policy_id socket_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
8692 necp_kernel_policy_id socket_skip_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
8693 necp_kernel_policy_id matched_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
8694 struct necp_kernel_ip_output_policy
*matched_policy
= NULL
;
8695 u_int16_t protocol
= 0;
8696 u_int32_t bound_interface_index
= 0;
8697 u_int32_t last_interface_index
= 0;
8698 union necp_sockaddr_union local_addr
;
8699 union necp_sockaddr_union remote_addr
;
8700 u_int32_t drop_dest_policy_result
= NECP_KERNEL_POLICY_RESULT_NONE
;
8701 necp_drop_all_bypass_check_result_t drop_all_bypass
= NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
;
8702 u_int16_t pf_tag
= 0;
8708 if (result_parameter
) {
8709 memset(result_parameter
, 0, sizeof(*result_parameter
));
8712 if (packet
== NULL
) {
8713 return NECP_KERNEL_POLICY_ID_NONE
;
8716 socket_policy_id
= necp_get_policy_id_from_packet(packet
);
8717 socket_skip_policy_id
= necp_get_skip_policy_id_from_packet(packet
);
8718 pf_tag
= necp_get_packet_filter_tags_from_packet(packet
);
8720 // Exit early for an empty list
8721 // Don't lock. Possible race condition, but we don't want the performance hit.
8722 if (necp_kernel_ip_output_policies_count
== 0 ||
8723 (socket_policy_id
== NECP_KERNEL_POLICY_ID_NONE
&& necp_kernel_ip_output_policies_non_id_count
== 0 && necp_drop_dest_policy
.entry_count
== 0)) {
8724 if (necp_drop_all_order
> 0) {
8725 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8727 if (necp_output_bypass(packet
)) {
8728 *result
= NECP_KERNEL_POLICY_RESULT_PASS
;
8730 *result
= NECP_KERNEL_POLICY_RESULT_DROP
;
8735 return matched_policy_id
;
8738 // Check for loopback exception
8739 if (necp_output_bypass(packet
)) {
8740 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8742 *result
= NECP_KERNEL_POLICY_RESULT_PASS
;
8744 return matched_policy_id
;
8747 last_interface_index
= necp_get_last_interface_index_from_packet(packet
);
8749 // Process packet to get relevant fields
8750 ip6
= mtod(packet
, struct ip6_hdr
*);
8752 if ((flags
& IPV6_OUTARGS
) && (ip6oa
!= NULL
) &&
8753 (ip6oa
->ip6oa_flags
& IP6OAF_BOUND_IF
) &&
8754 ip6oa
->ip6oa_boundif
!= IFSCOPE_NONE
) {
8755 bound_interface_index
= ip6oa
->ip6oa_boundif
;
8758 ((struct sockaddr_in6
*)&local_addr
)->sin6_family
= AF_INET6
;
8759 ((struct sockaddr_in6
*)&local_addr
)->sin6_len
= sizeof(struct sockaddr_in6
);
8760 memcpy(&((struct sockaddr_in6
*)&local_addr
)->sin6_addr
, &ip6
->ip6_src
, sizeof(ip6
->ip6_src
));
8762 ((struct sockaddr_in6
*)&remote_addr
)->sin6_family
= AF_INET6
;
8763 ((struct sockaddr_in6
*)&remote_addr
)->sin6_len
= sizeof(struct sockaddr_in6
);
8764 memcpy(&((struct sockaddr_in6
*)&remote_addr
)->sin6_addr
, &ip6
->ip6_dst
, sizeof(ip6
->ip6_dst
));
8766 offset
= ip6_lasthdr(packet
, 0, IPPROTO_IPV6
, &next
);
8767 if (offset
>= 0 && packet
->m_pkthdr
.len
>= offset
) {
8772 if ((int)(offset
+ sizeof(th
)) <= packet
->m_pkthdr
.len
) {
8773 m_copydata(packet
, offset
, sizeof(th
), (u_int8_t
*)&th
);
8774 ((struct sockaddr_in6
*)&local_addr
)->sin6_port
= th
.th_sport
;
8775 ((struct sockaddr_in6
*)&remote_addr
)->sin6_port
= th
.th_dport
;
8781 if ((int)(offset
+ sizeof(uh
)) <= packet
->m_pkthdr
.len
) {
8782 m_copydata(packet
, offset
, sizeof(uh
), (u_int8_t
*)&uh
);
8783 ((struct sockaddr_in6
*)&local_addr
)->sin6_port
= uh
.uh_sport
;
8784 ((struct sockaddr_in6
*)&remote_addr
)->sin6_port
= uh
.uh_dport
;
8789 ((struct sockaddr_in6
*)&local_addr
)->sin6_port
= 0;
8790 ((struct sockaddr_in6
*)&remote_addr
)->sin6_port
= 0;
8796 // Match packet to policy
8797 lck_rw_lock_shared(&necp_kernel_policy_lock
);
8798 u_int32_t route_rule_id
= 0;
8799 matched_policy
= necp_ip_output_find_policy_match_locked(socket_policy_id
, socket_skip_policy_id
, bound_interface_index
, last_interface_index
, protocol
, &local_addr
, &remote_addr
, rt
, pf_tag
, &route_rule_id
, &drop_dest_policy_result
, &drop_all_bypass
);
8800 if (matched_policy
) {
8801 matched_policy_id
= matched_policy
->id
;
8803 *result
= matched_policy
->result
;
8806 if (result_parameter
) {
8807 memcpy(result_parameter
, &matched_policy
->result_parameter
, sizeof(matched_policy
->result_parameter
));
8810 if (route_rule_id
!= 0 &&
8811 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
== 0) {
8812 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
= route_rule_id
;
8815 if (necp_debug
> 1) {
8816 NECPLOG(LOG_DEBUG
, "IP6 Output: (ID %d BoundInterface %d LastInterface %d Proto %d) Policy %d Result %d Parameter %d Route Rule %u", socket_policy_id
, bound_interface_index
, last_interface_index
, protocol
, matched_policy
->id
, matched_policy
->result
, matched_policy
->result_parameter
.tunnel_interface_index
, route_rule_id
);
8819 bool drop_all
= false;
8821 * Apply drop-all only to packets which have never matched a primary policy (check
8822 * if the packet saved policy id is none or falls within the socket policy id range).
8824 if (socket_policy_id
< NECP_KERNEL_POLICY_ID_FIRST_VALID_IP
&&
8825 (necp_drop_all_order
> 0 || drop_dest_policy_result
== NECP_KERNEL_POLICY_RESULT_DROP
)) {
8827 if (drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
) {
8828 drop_all_bypass
= necp_check_drop_all_bypass_result(NULL
);
8831 if (drop_all
&& drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
) {
8832 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8834 *result
= NECP_KERNEL_POLICY_RESULT_DROP
;
8836 } else if (route_rule_id
!= 0 &&
8837 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
== 0) {
8838 // If we matched a route rule, mark it
8839 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
= route_rule_id
;
8843 lck_rw_done(&necp_kernel_policy_lock
);
8845 return matched_policy_id
;
8850 necp_is_addr_in_range(struct sockaddr
*addr
, struct sockaddr
*range_start
, struct sockaddr
*range_end
)
8854 if (addr
== NULL
|| range_start
== NULL
|| range_end
== NULL
) {
8858 /* Must be greater than or equal to start */
8859 cmp
= necp_addr_compare(addr
, range_start
, 1);
8860 if (cmp
!= 0 && cmp
!= 1) {
8864 /* Must be less than or equal to end */
8865 cmp
= necp_addr_compare(addr
, range_end
, 1);
8866 if (cmp
!= 0 && cmp
!= -1) {
8874 necp_is_range_in_range(struct sockaddr
*inner_range_start
, struct sockaddr
*inner_range_end
, struct sockaddr
*range_start
, struct sockaddr
*range_end
)
8878 if (inner_range_start
== NULL
|| inner_range_end
== NULL
|| range_start
== NULL
|| range_end
== NULL
) {
8882 /* Must be greater than or equal to start */
8883 cmp
= necp_addr_compare(inner_range_start
, range_start
, 1);
8884 if (cmp
!= 0 && cmp
!= 1) {
8888 /* Must be less than or equal to end */
8889 cmp
= necp_addr_compare(inner_range_end
, range_end
, 1);
8890 if (cmp
!= 0 && cmp
!= -1) {
8898 necp_is_addr_in_subnet(struct sockaddr
*addr
, struct sockaddr
*subnet_addr
, u_int8_t subnet_prefix
)
8900 if (addr
== NULL
|| subnet_addr
== NULL
) {
8904 if (addr
->sa_family
!= subnet_addr
->sa_family
|| addr
->sa_len
!= subnet_addr
->sa_len
) {
8908 switch (addr
->sa_family
) {
8910 if (satosin(subnet_addr
)->sin_port
!= 0 &&
8911 satosin(addr
)->sin_port
!= satosin(subnet_addr
)->sin_port
) {
8914 return necp_buffer_compare_with_bit_prefix((u_int8_t
*)&satosin(addr
)->sin_addr
, (u_int8_t
*)&satosin(subnet_addr
)->sin_addr
, subnet_prefix
);
8917 if (satosin6(subnet_addr
)->sin6_port
!= 0 &&
8918 satosin6(addr
)->sin6_port
!= satosin6(subnet_addr
)->sin6_port
) {
8921 if (satosin6(addr
)->sin6_scope_id
&&
8922 satosin6(subnet_addr
)->sin6_scope_id
&&
8923 satosin6(addr
)->sin6_scope_id
!= satosin6(subnet_addr
)->sin6_scope_id
) {
8926 return necp_buffer_compare_with_bit_prefix((u_int8_t
*)&satosin6(addr
)->sin6_addr
, (u_int8_t
*)&satosin6(subnet_addr
)->sin6_addr
, subnet_prefix
);
8941 * 2: Not comparable or error
8944 necp_addr_compare(struct sockaddr
*sa1
, struct sockaddr
*sa2
, int check_port
)
8947 int port_result
= 0;
8949 if (sa1
->sa_family
!= sa2
->sa_family
|| sa1
->sa_len
!= sa2
->sa_len
) {
8953 if (sa1
->sa_len
== 0) {
8957 switch (sa1
->sa_family
) {
8959 if (sa1
->sa_len
!= sizeof(struct sockaddr_in
)) {
8963 result
= memcmp(&satosin(sa1
)->sin_addr
.s_addr
, &satosin(sa2
)->sin_addr
.s_addr
, sizeof(satosin(sa1
)->sin_addr
.s_addr
));
8966 if (satosin(sa1
)->sin_port
< satosin(sa2
)->sin_port
) {
8968 } else if (satosin(sa1
)->sin_port
> satosin(sa2
)->sin_port
) {
8973 result
= port_result
;
8974 } else if ((result
> 0 && port_result
< 0) || (result
< 0 && port_result
> 0)) {
8982 if (sa1
->sa_len
!= sizeof(struct sockaddr_in6
)) {
8986 if (satosin6(sa1
)->sin6_scope_id
!= satosin6(sa2
)->sin6_scope_id
) {
8990 result
= memcmp(&satosin6(sa1
)->sin6_addr
.s6_addr
[0], &satosin6(sa2
)->sin6_addr
.s6_addr
[0], sizeof(struct in6_addr
));
8993 if (satosin6(sa1
)->sin6_port
< satosin6(sa2
)->sin6_port
) {
8995 } else if (satosin6(sa1
)->sin6_port
> satosin6(sa2
)->sin6_port
) {
9000 result
= port_result
;
9001 } else if ((result
> 0 && port_result
< 0) || (result
< 0 && port_result
> 0)) {
9009 result
= memcmp(sa1
, sa2
, sa1
->sa_len
);
9016 } else if (result
> 0) {
9024 necp_buffer_compare_with_bit_prefix(u_int8_t
*p1
, u_int8_t
*p2
, u_int32_t bits
)
9028 /* Handle null pointers */
9029 if (p1
== NULL
|| p2
== NULL
) {
9034 if (*p1
++ != *p2
++) {
9041 mask
= ~((1 << (8 - bits
)) - 1);
9042 if ((*p1
& mask
) != (*p2
& mask
)) {
9050 necp_addr_is_empty(struct sockaddr
*addr
)
9056 if (addr
->sa_len
== 0) {
9060 switch (addr
->sa_family
) {
9062 static struct sockaddr_in ipv4_empty_address
= {
9063 .sin_len
= sizeof(struct sockaddr_in
),
9064 .sin_family
= AF_INET
,
9066 .sin_addr
= { .s_addr
= 0 }, // 0.0.0.0
9069 if (necp_addr_compare(addr
, (struct sockaddr
*)&ipv4_empty_address
, 0) == 0) {
9076 static struct sockaddr_in6 ipv6_empty_address
= {
9077 .sin6_len
= sizeof(struct sockaddr_in6
),
9078 .sin6_family
= AF_INET6
,
9081 .sin6_addr
= IN6ADDR_ANY_INIT
, // ::
9084 if (necp_addr_compare(addr
, (struct sockaddr
*)&ipv6_empty_address
, 0) == 0) {
9098 necp_update_qos_marking(struct ifnet
*ifp
, u_int32_t route_rule_id
)
9100 bool qos_marking
= FALSE
;
9101 int exception_index
= 0;
9102 struct necp_route_rule
*route_rule
= NULL
;
9104 route_rule
= necp_lookup_route_rule_locked(&necp_route_rules
, route_rule_id
);
9105 if (route_rule
== NULL
) {
9106 qos_marking
= FALSE
;
9110 qos_marking
= (route_rule
->default_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? TRUE
: FALSE
;
9116 for (exception_index
= 0; exception_index
< MAX_ROUTE_RULE_INTERFACES
; exception_index
++) {
9117 if (route_rule
->exception_if_indices
[exception_index
] == 0) {
9120 if (route_rule
->exception_if_actions
[exception_index
] != NECP_ROUTE_RULE_QOS_MARKING
) {
9123 if (route_rule
->exception_if_indices
[exception_index
] == ifp
->if_index
) {
9125 if (necp_debug
> 2) {
9126 NECPLOG(LOG_DEBUG
, "QoS Marking : Interface match %d for Rule %d Allowed %d",
9127 route_rule
->exception_if_indices
[exception_index
], route_rule_id
, qos_marking
);
9133 if ((route_rule
->cellular_action
== NECP_ROUTE_RULE_QOS_MARKING
&& IFNET_IS_CELLULAR(ifp
)) ||
9134 (route_rule
->wifi_action
== NECP_ROUTE_RULE_QOS_MARKING
&& IFNET_IS_WIFI(ifp
)) ||
9135 (route_rule
->wired_action
== NECP_ROUTE_RULE_QOS_MARKING
&& IFNET_IS_WIRED(ifp
)) ||
9136 (route_rule
->expensive_action
== NECP_ROUTE_RULE_QOS_MARKING
&& IFNET_IS_EXPENSIVE(ifp
)) ||
9137 (route_rule
->constrained_action
== NECP_ROUTE_RULE_QOS_MARKING
&& IFNET_IS_CONSTRAINED(ifp
))) {
9139 if (necp_debug
> 2) {
9140 NECPLOG(LOG_DEBUG
, "QoS Marking: C:%d WF:%d W:%d E:%d Cn:%d for Rule %d Allowed %d",
9141 route_rule
->cellular_action
, route_rule
->wifi_action
, route_rule
->wired_action
,
9142 route_rule
->expensive_action
, route_rule
->constrained_action
, route_rule_id
, qos_marking
);
9147 if (necp_debug
> 1) {
9148 NECPLOG(LOG_DEBUG
, "QoS Marking: Rule %d ifp %s Allowed %d",
9149 route_rule_id
, ifp
? ifp
->if_xname
: "", qos_marking
);
9155 necp_lookup_current_qos_marking(int32_t *qos_marking_gencount
, struct rtentry
*route
, struct ifnet
*interface
, u_int32_t route_rule_id
, bool old_qos_marking
)
9157 bool new_qos_marking
= old_qos_marking
;
9158 struct ifnet
*ifp
= interface
;
9160 if (net_qos_policy_restricted
== 0) {
9161 return new_qos_marking
;
9165 * This is racy but we do not need the performance hit of taking necp_kernel_policy_lock
9167 if (*qos_marking_gencount
== necp_kernel_socket_policies_gencount
) {
9168 return new_qos_marking
;
9171 lck_rw_lock_shared(&necp_kernel_policy_lock
);
9173 if (ifp
== NULL
&& route
!= NULL
) {
9174 ifp
= route
->rt_ifp
;
9177 * By default, until we have a interface, do not mark and reevaluate the Qos marking policy
9179 if (ifp
== NULL
|| route_rule_id
== 0) {
9180 new_qos_marking
= FALSE
;
9184 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id
)) {
9185 struct necp_aggregate_route_rule
*aggregate_route_rule
= necp_lookup_aggregate_route_rule_locked(route_rule_id
);
9186 if (aggregate_route_rule
!= NULL
) {
9188 for (index
= 0; index
< MAX_AGGREGATE_ROUTE_RULES
; index
++) {
9189 u_int32_t sub_route_rule_id
= aggregate_route_rule
->rule_ids
[index
];
9190 if (sub_route_rule_id
== 0) {
9193 new_qos_marking
= necp_update_qos_marking(ifp
, sub_route_rule_id
);
9194 if (new_qos_marking
== TRUE
) {
9200 new_qos_marking
= necp_update_qos_marking(ifp
, route_rule_id
);
9203 * Now that we have an interface we remember the gencount
9205 *qos_marking_gencount
= necp_kernel_socket_policies_gencount
;
9208 lck_rw_done(&necp_kernel_policy_lock
);
9209 return new_qos_marking
;
9213 necp_socket_update_qos_marking(struct inpcb
*inp
, struct rtentry
*route
, u_int32_t route_rule_id
)
9215 bool qos_marking
= inp
->inp_socket
->so_flags1
& SOF1_QOSMARKING_ALLOWED
? TRUE
: FALSE
;
9217 if (net_qos_policy_restricted
== 0) {
9220 if (inp
->inp_socket
== NULL
) {
9223 if ((inp
->inp_socket
->so_flags1
& SOF1_QOSMARKING_POLICY_OVERRIDE
)) {
9227 qos_marking
= necp_lookup_current_qos_marking(&(inp
->inp_policyresult
.results
.qos_marking_gencount
), route
, NULL
, route_rule_id
, qos_marking
);
9229 if (qos_marking
== TRUE
) {
9230 inp
->inp_socket
->so_flags1
|= SOF1_QOSMARKING_ALLOWED
;
9232 inp
->inp_socket
->so_flags1
&= ~SOF1_QOSMARKING_ALLOWED
;
9237 necp_route_is_lqm_abort(struct ifnet
*ifp
, struct ifnet
*delegated_ifp
)
9240 (ifp
->if_interface_state
.valid_bitmask
& IF_INTERFACE_STATE_LQM_STATE_VALID
) &&
9241 ifp
->if_interface_state
.lqm_state
== IFNET_LQM_THRESH_ABORT
) {
9244 if (delegated_ifp
!= NULL
&&
9245 (delegated_ifp
->if_interface_state
.valid_bitmask
& IF_INTERFACE_STATE_LQM_STATE_VALID
) &&
9246 delegated_ifp
->if_interface_state
.lqm_state
== IFNET_LQM_THRESH_ABORT
) {
9253 necp_route_is_allowed_inner(struct rtentry
*route
, struct ifnet
*ifp
, u_int32_t route_rule_id
, u_int32_t
*interface_type_denied
)
9255 bool default_is_allowed
= TRUE
;
9256 u_int8_t type_aggregate_action
= NECP_ROUTE_RULE_NONE
;
9257 int exception_index
= 0;
9258 struct ifnet
*delegated_ifp
= NULL
;
9259 struct necp_route_rule
*route_rule
= NULL
;
9261 route_rule
= necp_lookup_route_rule_locked(&necp_route_rules
, route_rule_id
);
9262 if (route_rule
== NULL
) {
9266 default_is_allowed
= (route_rule
->default_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? FALSE
: TRUE
;
9268 ifp
= route
->rt_ifp
;
9271 if (necp_debug
> 1 && !default_is_allowed
) {
9272 NECPLOG(LOG_DEBUG
, "Route Allowed: No interface for route, using default for Rule %d Allowed %d", route_rule_id
, default_is_allowed
);
9274 return default_is_allowed
;
9277 delegated_ifp
= ifp
->if_delegated
.ifp
;
9278 for (exception_index
= 0; exception_index
< MAX_ROUTE_RULE_INTERFACES
; exception_index
++) {
9279 if (route_rule
->exception_if_indices
[exception_index
] == 0) {
9282 if (route_rule
->exception_if_indices
[exception_index
] == ifp
->if_index
||
9283 (delegated_ifp
!= NULL
&& route_rule
->exception_if_indices
[exception_index
] == delegated_ifp
->if_index
)) {
9284 if (route_rule
->exception_if_actions
[exception_index
] == NECP_ROUTE_RULE_DENY_LQM_ABORT
) {
9285 const bool lqm_abort
= necp_route_is_lqm_abort(ifp
, delegated_ifp
);
9286 if (necp_debug
> 1 && lqm_abort
) {
9287 NECPLOG(LOG_DEBUG
, "Route Allowed: Interface match %d for Rule %d Deny LQM Abort",
9288 route_rule
->exception_if_indices
[exception_index
], route_rule_id
);
9291 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->exception_if_actions
[exception_index
])) {
9292 if (necp_debug
> 1) {
9293 NECPLOG(LOG_DEBUG
, "Route Allowed: Interface match %d for Rule %d Allowed %d", route_rule
->exception_if_indices
[exception_index
], route_rule_id
, ((route_rule
->exception_if_actions
[exception_index
] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? FALSE
: TRUE
));
9295 return (route_rule
->exception_if_actions
[exception_index
] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? FALSE
: TRUE
;
9300 if (IFNET_IS_CELLULAR(ifp
)) {
9301 if (route_rule
->cellular_action
== NECP_ROUTE_RULE_DENY_LQM_ABORT
) {
9302 if (necp_route_is_lqm_abort(ifp
, delegated_ifp
)) {
9303 if (interface_type_denied
!= NULL
) {
9304 *interface_type_denied
= IFRTYPE_FUNCTIONAL_CELLULAR
;
9306 // Mark aggregate action as deny
9307 type_aggregate_action
= NECP_ROUTE_RULE_DENY_INTERFACE
;
9309 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->cellular_action
)) {
9310 if (interface_type_denied
!= NULL
) {
9311 *interface_type_denied
= IFRTYPE_FUNCTIONAL_CELLULAR
;
9313 if (type_aggregate_action
== NECP_ROUTE_RULE_NONE
||
9314 (type_aggregate_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
&&
9315 route_rule
->cellular_action
== NECP_ROUTE_RULE_DENY_INTERFACE
)) {
9316 // Deny wins if there is a conflict
9317 type_aggregate_action
= route_rule
->cellular_action
;
9322 if (IFNET_IS_WIFI(ifp
)) {
9323 if (route_rule
->wifi_action
== NECP_ROUTE_RULE_DENY_LQM_ABORT
) {
9324 if (necp_route_is_lqm_abort(ifp
, delegated_ifp
)) {
9325 if (interface_type_denied
!= NULL
) {
9326 *interface_type_denied
= IFRTYPE_FUNCTIONAL_WIFI_INFRA
;
9328 // Mark aggregate action as deny
9329 type_aggregate_action
= NECP_ROUTE_RULE_DENY_INTERFACE
;
9331 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->wifi_action
)) {
9332 if (interface_type_denied
!= NULL
) {
9333 *interface_type_denied
= IFRTYPE_FUNCTIONAL_WIFI_INFRA
;
9335 if (type_aggregate_action
== NECP_ROUTE_RULE_NONE
||
9336 (type_aggregate_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
&&
9337 route_rule
->wifi_action
== NECP_ROUTE_RULE_DENY_INTERFACE
)) {
9338 // Deny wins if there is a conflict
9339 type_aggregate_action
= route_rule
->wifi_action
;
9344 if (IFNET_IS_WIRED(ifp
)) {
9345 if (route_rule
->wired_action
== NECP_ROUTE_RULE_DENY_LQM_ABORT
) {
9346 if (necp_route_is_lqm_abort(ifp
, delegated_ifp
)) {
9347 if (interface_type_denied
!= NULL
) {
9348 *interface_type_denied
= IFRTYPE_FUNCTIONAL_WIRED
;
9350 // Mark aggregate action as deny
9351 type_aggregate_action
= NECP_ROUTE_RULE_DENY_INTERFACE
;
9353 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->wired_action
)) {
9354 if (interface_type_denied
!= NULL
) {
9355 *interface_type_denied
= IFRTYPE_FUNCTIONAL_WIRED
;
9357 if (type_aggregate_action
== NECP_ROUTE_RULE_NONE
||
9358 (type_aggregate_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
&&
9359 route_rule
->wired_action
== NECP_ROUTE_RULE_DENY_INTERFACE
)) {
9360 // Deny wins if there is a conflict
9361 type_aggregate_action
= route_rule
->wired_action
;
9366 if (IFNET_IS_EXPENSIVE(ifp
)) {
9367 if (route_rule
->expensive_action
== NECP_ROUTE_RULE_DENY_LQM_ABORT
) {
9368 if (necp_route_is_lqm_abort(ifp
, delegated_ifp
)) {
9369 // Mark aggregate action as deny
9370 type_aggregate_action
= NECP_ROUTE_RULE_DENY_INTERFACE
;
9372 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->expensive_action
)) {
9373 if (type_aggregate_action
== NECP_ROUTE_RULE_NONE
||
9374 (type_aggregate_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
&&
9375 route_rule
->expensive_action
== NECP_ROUTE_RULE_DENY_INTERFACE
)) {
9376 // Deny wins if there is a conflict
9377 type_aggregate_action
= route_rule
->expensive_action
;
9382 if (IFNET_IS_CONSTRAINED(ifp
)) {
9383 if (route_rule
->constrained_action
== NECP_ROUTE_RULE_DENY_LQM_ABORT
) {
9384 if (necp_route_is_lqm_abort(ifp
, delegated_ifp
)) {
9385 // Mark aggregate action as deny
9386 type_aggregate_action
= NECP_ROUTE_RULE_DENY_INTERFACE
;
9388 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->constrained_action
)) {
9389 if (type_aggregate_action
== NECP_ROUTE_RULE_NONE
||
9390 (type_aggregate_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
&&
9391 route_rule
->constrained_action
== NECP_ROUTE_RULE_DENY_INTERFACE
)) {
9392 // Deny wins if there is a conflict
9393 type_aggregate_action
= route_rule
->constrained_action
;
9398 if (type_aggregate_action
!= NECP_ROUTE_RULE_NONE
) {
9399 if (necp_debug
> 1) {
9400 NECPLOG(LOG_DEBUG
, "Route Allowed: C:%d WF:%d W:%d E:%d for Rule %d Allowed %d", route_rule
->cellular_action
, route_rule
->wifi_action
, route_rule
->wired_action
, route_rule
->expensive_action
, route_rule_id
, ((type_aggregate_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? FALSE
: TRUE
));
9402 return (type_aggregate_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? FALSE
: TRUE
;
9405 if (necp_debug
> 1 && !default_is_allowed
) {
9406 NECPLOG(LOG_DEBUG
, "Route Allowed: Using default for Rule %d Allowed %d", route_rule_id
, default_is_allowed
);
9408 return default_is_allowed
;
9412 necp_route_is_allowed(struct rtentry
*route
, struct ifnet
*interface
, u_int32_t route_rule_id
, u_int32_t
*interface_type_denied
)
9414 if ((route
== NULL
&& interface
== NULL
) || route_rule_id
== 0) {
9415 if (necp_debug
> 1) {
9416 NECPLOG(LOG_DEBUG
, "Route Allowed: no route or interface, Rule %d Allowed %d", route_rule_id
, TRUE
);
9421 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id
)) {
9422 struct necp_aggregate_route_rule
*aggregate_route_rule
= necp_lookup_aggregate_route_rule_locked(route_rule_id
);
9423 if (aggregate_route_rule
!= NULL
) {
9425 for (index
= 0; index
< MAX_AGGREGATE_ROUTE_RULES
; index
++) {
9426 u_int32_t sub_route_rule_id
= aggregate_route_rule
->rule_ids
[index
];
9427 if (sub_route_rule_id
== 0) {
9430 if (!necp_route_is_allowed_inner(route
, interface
, sub_route_rule_id
, interface_type_denied
)) {
9436 return necp_route_is_allowed_inner(route
, interface
, route_rule_id
, interface_type_denied
);
9443 necp_packet_is_allowed_over_interface(struct mbuf
*packet
, struct ifnet
*interface
)
9445 bool is_allowed
= TRUE
;
9446 u_int32_t route_rule_id
= necp_get_route_rule_id_from_packet(packet
);
9447 if (route_rule_id
!= 0 &&
9448 interface
!= NULL
) {
9449 lck_rw_lock_shared(&necp_kernel_policy_lock
);
9450 is_allowed
= necp_route_is_allowed(NULL
, interface
, necp_get_route_rule_id_from_packet(packet
), NULL
);
9451 lck_rw_done(&necp_kernel_policy_lock
);
9457 necp_netagents_allow_traffic(u_int32_t
*netagent_ids
, size_t netagent_id_count
)
9459 size_t netagent_cursor
;
9460 for (netagent_cursor
= 0; netagent_cursor
< netagent_id_count
; netagent_cursor
++) {
9461 struct necp_uuid_id_mapping
*mapping
= NULL
;
9462 u_int32_t netagent_id
= netagent_ids
[netagent_cursor
];
9463 if (netagent_id
== 0) {
9466 mapping
= necp_uuid_lookup_uuid_with_service_id_locked(netagent_id
);
9467 if (mapping
!= NULL
) {
9468 u_int32_t agent_flags
= 0;
9469 agent_flags
= netagent_get_flags(mapping
->uuid
);
9470 if (agent_flags
& NETAGENT_FLAG_REGISTERED
) {
9471 if (agent_flags
& NETAGENT_FLAG_ACTIVE
) {
9473 } else if ((agent_flags
& NETAGENT_FLAG_VOLUNTARY
) == 0) {
9483 necp_packet_filter_tags_receive(u_int16_t pf_tag
, u_int32_t pass_flags
)
9485 bool allowed_to_receive
= TRUE
;
9487 if (pf_tag
== PF_TAG_ID_STACK_DROP
&&
9488 (pass_flags
& NECP_KERNEL_POLICY_PASS_PF_TAG
) != NECP_KERNEL_POLICY_PASS_PF_TAG
) {
9489 allowed_to_receive
= FALSE
;
9492 return allowed_to_receive
;
9496 necp_socket_is_allowed_to_send_recv_internal(struct inpcb
*inp
, struct sockaddr
*override_local_addr
, struct sockaddr
*override_remote_addr
, ifnet_t interface
, u_int16_t pf_tag
, necp_kernel_policy_id
*return_policy_id
, u_int32_t
*return_route_rule_id
, necp_kernel_policy_id
*return_skip_policy_id
, u_int32_t
*return_pass_flags
)
9498 u_int32_t verifyifindex
= interface
? interface
->if_index
: 0;
9499 bool allowed_to_receive
= TRUE
;
9500 struct necp_socket_info info
;
9501 u_int32_t flowhash
= 0;
9502 necp_kernel_policy_result service_action
= 0;
9503 necp_kernel_policy_service service
= { 0, 0 };
9504 u_int32_t route_rule_id
= 0;
9505 struct rtentry
*route
= NULL
;
9506 u_int32_t interface_type_denied
= IFRTYPE_FUNCTIONAL_UNKNOWN
;
9507 necp_kernel_policy_result drop_dest_policy_result
= NECP_KERNEL_POLICY_RESULT_NONE
;
9508 necp_drop_all_bypass_check_result_t drop_all_bypass
= NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
;
9509 u_int32_t netagent_ids
[NECP_MAX_NETAGENTS
];
9510 proc_t socket_proc
= NULL
;
9511 necp_kernel_policy_filter filter_control_unit
= 0;
9512 u_int32_t pass_flags
= 0;
9513 u_int32_t flow_divert_aggregate_unit
= 0;
9515 memset(&netagent_ids
, 0, sizeof(netagent_ids
));
9517 if (return_policy_id
) {
9518 *return_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
9520 if (return_skip_policy_id
) {
9521 *return_skip_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
9523 if (return_route_rule_id
) {
9524 *return_route_rule_id
= 0;
9526 if (return_pass_flags
) {
9527 *return_pass_flags
= 0;
9534 route
= inp
->inp_route
.ro_rt
;
9536 struct socket
*so
= inp
->inp_socket
;
9538 u_int32_t drop_order
= necp_process_drop_order(so
->so_cred
);
9540 // Don't lock. Possible race condition, but we don't want the performance hit.
9541 if (necp_kernel_socket_policies_count
== 0 ||
9542 (!(inp
->inp_flags2
& INP2_WANT_APP_POLICY
) && necp_kernel_socket_policies_non_app_count
== 0)) {
9543 if (necp_drop_all_order
> 0 || drop_order
> 0) {
9544 if (necp_socket_bypass(override_local_addr
, override_remote_addr
, inp
)) {
9545 allowed_to_receive
= TRUE
;
9547 allowed_to_receive
= FALSE
;
9553 // If this socket is connected, or we are not taking addresses into account, try to reuse last result
9554 if ((necp_socket_is_connected(inp
) || (override_local_addr
== NULL
&& override_remote_addr
== NULL
)) && inp
->inp_policyresult
.policy_id
!= NECP_KERNEL_POLICY_ID_NONE
) {
9555 bool policies_have_changed
= FALSE
;
9556 bool route_allowed
= TRUE
;
9558 if (inp
->inp_policyresult
.policy_gencount
!= necp_kernel_socket_policies_gencount
) {
9559 policies_have_changed
= TRUE
;
9561 if (inp
->inp_policyresult
.results
.route_rule_id
!= 0) {
9562 lck_rw_lock_shared(&necp_kernel_policy_lock
);
9563 if (!necp_route_is_allowed(route
, interface
, inp
->inp_policyresult
.results
.route_rule_id
, &interface_type_denied
)) {
9564 route_allowed
= FALSE
;
9566 lck_rw_done(&necp_kernel_policy_lock
);
9570 if (!policies_have_changed
) {
9571 if (!route_allowed
||
9572 inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_DROP
||
9573 inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
||
9574 (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&& interface
&&
9575 inp
->inp_policyresult
.results
.result_parameter
.tunnel_interface_index
!= verifyifindex
)) {
9576 allowed_to_receive
= FALSE
;
9578 if (return_policy_id
) {
9579 *return_policy_id
= inp
->inp_policyresult
.policy_id
;
9581 if (return_skip_policy_id
) {
9582 *return_skip_policy_id
= inp
->inp_policyresult
.skip_policy_id
;
9584 if (return_route_rule_id
) {
9585 *return_route_rule_id
= inp
->inp_policyresult
.results
.route_rule_id
;
9587 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_PASS
) {
9588 pass_flags
= inp
->inp_policyresult
.results
.result_parameter
.pass_flags
;
9595 // Check for loopback exception
9596 if (necp_socket_bypass(override_local_addr
, override_remote_addr
, inp
)) {
9597 allowed_to_receive
= TRUE
;
9601 // Actually calculate policy result
9602 lck_rw_lock_shared(&necp_kernel_policy_lock
);
9603 necp_socket_fillout_info_locked(inp
, override_local_addr
, override_remote_addr
, 0, drop_order
, &socket_proc
, &info
);
9605 flowhash
= necp_socket_calc_flowhash_locked(&info
);
9606 if (inp
->inp_policyresult
.policy_id
!= NECP_KERNEL_POLICY_ID_NONE
&&
9607 inp
->inp_policyresult
.policy_gencount
== necp_kernel_socket_policies_gencount
&&
9608 inp
->inp_policyresult
.flowhash
== flowhash
) {
9609 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_DROP
||
9610 inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
||
9611 (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&& interface
&&
9612 inp
->inp_policyresult
.results
.result_parameter
.tunnel_interface_index
!= verifyifindex
) ||
9613 (inp
->inp_policyresult
.results
.route_rule_id
!= 0 &&
9614 !necp_route_is_allowed(route
, interface
, inp
->inp_policyresult
.results
.route_rule_id
, &interface_type_denied
))) {
9615 allowed_to_receive
= FALSE
;
9617 if (return_policy_id
) {
9618 *return_policy_id
= inp
->inp_policyresult
.policy_id
;
9620 if (return_route_rule_id
) {
9621 *return_route_rule_id
= inp
->inp_policyresult
.results
.route_rule_id
;
9623 if (return_skip_policy_id
) {
9624 *return_skip_policy_id
= inp
->inp_policyresult
.skip_policy_id
;
9626 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_PASS
) {
9627 pass_flags
= inp
->inp_policyresult
.results
.result_parameter
.pass_flags
;
9630 lck_rw_done(&necp_kernel_policy_lock
);
9634 u_int32_t route_rule_id_array
[MAX_AGGREGATE_ROUTE_RULES
];
9635 size_t route_rule_id_array_count
= 0;
9636 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
, &filter_control_unit
, route_rule_id_array
, &route_rule_id_array_count
, MAX_AGGREGATE_ROUTE_RULES
, &service_action
, &service
, netagent_ids
, NULL
, NECP_MAX_NETAGENTS
, NULL
, 0, socket_proc
? socket_proc
: current_proc(), pf_tag
, return_skip_policy_id
, inp
->inp_route
.ro_rt
, &drop_dest_policy_result
, &drop_all_bypass
, &flow_divert_aggregate_unit
);
9638 if (route_rule_id_array_count
== 1) {
9639 route_rule_id
= route_rule_id_array
[0];
9640 } else if (route_rule_id_array_count
> 1) {
9641 route_rule_id
= necp_create_aggregate_route_rule(route_rule_id_array
);
9644 bool send_local_network_denied_event
= false;
9645 if (matched_policy
!= NULL
) {
9646 if (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_DROP
&&
9647 matched_policy
->result_parameter
.drop_flags
& NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK
) {
9648 // Trigger the event that we dropped due to a local network policy
9649 send_local_network_denied_event
= true;
9652 if (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_DROP
||
9653 matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
||
9654 (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&& interface
&&
9655 matched_policy
->result_parameter
.tunnel_interface_index
!= verifyifindex
) ||
9656 ((service_action
== NECP_KERNEL_POLICY_RESULT_TRIGGER_SCOPED
||
9657 service_action
== NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED
) &&
9658 service
.identifier
!= 0 && service
.identifier
!= NECP_NULL_SERVICE_ID
) ||
9659 (route_rule_id
!= 0 &&
9660 !necp_route_is_allowed(route
, interface
, route_rule_id
, &interface_type_denied
)) ||
9661 !necp_netagents_allow_traffic(netagent_ids
, NECP_MAX_NETAGENTS
)) {
9662 allowed_to_receive
= FALSE
;
9664 if (return_policy_id
) {
9665 *return_policy_id
= matched_policy
->id
;
9667 if (return_route_rule_id
) {
9668 *return_route_rule_id
= route_rule_id
;
9670 if (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_PASS
) {
9671 pass_flags
= matched_policy
->result_parameter
.pass_flags
;
9673 // Polices has changed since last evaluation, update inp result with new filter state
9674 if (inp
->inp_policyresult
.results
.filter_control_unit
!= filter_control_unit
) {
9675 inp
->inp_policyresult
.results
.filter_control_unit
= filter_control_unit
;
9677 if (inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
!= flow_divert_aggregate_unit
) {
9678 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= flow_divert_aggregate_unit
;
9682 if (necp_debug
> 1 && matched_policy
->id
!= inp
->inp_policyresult
.policy_id
) {
9683 NECPLOG(LOG_DEBUG
, "Socket Send/Recv Policy: Policy %d Allowed %d", return_policy_id
? *return_policy_id
: 0, allowed_to_receive
);
9686 bool drop_all
= false;
9687 if (necp_drop_all_order
> 0 || info
.drop_order
> 0 || drop_dest_policy_result
== NECP_KERNEL_POLICY_RESULT_DROP
) {
9689 if (drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
) {
9690 drop_all_bypass
= necp_check_drop_all_bypass_result(socket_proc
? socket_proc
: current_proc());
9693 if (drop_all
&& drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
) {
9694 allowed_to_receive
= FALSE
;
9696 if (return_policy_id
) {
9697 *return_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
9699 if (return_route_rule_id
) {
9700 *return_route_rule_id
= route_rule_id
;
9703 // Polices has changed since last evaluation, update inp result with new filter state
9704 if (inp
->inp_policyresult
.results
.filter_control_unit
!= filter_control_unit
) {
9705 inp
->inp_policyresult
.results
.filter_control_unit
= filter_control_unit
;
9707 if (inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
!= flow_divert_aggregate_unit
) {
9708 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= flow_divert_aggregate_unit
;
9713 if (necp_check_restricted_multicast_drop(socket_proc
? socket_proc
: current_proc(), &info
, true)) {
9714 allowed_to_receive
= FALSE
;
9717 lck_rw_done(&necp_kernel_policy_lock
);
9719 if (send_local_network_denied_event
) {
9720 necp_send_network_denied_event(((so
->so_flags
& SOF_DELEGATED
) ? so
->e_pid
: so
->last_pid
),
9721 ((so
->so_flags
& SOF_DELEGATED
) ? so
->e_uuid
: so
->last_uuid
),
9722 NETPOLICY_NETWORKTYPE_LOCAL
);
9726 if (return_pass_flags
!= NULL
) {
9727 *return_pass_flags
= pass_flags
;
9730 if (pf_tag
!= 0 && allowed_to_receive
) {
9731 allowed_to_receive
= necp_packet_filter_tags_receive(pf_tag
, pass_flags
);
9734 if (!allowed_to_receive
&& interface_type_denied
!= IFRTYPE_FUNCTIONAL_UNKNOWN
) {
9735 soevent(inp
->inp_socket
, (SO_FILT_HINT_LOCKED
| SO_FILT_HINT_IFDENIED
));
9739 proc_rele(socket_proc
);
9742 return allowed_to_receive
;
9746 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
, u_int16_t pf_tag
, necp_kernel_policy_id
*return_policy_id
, u_int32_t
*return_route_rule_id
, necp_kernel_policy_id
*return_skip_policy_id
, u_int32_t
*return_pass_flags
)
9748 struct sockaddr_in local
= {};
9749 struct sockaddr_in remote
= {};
9750 local
.sin_family
= remote
.sin_family
= AF_INET
;
9751 local
.sin_len
= remote
.sin_len
= sizeof(struct sockaddr_in
);
9752 local
.sin_port
= local_port
;
9753 remote
.sin_port
= remote_port
;
9754 memcpy(&local
.sin_addr
, local_addr
, sizeof(local
.sin_addr
));
9755 memcpy(&remote
.sin_addr
, remote_addr
, sizeof(remote
.sin_addr
));
9757 return necp_socket_is_allowed_to_send_recv_internal(inp
, (struct sockaddr
*)&local
, (struct sockaddr
*)&remote
, interface
,
9758 pf_tag
, return_policy_id
, return_route_rule_id
, return_skip_policy_id
, return_pass_flags
);
9762 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
, u_int16_t pf_tag
, necp_kernel_policy_id
*return_policy_id
, u_int32_t
*return_route_rule_id
, necp_kernel_policy_id
*return_skip_policy_id
, u_int32_t
*return_pass_flags
)
9764 struct sockaddr_in6 local
= {};
9765 struct sockaddr_in6 remote
= {};
9766 local
.sin6_family
= remote
.sin6_family
= AF_INET6
;
9767 local
.sin6_len
= remote
.sin6_len
= sizeof(struct sockaddr_in6
);
9768 local
.sin6_port
= local_port
;
9769 remote
.sin6_port
= remote_port
;
9770 memcpy(&local
.sin6_addr
, local_addr
, sizeof(local
.sin6_addr
));
9771 memcpy(&remote
.sin6_addr
, remote_addr
, sizeof(remote
.sin6_addr
));
9773 return necp_socket_is_allowed_to_send_recv_internal(inp
, (struct sockaddr
*)&local
, (struct sockaddr
*)&remote
, interface
,
9774 pf_tag
, return_policy_id
, return_route_rule_id
, return_skip_policy_id
, return_pass_flags
);
9778 necp_socket_is_allowed_to_send_recv(struct inpcb
*inp
, ifnet_t interface
, u_int16_t pf_tag
, necp_kernel_policy_id
*return_policy_id
,
9779 u_int32_t
*return_route_rule_id
, necp_kernel_policy_id
*return_skip_policy_id
, u_int32_t
*return_pass_flags
)
9781 return necp_socket_is_allowed_to_send_recv_internal(inp
, NULL
, NULL
, interface
, pf_tag
,
9782 return_policy_id
, return_route_rule_id
,
9783 return_skip_policy_id
, return_pass_flags
);
9787 necp_mark_packet_from_socket(struct mbuf
*packet
, struct inpcb
*inp
, necp_kernel_policy_id policy_id
, u_int32_t route_rule_id
,
9788 necp_kernel_policy_id skip_policy_id
, u_int32_t pass_flags
)
9790 if (packet
== NULL
|| inp
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
9794 // Mark ID for Pass and IP Tunnel
9795 if (policy_id
!= NECP_KERNEL_POLICY_ID_NONE
) {
9796 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= policy_id
;
9797 } else if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_PASS
||
9798 inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
) {
9799 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= inp
->inp_policyresult
.policy_id
;
9801 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
9803 packet
->m_pkthdr
.necp_mtag
.necp_last_interface_index
= 0;
9804 if (route_rule_id
!= 0) {
9805 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
= route_rule_id
;
9807 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
= inp
->inp_policyresult
.results
.route_rule_id
;
9809 packet
->m_pkthdr
.necp_mtag
.necp_app_id
= (inp
->inp_policyresult
.app_id
> UINT16_MAX
? (inp
->inp_policyresult
.app_id
- UINT16_MAX
) : inp
->inp_policyresult
.app_id
);
9811 if (skip_policy_id
!= NECP_KERNEL_POLICY_ID_NONE
&&
9812 skip_policy_id
!= NECP_KERNEL_POLICY_ID_NO_MATCH
) {
9813 // Only mark the skip policy if it is a valid policy ID
9814 packet
->m_pkthdr
.necp_mtag
.necp_skip_policy_id
= skip_policy_id
;
9815 } else if (inp
->inp_policyresult
.results
.filter_control_unit
== NECP_FILTER_UNIT_NO_FILTER
) {
9816 // Overload the meaning of "NECP_KERNEL_POLICY_ID_NO_MATCH"
9817 // to indicate that NECP_FILTER_UNIT_NO_FILTER was set
9818 // See necp_get_skip_policy_id_from_packet() and
9819 // necp_packet_should_skip_filters().
9820 packet
->m_pkthdr
.necp_mtag
.necp_skip_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
9822 packet
->m_pkthdr
.necp_mtag
.necp_skip_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
9825 if (((pass_flags
& NECP_KERNEL_POLICY_PASS_PF_TAG
) == NECP_KERNEL_POLICY_PASS_PF_TAG
) ||
9826 ((inp
->inp_policyresult
.results
.result_parameter
.pass_flags
& NECP_KERNEL_POLICY_PASS_PF_TAG
) == NECP_KERNEL_POLICY_PASS_PF_TAG
)) {
9827 m_pftag(packet
)->pftag_tag
= PF_TAG_ID_SYSTEM_SERVICE
;
9834 necp_mark_packet_from_ip(struct mbuf
*packet
, necp_kernel_policy_id policy_id
)
9836 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
9840 // Mark ID for Pass and IP Tunnel
9841 if (policy_id
!= NECP_KERNEL_POLICY_ID_NONE
) {
9842 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= policy_id
;
9844 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
9851 necp_mark_packet_from_interface(struct mbuf
*packet
, ifnet_t interface
)
9853 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
9857 // Mark ID for Pass and IP Tunnel
9858 if (interface
!= NULL
) {
9859 packet
->m_pkthdr
.necp_mtag
.necp_last_interface_index
= interface
->if_index
;
9866 necp_mark_packet_as_keepalive(struct mbuf
*packet
, bool is_keepalive
)
9868 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
9873 packet
->m_pkthdr
.pkt_flags
|= PKTF_KEEPALIVE
;
9875 packet
->m_pkthdr
.pkt_flags
&= ~PKTF_KEEPALIVE
;
9881 necp_kernel_policy_id
9882 necp_get_policy_id_from_packet(struct mbuf
*packet
)
9884 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
9885 return NECP_KERNEL_POLICY_ID_NONE
;
9888 return packet
->m_pkthdr
.necp_mtag
.necp_policy_id
;
9891 necp_kernel_policy_id
9892 necp_get_skip_policy_id_from_packet(struct mbuf
*packet
)
9894 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
9895 return NECP_KERNEL_POLICY_ID_NONE
;
9898 // Check for overloaded value. See necp_mark_packet_from_socket().
9899 if (packet
->m_pkthdr
.necp_mtag
.necp_skip_policy_id
== NECP_KERNEL_POLICY_ID_NO_MATCH
) {
9900 return NECP_KERNEL_POLICY_ID_NONE
;
9903 return packet
->m_pkthdr
.necp_mtag
.necp_skip_policy_id
;
9907 necp_get_packet_filter_tags_from_packet(struct mbuf
*packet
)
9909 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
9913 return m_pftag(packet
)->pftag_tag
;
9917 necp_packet_should_skip_filters(struct mbuf
*packet
)
9919 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
9923 // Check for overloaded value. See necp_mark_packet_from_socket().
9924 return packet
->m_pkthdr
.necp_mtag
.necp_skip_policy_id
== NECP_KERNEL_POLICY_ID_NO_MATCH
;
9928 necp_get_last_interface_index_from_packet(struct mbuf
*packet
)
9930 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
9934 return packet
->m_pkthdr
.necp_mtag
.necp_last_interface_index
;
9938 necp_get_route_rule_id_from_packet(struct mbuf
*packet
)
9940 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
9944 return packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
;
9948 necp_get_app_uuid_from_packet(struct mbuf
*packet
,
9951 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
9955 bool found_mapping
= FALSE
;
9956 if (packet
->m_pkthdr
.necp_mtag
.necp_app_id
!= 0) {
9957 lck_rw_lock_shared(&necp_kernel_policy_lock
);
9958 necp_app_id app_id
= (packet
->m_pkthdr
.necp_mtag
.necp_app_id
< UINT16_MAX
? (packet
->m_pkthdr
.necp_mtag
.necp_app_id
+ UINT16_MAX
) : packet
->m_pkthdr
.necp_mtag
.necp_app_id
);
9959 struct necp_uuid_id_mapping
*entry
= necp_uuid_lookup_uuid_with_app_id_locked(app_id
);
9960 if (entry
!= NULL
) {
9961 uuid_copy(app_uuid
, entry
->uuid
);
9962 found_mapping
= true;
9964 lck_rw_done(&necp_kernel_policy_lock
);
9966 if (!found_mapping
) {
9967 uuid_clear(app_uuid
);
9973 necp_get_is_keepalive_from_packet(struct mbuf
*packet
)
9975 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
9979 return packet
->m_pkthdr
.pkt_flags
& PKTF_KEEPALIVE
;
9983 necp_socket_get_content_filter_control_unit(struct socket
*so
)
9985 struct inpcb
*inp
= sotoinpcb(so
);
9990 return inp
->inp_policyresult
.results
.filter_control_unit
;
9994 necp_socket_should_use_flow_divert(struct inpcb
*inp
)
10000 return !(inp
->inp_socket
->so_flags1
& SOF1_FLOW_DIVERT_SKIP
) &&
10001 (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
||
10002 (inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
!= 0));
10006 necp_socket_get_flow_divert_control_unit(struct inpcb
*inp
, uint32_t *aggregate_unit
)
10012 if (inp
->inp_socket
->so_flags1
& SOF1_FLOW_DIVERT_SKIP
) {
10016 if (aggregate_unit
!= NULL
&&
10017 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
!= 0) {
10018 *aggregate_unit
= inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
;
10021 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
) {
10022 return inp
->inp_policyresult
.results
.result_parameter
.flow_divert_control_unit
;
10029 necp_socket_should_rescope(struct inpcb
*inp
)
10035 return inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
||
10036 inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT
;
10040 necp_socket_get_rescope_if_index(struct inpcb
*inp
)
10046 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
) {
10047 return inp
->inp_policyresult
.results
.result_parameter
.scoped_interface_index
;
10048 } else if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT
) {
10049 return necp_get_primary_direct_interface_index();
10056 necp_socket_get_effective_mtu(struct inpcb
*inp
, u_int32_t current_mtu
)
10059 return current_mtu
;
10062 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&&
10063 (inp
->inp_flags
& INP_BOUND_IF
) &&
10064 inp
->inp_boundifp
) {
10065 u_int bound_interface_index
= inp
->inp_boundifp
->if_index
;
10066 u_int tunnel_interface_index
= inp
->inp_policyresult
.results
.result_parameter
.tunnel_interface_index
;
10068 // The result is IP Tunnel, and is rescoping from one interface to another. Recalculate MTU.
10069 if (bound_interface_index
!= tunnel_interface_index
) {
10070 ifnet_t tunnel_interface
= NULL
;
10072 ifnet_head_lock_shared();
10073 tunnel_interface
= ifindex2ifnet
[tunnel_interface_index
];
10076 if (tunnel_interface
!= NULL
) {
10077 u_int32_t direct_tunnel_mtu
= tunnel_interface
->if_mtu
;
10078 u_int32_t delegate_tunnel_mtu
= (tunnel_interface
->if_delegated
.ifp
!= NULL
) ? tunnel_interface
->if_delegated
.ifp
->if_mtu
: 0;
10079 if (delegate_tunnel_mtu
!= 0 &&
10080 strncmp(tunnel_interface
->if_name
, "ipsec", strlen("ipsec")) == 0) {
10081 // For ipsec interfaces, calculate the overhead from the delegate interface
10082 u_int32_t tunnel_overhead
= (u_int32_t
)(esp_hdrsiz(NULL
) + sizeof(struct ip6_hdr
));
10083 if (delegate_tunnel_mtu
> tunnel_overhead
) {
10084 delegate_tunnel_mtu
-= tunnel_overhead
;
10087 if (delegate_tunnel_mtu
< direct_tunnel_mtu
) {
10088 // If the (delegate - overhead) < direct, return (delegate - overhead)
10089 return delegate_tunnel_mtu
;
10091 // Otherwise return direct
10092 return direct_tunnel_mtu
;
10095 // For non-ipsec interfaces, just return the tunnel MTU
10096 return direct_tunnel_mtu
;
10102 // By default, just return the MTU passed in
10103 return current_mtu
;
10107 necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter
*result_parameter
)
10109 if (result_parameter
== NULL
) {
10113 return ifindex2ifnet
[result_parameter
->tunnel_interface_index
];
10117 necp_packet_can_rebind_to_ifnet(struct mbuf
*packet
, struct ifnet
*interface
, struct route
*new_route
, int family
)
10119 bool found_match
= FALSE
;
10120 errno_t result
= 0;
10121 ifaddr_t
*addresses
= NULL
;
10122 union necp_sockaddr_union address_storage
;
10125 if (packet
== NULL
|| interface
== NULL
|| new_route
== NULL
|| (family
!= AF_INET
&& family
!= AF_INET6
)) {
10129 result
= ifnet_get_address_list_family(interface
, &addresses
, family
);
10131 NECPLOG(LOG_ERR
, "Failed to get address list for %s%d", ifnet_name(interface
), ifnet_unit(interface
));
10135 for (i
= 0; addresses
[i
] != NULL
; i
++) {
10136 ROUTE_RELEASE(new_route
);
10137 if (ifaddr_address(addresses
[i
], &address_storage
.sa
, sizeof(address_storage
)) == 0) {
10138 if (family
== AF_INET
) {
10139 struct ip
*ip
= mtod(packet
, struct ip
*);
10140 if (memcmp(&address_storage
.sin
.sin_addr
, &ip
->ip_src
, sizeof(ip
->ip_src
)) == 0) {
10141 struct sockaddr_in
*dst4
= (struct sockaddr_in
*)(void *)&new_route
->ro_dst
;
10142 dst4
->sin_family
= AF_INET
;
10143 dst4
->sin_len
= sizeof(struct sockaddr_in
);
10144 dst4
->sin_addr
= ip
->ip_dst
;
10145 rtalloc_scoped(new_route
, interface
->if_index
);
10146 if (!ROUTE_UNUSABLE(new_route
)) {
10147 found_match
= TRUE
;
10151 } else if (family
== AF_INET6
) {
10152 struct ip6_hdr
*ip6
= mtod(packet
, struct ip6_hdr
*);
10153 if (memcmp(&address_storage
.sin6
.sin6_addr
, &ip6
->ip6_src
, sizeof(ip6
->ip6_src
)) == 0) {
10154 struct sockaddr_in6
*dst6
= (struct sockaddr_in6
*)(void *)&new_route
->ro_dst
;
10155 dst6
->sin6_family
= AF_INET6
;
10156 dst6
->sin6_len
= sizeof(struct sockaddr_in6
);
10157 dst6
->sin6_addr
= ip6
->ip6_dst
;
10158 rtalloc_scoped(new_route
, interface
->if_index
);
10159 if (!ROUTE_UNUSABLE(new_route
)) {
10160 found_match
= TRUE
;
10169 ifnet_free_address_list(addresses
);
10171 return found_match
;
10175 necp_addr_is_loopback(struct sockaddr
*address
)
10177 if (address
== NULL
) {
10181 if (address
->sa_family
== AF_INET
) {
10182 return ntohl(((struct sockaddr_in
*)(void *)address
)->sin_addr
.s_addr
) == INADDR_LOOPBACK
;
10183 } else if (address
->sa_family
== AF_INET6
) {
10184 return IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6
*)(void *)address
)->sin6_addr
);
10191 necp_is_loopback(struct sockaddr
*local_addr
, struct sockaddr
*remote_addr
, struct inpcb
*inp
, struct mbuf
*packet
, u_int32_t bound_interface_index
)
10193 // Note: This function only checks for the loopback addresses.
10194 // In the future, we may want to expand to also allow any traffic
10195 // going through the loopback interface, but until then, this
10196 // check is cheaper.
10198 if (local_addr
!= NULL
&& necp_addr_is_loopback(local_addr
)) {
10202 if (remote_addr
!= NULL
&& necp_addr_is_loopback(remote_addr
)) {
10207 if ((inp
->inp_flags
& INP_BOUND_IF
) && inp
->inp_boundifp
&& (inp
->inp_boundifp
->if_flags
& IFF_LOOPBACK
)) {
10210 if (inp
->inp_vflag
& INP_IPV4
) {
10211 if (ntohl(inp
->inp_laddr
.s_addr
) == INADDR_LOOPBACK
||
10212 ntohl(inp
->inp_faddr
.s_addr
) == INADDR_LOOPBACK
) {
10215 } else if (inp
->inp_vflag
& INP_IPV6
) {
10216 if (IN6_IS_ADDR_LOOPBACK(&inp
->in6p_laddr
) ||
10217 IN6_IS_ADDR_LOOPBACK(&inp
->in6p_faddr
)) {
10221 } else if (bound_interface_index
!= IFSCOPE_NONE
&& lo_ifp
->if_index
== bound_interface_index
) {
10225 if (packet
!= NULL
) {
10226 struct ip
*ip
= mtod(packet
, struct ip
*);
10227 if (ip
->ip_v
== 4) {
10228 if (ntohl(ip
->ip_src
.s_addr
) == INADDR_LOOPBACK
) {
10231 if (ntohl(ip
->ip_dst
.s_addr
) == INADDR_LOOPBACK
) {
10234 } else if (ip
->ip_v
== 6) {
10235 struct ip6_hdr
*ip6
= mtod(packet
, struct ip6_hdr
*);
10236 if (IN6_IS_ADDR_LOOPBACK(&ip6
->ip6_src
)) {
10239 if (IN6_IS_ADDR_LOOPBACK(&ip6
->ip6_dst
)) {
10249 necp_is_intcoproc(struct inpcb
*inp
, struct mbuf
*packet
)
10252 if (!(inp
->inp_vflag
& INP_IPV6
)) {
10255 if (INP_INTCOPROC_ALLOWED(inp
)) {
10258 if ((inp
->inp_flags
& INP_BOUND_IF
) &&
10259 IFNET_IS_INTCOPROC(inp
->inp_boundifp
)) {
10264 if (packet
!= NULL
) {
10265 struct ip6_hdr
*ip6
= mtod(packet
, struct ip6_hdr
*);
10266 if ((ip6
->ip6_vfc
& IPV6_VERSION_MASK
) == IPV6_VERSION
&&
10267 IN6_IS_ADDR_LINKLOCAL(&ip6
->ip6_dst
) &&
10268 ip6
->ip6_dst
.s6_addr32
[2] == ntohl(0xaede48ff) &&
10269 ip6
->ip6_dst
.s6_addr32
[3] == ntohl(0xfe334455)) {
10278 necp_address_matches_drop_dest_policy(union necp_sockaddr_union
*sau
, u_int32_t session_order
)
10280 char dest_str
[MAX_IPv6_STR_LEN
];
10282 if (necp_drop_dest_debug
> 0) {
10283 if (sau
->sa
.sa_family
== AF_INET
) {
10284 (void) inet_ntop(AF_INET
, &sau
->sin
.sin_addr
, dest_str
, sizeof(dest_str
));
10285 } else if (sau
->sa
.sa_family
== AF_INET6
) {
10286 (void) inet_ntop(AF_INET6
, &sau
->sin6
.sin6_addr
, dest_str
, sizeof(dest_str
));
10291 for (u_int32_t i
= 0; i
< necp_drop_dest_policy
.entry_count
; i
++) {
10292 struct necp_drop_dest_entry
*necp_drop_dest_entry
= &necp_drop_dest_policy
.entries
[i
];
10293 struct necp_policy_condition_addr
*npca
= &necp_drop_dest_entry
->cond_addr
;
10295 if (session_order
>= necp_drop_dest_entry
->order
&& necp_is_addr_in_subnet(&sau
->sa
, &npca
->address
.sa
, npca
->prefix
)) {
10296 if (necp_drop_dest_debug
> 0) {
10297 char subnet_str
[MAX_IPv6_STR_LEN
];
10298 struct proc
*p
= current_proc();
10299 pid_t pid
= proc_pid(p
);
10301 if (sau
->sa
.sa_family
== AF_INET
) {
10302 (void) inet_ntop(AF_INET
, &npca
->address
.sin
, subnet_str
, sizeof(subnet_str
));
10303 os_log(OS_LOG_DEFAULT
, "%s (process %s:%u) %s matches %s/%u", __func__
, proc_best_name(p
), pid
, dest_str
, subnet_str
, npca
->prefix
);
10304 } else if (sau
->sa
.sa_family
== AF_INET6
) {
10305 (void) inet_ntop(AF_INET6
, &npca
->address
.sin6
, subnet_str
, sizeof(subnet_str
));
10306 os_log(OS_LOG_DEFAULT
, "%s (process %s:%u) %s matches %s/%u", __func__
, proc_best_name(p
), pid
, dest_str
, subnet_str
, npca
->prefix
);
10312 if (necp_drop_dest_debug
> 1) {
10313 struct proc
*p
= current_proc();
10314 pid_t pid
= proc_pid(p
);
10316 os_log(OS_LOG_DEFAULT
, "%s (process %s:%u) %s no match", __func__
, proc_best_name(p
), pid
, dest_str
);
10322 sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS
10324 #pragma unused(arg1, arg2, oidp)
10327 struct necp_drop_dest_policy tmp_drop_dest_policy
;
10328 struct proc
*p
= current_proc();
10329 pid_t pid
= proc_pid(p
);
10331 if (req
->newptr
!= USER_ADDR_NULL
&& proc_suser(current_proc()) != 0 &&
10332 priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES
, 0) != 0) {
10333 NECPLOG(LOG_ERR
, "%s (process %s:%u) not permitted", __func__
, proc_best_name(p
), pid
);
10336 if (req
->newptr
!= USER_ADDR_NULL
&& req
->newlen
!= sizeof(struct necp_drop_dest_policy
)) {
10337 NECPLOG(LOG_ERR
, "%s (process %s:%u) bad newlen %lu", __func__
, proc_best_name(p
), pid
, req
->newlen
);
10341 memcpy(&tmp_drop_dest_policy
, &necp_drop_dest_policy
, sizeof(struct necp_drop_dest_policy
));
10342 error
= sysctl_io_opaque(req
, &tmp_drop_dest_policy
, sizeof(struct necp_drop_dest_policy
), &changed
);
10344 NECPLOG(LOG_ERR
, "%s (process %s:%u) sysctl_io_opaque() error %d", __func__
, proc_best_name(p
), pid
, error
);
10347 if (changed
== 0 || req
->newptr
== USER_ADDR_NULL
) {
10352 // Validate the passed parameters
10354 if (tmp_drop_dest_policy
.entry_count
>= MAX_NECP_DROP_DEST_LEVEL_ADDRS
) {
10355 NECPLOG(LOG_ERR
, "%s (process %s:%u) bad entry_count %u", __func__
, proc_best_name(p
), pid
, tmp_drop_dest_policy
.entry_count
);
10358 for (u_int32_t i
= 0; i
< tmp_drop_dest_policy
.entry_count
; i
++) {
10359 struct necp_drop_dest_entry
*tmp_drop_dest_entry
= &tmp_drop_dest_policy
.entries
[i
];
10360 struct necp_policy_condition_addr
*npca
= &tmp_drop_dest_entry
->cond_addr
;
10362 switch (tmp_drop_dest_entry
->level
) {
10363 case NECP_SESSION_PRIORITY_UNKNOWN
:
10364 if (tmp_drop_dest_policy
.entry_count
!= 0) {
10365 NECPLOG(LOG_ERR
, "%s (process %s:%u) NECP_SESSION_PRIORITY_UNKNOWN bad entry_count %u", __func__
, proc_best_name(p
), pid
, tmp_drop_dest_policy
.entry_count
);
10369 case NECP_SESSION_PRIORITY_CONTROL
:
10370 case NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL
:
10371 case NECP_SESSION_PRIORITY_HIGH
:
10372 case NECP_SESSION_PRIORITY_HIGH_1
:
10373 case NECP_SESSION_PRIORITY_HIGH_2
:
10374 case NECP_SESSION_PRIORITY_HIGH_3
:
10375 case NECP_SESSION_PRIORITY_HIGH_4
:
10376 case NECP_SESSION_PRIORITY_HIGH_RESTRICTED
:
10377 case NECP_SESSION_PRIORITY_DEFAULT
:
10378 case NECP_SESSION_PRIORITY_LOW
:
10379 if (tmp_drop_dest_policy
.entry_count
== 0) {
10380 NECPLOG(LOG_ERR
, "%s (process %s:%u) priority %u entry_count 0", __func__
, proc_best_name(p
), pid
, tmp_drop_dest_entry
->level
);
10385 NECPLOG(LOG_ERR
, "%s (process %s:%u) bad level %u", __func__
, proc_best_name(p
), pid
, tmp_drop_dest_entry
->level
);
10390 switch (npca
->address
.sa
.sa_family
) {
10392 if (npca
->prefix
> 32) {
10393 NECPLOG(LOG_ERR
, "%s (process %s:%u) AF_INET bad prefix %u", __func__
, proc_best_name(p
), pid
, npca
->prefix
);
10396 if (npca
->address
.sin
.sin_len
!= sizeof(struct sockaddr_in
)) {
10397 NECPLOG(LOG_ERR
, "%s (process %s:%u) AF_INET bad sin_len %u", __func__
, proc_best_name(p
), pid
, npca
->address
.sin
.sin_len
);
10400 if (npca
->address
.sin
.sin_port
!= 0) {
10401 NECPLOG(LOG_ERR
, "%s (process %s:%u) AF_INET bad sin_port %u, not zero", __func__
, proc_best_name(p
), pid
, npca
->address
.sin
.sin_port
);
10407 if (npca
->prefix
> 128) {
10408 NECPLOG(LOG_ERR
, "%s (process %s:%u) AF_INET6 bad prefix %u", __func__
, proc_best_name(p
), pid
, npca
->prefix
);
10411 if (npca
->address
.sin6
.sin6_len
!= sizeof(struct sockaddr_in6
)) {
10412 NECPLOG(LOG_ERR
, "%s (process %s:%u) AF_INET6 bad sin6_len %u", __func__
, proc_best_name(p
), pid
, npca
->address
.sin6
.sin6_len
);
10415 if (npca
->address
.sin6
.sin6_port
!= 0) {
10416 NECPLOG(LOG_ERR
, "%s (process %s:%u) AF_INET6 bad sin6_port %u, not zero", __func__
, proc_best_name(p
), pid
, npca
->address
.sin6
.sin6_port
);
10419 if (npca
->address
.sin6
.sin6_flowinfo
!= 0) {
10420 NECPLOG(LOG_ERR
, "%s (process %s:%u) AF_INET6 bad sin6_flowinfo %u, not zero", __func__
, proc_best_name(p
), pid
, npca
->address
.sin6
.sin6_flowinfo
);
10423 if (npca
->address
.sin6
.sin6_scope_id
!= 0) {
10424 NECPLOG(LOG_ERR
, "%s (process %s:%u) AF_INET6 bad sin6_scope_id %u, not zero", __func__
, proc_best_name(p
), pid
, npca
->address
.sin6
.sin6_scope_id
);
10436 // Commit the changed policy
10438 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
10439 memset(&necp_drop_dest_policy
, 0, sizeof(struct necp_drop_dest_policy
));
10441 necp_drop_dest_policy
.entry_count
= tmp_drop_dest_policy
.entry_count
;
10442 for (u_int32_t i
= 0; i
< tmp_drop_dest_policy
.entry_count
; i
++) {
10443 struct necp_drop_dest_entry
*tmp_drop_dest_entry
= &tmp_drop_dest_policy
.entries
[i
];
10444 struct necp_drop_dest_entry
*necp_drop_dest_entry
= &necp_drop_dest_policy
.entries
[i
];
10446 memcpy(necp_drop_dest_entry
, tmp_drop_dest_entry
, sizeof(struct necp_drop_dest_entry
));
10448 necp_drop_dest_entry
->order
= necp_get_first_order_for_priority(necp_drop_dest_entry
->level
);
10450 lck_rw_done(&necp_kernel_policy_lock
);