2  * Copyright (c) 2013-2021 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 <mach-o/loader.h> 
  71 #include <net/network_agent.h> 
  73 #include <netinet/flow_divert_proto.h> 
  76  * NECP - Network Extension Control Policy database 
  77  * ------------------------------------------------ 
  78  * The goal of this module is to allow clients connecting via a 
  79  * policy file descriptor to create high-level policy sessions, which 
  80  * are ingested into low-level kernel policies that control and tag 
  81  * traffic at the application, socket, and IP layers. 
  83  * ------------------------------------------------ 
  85  * ------------------------------------------------ 
  86  * Each session owns a list of session policies, each of which can 
  87  * specify any combination of conditions and a single result. Each 
  88  * session also has a priority level (such as High, Default, or Low) 
  89  * which is requested by the client. Based on the requested level, 
  90  * a session order value is assigned to the session, which will be used 
  91  * to sort kernel policies generated by the session. The session client 
  92  * can specify the sub-order for each policy it creates which will be 
  93  * used to further sort the kernel policies. 
  95  *  Policy fd --> 1 necp_session --> list of necp_session_policy structs 
  97  * ------------------------------------------------ 
  99  * ------------------------------------------------ 
 100  * Whenever a session send the Apply command, its policies are ingested 
 101  * and generate kernel policies. There are two phases of kernel policy 
 104  * 1. The session policy is parsed to create kernel policies at the socket 
 105  *        and IP layers, when applicable. For example, a policy that requires 
 106  *    all traffic from App1 to Pass will generate a socket kernel policy to 
 107  *    match App1 and mark packets with ID1, and also an IP policy to match 
 108  *    ID1 and let the packet pass. This is handled in necp_apply_policy. The 
 109  *    resulting kernel policies are added to the global socket and IP layer 
 111  *  necp_session_policy --> necp_kernel_socket_policy and necp_kernel_ip_output_policy 
 114  *                          necp_kernel_socket_policies   necp_kernel_ip_output_policies 
 116  * 2. Once the global lists of kernel policies have been filled out, each 
 117  *    list is traversed to create optimized sub-lists ("Maps") which are used during 
 118  *    data-path evaluation. IP policies are sent into necp_kernel_ip_output_policies_map, 
 119  *    which hashes incoming packets based on marked socket-layer policies, and removes 
 120  *    duplicate or overlapping policies. Socket policies are sent into two maps, 
 121  *    necp_kernel_socket_policies_map and necp_kernel_socket_policies_app_layer_map. 
 122  *    The app layer map is used for policy checks coming in from user space, and is one 
 123  *    list with duplicate and overlapping policies removed. The socket map hashes based 
 124  *    on app UUID, and removes duplicate and overlapping policies. 
 125  *  necp_kernel_socket_policy --> necp_kernel_socket_policies_app_layer_map 
 126  *                            |-> necp_kernel_socket_policies_map 
 128  *  necp_kernel_ip_output_policies --> necp_kernel_ip_output_policies_map 
 130  * ------------------------------------------------ 
 132  * ------------------------------------------------ 
 133  * The Drop All Level is a sysctl that controls the level at which policies are allowed 
 134  * to override a global drop rule. If the value is 0, no drop rule is applied. If the value 
 135  * is 1, all traffic is dropped. If the value is greater than 1, all kernel policies created 
 136  * by a session with a priority level better than (numerically less than) the 
 137  * Drop All Level will allow matching traffic to not be dropped. The Drop All Level is 
 138  * dynamically interpreted into necp_drop_all_order, which specifies the equivalent assigned 
 139  * session orders to be dropped. 
 142 u_int32_t necp_drop_all_order 
= 0; 
 143 u_int32_t necp_drop_all_level 
= 0; 
 145 u_int32_t necp_pass_loopback 
= NECP_LOOPBACK_PASS_ALL
; 
 146 u_int32_t necp_pass_keepalives 
= 1; // 0=Off, 1=On 
 147 u_int32_t necp_pass_interpose 
= 1; // 0=Off, 1=On 
 148 u_int32_t necp_restrict_multicast 
= 1; // 0=Off, 1=On 
 149 u_int32_t necp_dedup_policies 
= 0; // 0=Off, 1=On 
 151 u_int32_t necp_drop_unentitled_order 
= 0; 
 152 #ifdef XNU_TARGET_OS_WATCH 
 153 u_int32_t necp_drop_unentitled_level 
= NECP_SESSION_PRIORITY_CONTROL 
+ 1; // Block all unentitled traffic from policies below control level 
 154 #else // XNU_TARGET_OS_WATCH 
 155 u_int32_t necp_drop_unentitled_level 
= 0; 
 156 #endif // XNU_TARGET_OS_WATCH 
 158 u_int32_t necp_debug 
= 0; // 0=None, 1=Basic, 2=EveryMatch 
 160 os_log_t necp_log_handle 
= NULL
; 
 162 u_int32_t necp_session_count 
= 0; 
 164 ZONE_DECLARE(necp_session_policy_zone
, "necp_session_policy", 
 165     sizeof(struct necp_session_policy
), ZC_ZFREE_CLEARMEM 
| ZC_NOENCRYPT
); 
 166 ZONE_DECLARE(necp_socket_policy_zone
, "necp_socket_policy", 
 167     sizeof(struct necp_kernel_socket_policy
), ZC_ZFREE_CLEARMEM 
| ZC_NOENCRYPT
); 
 168 ZONE_DECLARE(necp_ip_policy_zone
, "necp_ip_policy", 
 169     sizeof(struct necp_kernel_ip_output_policy
), ZC_ZFREE_CLEARMEM 
| ZC_NOENCRYPT
); 
 171 #define LIST_INSERT_SORTED_ASCENDING(head, elm, field, sortfield, tmpelm) do {          \ 
 172         if (LIST_EMPTY((head)) || (LIST_FIRST(head)->sortfield >= (elm)->sortfield)) {  \ 
 173                 LIST_INSERT_HEAD((head), elm, field);                                                                           \ 
 175                 LIST_FOREACH(tmpelm, head, field) {                                                                                     \ 
 176                         if (LIST_NEXT(tmpelm, field) == NULL || LIST_NEXT(tmpelm, field)->sortfield >= (elm)->sortfield) {      \ 
 177                                 LIST_INSERT_AFTER(tmpelm, elm, field);                                                          \ 
 184 #define LIST_INSERT_SORTED_TWICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, tmpelm) do {      \ 
 185         if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield))) {                                                                                                               \ 
 186                 LIST_INSERT_HEAD((head), elm, field);                                                                           \ 
 188                 LIST_FOREACH(tmpelm, head, field) {                                                                                     \ 
 189                         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))) {         \ 
 190                                 LIST_INSERT_AFTER(tmpelm, elm, field);                                                          \ 
 197 #define LIST_INSERT_SORTED_THRICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, thirdsortfield, tmpelm) do { \ 
 198         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))) {                                                                                                                      \ 
 199                 LIST_INSERT_HEAD((head), elm, field);                                                                           \ 
 201                 LIST_FOREACH(tmpelm, head, field) {                                                                                     \ 
 202                         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)))  { \ 
 203                                 LIST_INSERT_AFTER(tmpelm, elm, field);                                                          \ 
 210 #define IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(x)     ((x) == NECP_ROUTE_RULE_DENY_INTERFACE || (x) == NECP_ROUTE_RULE_ALLOW_INTERFACE) 
 212 #define IS_NECP_DEST_IN_LOCAL_NETWORKS(rt) \ 
 213     ((rt) != NULL && !((rt)->rt_flags & RTF_GATEWAY) && ((rt)->rt_ifa && (rt)->rt_ifa->ifa_ifp && !((rt)->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT))) 
 215 #define NECP_KERNEL_CONDITION_ALL_INTERFACES            0x000001 
 216 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE           0x000002 
 217 #define NECP_KERNEL_CONDITION_PROTOCOL                          0x000004 
 218 #define NECP_KERNEL_CONDITION_LOCAL_START                       0x000008 
 219 #define NECP_KERNEL_CONDITION_LOCAL_END                         0x000010 
 220 #define NECP_KERNEL_CONDITION_LOCAL_PREFIX                      0x000020 
 221 #define NECP_KERNEL_CONDITION_REMOTE_START                      0x000040 
 222 #define NECP_KERNEL_CONDITION_REMOTE_END                        0x000080 
 223 #define NECP_KERNEL_CONDITION_REMOTE_PREFIX                     0x000100 
 224 #define NECP_KERNEL_CONDITION_APP_ID                            0x000200 
 225 #define NECP_KERNEL_CONDITION_REAL_APP_ID                       0x000400 
 226 #define NECP_KERNEL_CONDITION_DOMAIN                            0x000800 
 227 #define NECP_KERNEL_CONDITION_ACCOUNT_ID                        0x001000 
 228 #define NECP_KERNEL_CONDITION_POLICY_ID                         0x002000 
 229 #define NECP_KERNEL_CONDITION_PID                                       0x004000 
 230 #define NECP_KERNEL_CONDITION_UID                                       0x008000 
 231 #define NECP_KERNEL_CONDITION_LAST_INTERFACE            0x010000                        // Only set from packets looping between interfaces 
 232 #define NECP_KERNEL_CONDITION_TRAFFIC_CLASS                     0x020000 
 233 #define NECP_KERNEL_CONDITION_ENTITLEMENT                       0x040000 
 234 #define NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT        0x080000 
 235 #define NECP_KERNEL_CONDITION_AGENT_TYPE                        0x100000 
 236 #define NECP_KERNEL_CONDITION_HAS_CLIENT                        0x200000 
 237 #define NECP_KERNEL_CONDITION_LOCAL_NETWORKS                    0x400000 
 238 #define NECP_KERNEL_CONDITION_CLIENT_FLAGS                      0x800000 
 239 #define NECP_KERNEL_CONDITION_LOCAL_EMPTY                       0x1000000 
 240 #define NECP_KERNEL_CONDITION_REMOTE_EMPTY                      0x2000000 
 241 #define NECP_KERNEL_CONDITION_PLATFORM_BINARY                   0x4000000 
 242 #define NECP_KERNEL_CONDITION_SDK_VERSION                       0x8000000 
 243 #define NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER                0x10000000 
 244 #define NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS                0x20000000 
 245 #define NECP_KERNEL_CONDITION_IS_LOOPBACK                       0x40000000 
 246 #define NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY       0x80000000 
 248 #define NECP_MAX_POLICY_RESULT_SIZE                                     512 
 249 #define NECP_MAX_ROUTE_RULES_ARRAY_SIZE                         1024 
 250 #define NECP_MAX_CONDITIONS_ARRAY_SIZE                          4096 
 251 #define NECP_MAX_POLICY_LIST_COUNT                                      1024 
 254         NECP_BYPASS_TYPE_NONE 
= 0, 
 255         NECP_BYPASS_TYPE_INTCOPROC 
= 1, 
 256         NECP_BYPASS_TYPE_LOOPBACK 
= 2, 
 257 } necp_socket_bypass_type_t
; 
 259 // Cap the policy size at the max result + conditions size, with room for extra TLVs 
 260 #define NECP_MAX_POLICY_SIZE                                            (1024 + NECP_MAX_POLICY_RESULT_SIZE + NECP_MAX_CONDITIONS_ARRAY_SIZE) 
 262 struct necp_service_registration 
{ 
 263         LIST_ENTRY(necp_service_registration
)   session_chain
; 
 264         LIST_ENTRY(necp_service_registration
)   kernel_chain
; 
 265         u_int32_t                                                               service_id
; 
 268 struct necp_session 
{ 
 269         u_int8_t                                        necp_fd_type
; 
 270         u_int32_t                                       control_unit
; 
 271         u_int32_t                                       session_priority
; // Descriptive priority rating 
 272         u_int32_t                                       session_order
; 
 274         necp_policy_id                          last_policy_id
; 
 276         decl_lck_mtx_data(, lock
); 
 278         bool                                            proc_locked
; // Messages must come from proc_uuid 
 283         LIST_HEAD(_policies
, necp_session_policy
) policies
; 
 285         LIST_HEAD(_services
, necp_service_registration
) services
; 
 287         TAILQ_ENTRY(necp_session
) chain
; 
 290 #define NECP_SESSION_LOCK(_s) lck_mtx_lock(&_s->lock) 
 291 #define NECP_SESSION_UNLOCK(_s) lck_mtx_unlock(&_s->lock) 
 293 static TAILQ_HEAD(_necp_session_list
, necp_session
) necp_session_list
; 
 295 struct necp_socket_info 
{ 
 299         union necp_sockaddr_union local_addr
; 
 300         union necp_sockaddr_union remote_addr
; 
 301         u_int32_t bound_interface_index
; 
 302         u_int32_t traffic_class
; 
 304         u_int32_t application_id
; 
 305         u_int32_t real_application_id
; 
 306         u_int32_t account_id
; 
 307         u_int32_t drop_order
; 
 308         u_int32_t client_flags
; 
 311         unsigned has_client 
: 1; 
 312         unsigned is_platform_binary 
: 1; 
 313         unsigned used_responsible_pid 
: 1; 
 314         unsigned is_loopback 
: 1; 
 315         unsigned real_is_platform_binary 
: 1; 
 316         unsigned is_delegated 
: 1; 
 317         unsigned __pad_bits 
: 6; 
 320 static  lck_grp_attr_t  
*necp_kernel_policy_grp_attr    
= NULL
; 
 321 static  lck_attr_t              
*necp_kernel_policy_mtx_attr    
= NULL
; 
 322 static  lck_grp_t               
*necp_kernel_policy_mtx_grp             
= NULL
; 
 323 decl_lck_rw_data(static, necp_kernel_policy_lock
); 
 325 static  lck_grp_attr_t  
*necp_route_rule_grp_attr       
= NULL
; 
 326 static  lck_attr_t              
*necp_route_rule_mtx_attr       
= NULL
; 
 327 static  lck_grp_t               
*necp_route_rule_mtx_grp        
= NULL
; 
 328 decl_lck_rw_data(static, necp_route_rule_lock
); 
 330 os_refgrp_decl(static, necp_refgrp
, "NECPRefGroup", NULL
); 
 333  * On modification, invalidate cached lookups by bumping the generation count. 
 334  * Other calls will need to take the slowpath of taking 
 335  * the subsystem lock. 
 337 static volatile int32_t necp_kernel_socket_policies_gencount
; 
 338 #define BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT() do {                                                     \ 
 339         if (OSIncrementAtomic(&necp_kernel_socket_policies_gencount) == (INT32_MAX - 1)) {      \ 
 340                 necp_kernel_socket_policies_gencount = 1;                                                                               \ 
 346  * Allow priviledged processes to bypass the default drop-all 
 347  * via entitlement check.  For OSX, since entitlement check is 
 348  * not supported for configd, configd signing identity is checked 
 351 #define SIGNING_ID_CONFIGD "com.apple.configd" 
 352 #define SIGNING_ID_CONFIGD_LEN (sizeof(SIGNING_ID_CONFIGD) - 1) 
 355         NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE 
= 0, 
 356         NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE 
= 1, 
 357         NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE 
= 2, 
 358 } necp_drop_all_bypass_check_result_t
; 
 360 static u_int32_t necp_kernel_application_policies_condition_mask
; 
 361 static size_t necp_kernel_application_policies_count
; 
 362 static u_int32_t necp_kernel_socket_policies_condition_mask
; 
 363 static size_t necp_kernel_socket_policies_count
; 
 364 static size_t necp_kernel_socket_policies_non_app_count
; 
 365 static LIST_HEAD(_necpkernelsocketconnectpolicies
, necp_kernel_socket_policy
) necp_kernel_socket_policies
; 
 366 #define NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS 5 
 367 #define NECP_SOCKET_MAP_APP_ID_TO_BUCKET(appid) (appid ? (appid%(NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS - 1) + 1) : 0) 
 368 static struct necp_kernel_socket_policy 
**necp_kernel_socket_policies_map
[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
]; 
 369 static struct necp_kernel_socket_policy 
**necp_kernel_socket_policies_app_layer_map
; 
 371  * A note on policy 'maps': these are used for boosting efficiency when matching policies. For each dimension of the map, 
 372  * such as an ID, the 0 bucket is reserved for sockets/packets that do not have this parameter, while the other 
 373  * buckets lead to an array of policy pointers that form the list applicable when the (parameter%(NUM_BUCKETS - 1) + 1) == bucket_index. 
 375  * For example, a packet with policy ID of 7, when there are 4 ID buckets, will map to bucket (7%3 + 1) = 2. 
 378 static u_int32_t necp_kernel_ip_output_policies_condition_mask
; 
 379 static size_t necp_kernel_ip_output_policies_count
; 
 380 static size_t necp_kernel_ip_output_policies_non_id_count
; 
 381 static LIST_HEAD(_necpkernelipoutputpolicies
, necp_kernel_ip_output_policy
) necp_kernel_ip_output_policies
; 
 382 #define NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS 5 
 383 #define NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(id) (id ? (id%(NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS - 1) + 1) : 0) 
 384 static struct necp_kernel_ip_output_policy 
**necp_kernel_ip_output_policies_map
[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
]; 
 385 static struct necp_kernel_socket_policy pass_policy 
= 
 387         .id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
, 
 388         .result 
= NECP_KERNEL_POLICY_RESULT_PASS
, 
 391 static struct necp_session 
*necp_create_session(void); 
 392 static void necp_delete_session(struct necp_session 
*session
); 
 394 static necp_policy_id 
necp_handle_policy_add(struct necp_session 
*session
, 
 395     u_int8_t 
*tlv_buffer
, size_t tlv_buffer_length
, int offset
, int *error
); 
 396 static int necp_handle_policy_dump_all(user_addr_t out_buffer
, size_t out_buffer_length
); 
 398 #define MAX_RESULT_STRING_LEN 64 
 399 static inline const char * necp_get_result_description(char *result_string
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
); 
 401 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
); 
 402 static struct necp_session_policy 
*necp_policy_find(struct necp_session 
*session
, necp_policy_id policy_id
); 
 403 static bool necp_policy_mark_for_deletion(struct necp_session 
*session
, struct necp_session_policy 
*policy
); 
 404 static bool necp_policy_mark_all_for_deletion(struct necp_session 
*session
); 
 405 static bool necp_policy_delete(struct necp_session 
*session
, struct necp_session_policy 
*policy
); 
 406 static void necp_policy_apply_all(struct necp_session 
*session
); 
 408 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
, int32_t cond_pidversion
, 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
); 
 409 static bool necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id
); 
 410 static bool necp_kernel_socket_policies_reprocess(void); 
 411 static bool necp_kernel_socket_policies_update_uuid_table(void); 
 412 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
); 
 414 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
); 
 415 static bool necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id
); 
 416 static bool necp_kernel_ip_output_policies_reprocess(void); 
 418 static bool necp_is_addr_in_range(struct sockaddr 
*addr
, struct sockaddr 
*range_start
, struct sockaddr 
*range_end
); 
 419 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
); 
 420 static bool necp_is_addr_in_subnet(struct sockaddr 
*addr
, struct sockaddr 
*subnet_addr
, u_int8_t subnet_prefix
); 
 421 static int necp_addr_compare(struct sockaddr 
*sa1
, struct sockaddr 
*sa2
, int check_port
); 
 422 static bool necp_buffer_compare_with_bit_prefix(u_int8_t 
*p1
, u_int8_t 
*p2
, u_int32_t bits
); 
 423 static bool necp_addr_is_empty(struct sockaddr 
*addr
); 
 424 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
); 
 425 static bool necp_is_intcoproc(struct inpcb 
*inp
, struct mbuf 
*packet
); 
 427 struct necp_uuid_id_mapping 
{ 
 428         LIST_ENTRY(necp_uuid_id_mapping
) chain
; 
 431         os_refcnt_t     refcount
; 
 432         u_int32_t       table_usecount
; // Add to UUID policy table count 
 434 static size_t necp_num_uuid_app_id_mappings
; 
 435 static bool necp_uuid_app_id_mappings_dirty
; 
 436 #define NECP_UUID_APP_ID_HASH_SIZE 64 
 437 static u_long necp_uuid_app_id_hash_mask
; 
 438 static u_long necp_uuid_app_id_hash_num_buckets
; 
 439 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 
 440 #define APPUUIDHASH(uuid) (&necp_uuid_app_id_hashtbl[uuid[0] & necp_uuid_app_id_hash_mask]) // Assume first byte of UUIDs are evenly distributed 
 441 static u_int32_t 
necp_create_uuid_app_id_mapping(uuid_t uuid
, bool *allocated_mapping
, bool uuid_policy_table
); 
 442 static bool necp_remove_uuid_app_id_mapping(uuid_t uuid
, bool *removed_mapping
, bool uuid_policy_table
); 
 443 static struct necp_uuid_id_mapping 
*necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id
); 
 445 static struct necp_uuid_id_mapping 
*necp_uuid_lookup_service_id_locked(uuid_t uuid
); 
 446 static struct necp_uuid_id_mapping 
*necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id
); 
 447 static u_int32_t 
necp_create_uuid_service_id_mapping(uuid_t uuid
); 
 448 static bool necp_remove_uuid_service_id_mapping(uuid_t uuid
); 
 449 static bool necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id
); 
 451 struct necp_string_id_mapping 
{ 
 452         LIST_ENTRY(necp_string_id_mapping
) chain
; 
 455         os_refcnt_t     refcount
; 
 457 static LIST_HEAD(necp_string_id_mapping_list
, necp_string_id_mapping
) necp_account_id_list
; 
 458 static u_int32_t 
necp_create_string_to_id_mapping(struct necp_string_id_mapping_list 
*list
, char *domain
); 
 459 static bool necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list 
*list
, char *domain
); 
 460 static struct necp_string_id_mapping 
*necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list 
*list
, u_int32_t local_id
); 
 462 static struct necp_kernel_socket_policy 
*necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id
); 
 463 static struct necp_kernel_ip_output_policy 
*necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id
); 
 465 static LIST_HEAD(_necp_kernel_service_list
, necp_service_registration
) necp_registered_service_list
; 
 467 static char *necp_create_trimmed_domain(char *string
, size_t length
); 
 468 static inline int necp_count_dots(char *string
, size_t length
); 
 470 static char *necp_copy_string(char *string
, size_t length
); 
 471 static bool necp_update_qos_marking(struct ifnet 
*ifp
, u_int32_t route_rule_id
); 
 473 #define ROUTE_RULE_IS_AGGREGATE(ruleid) (ruleid > UINT16_MAX) 
 475 #define MAX_ROUTE_RULE_INTERFACES 10 
 476 struct necp_route_rule 
{ 
 477         LIST_ENTRY(necp_route_rule
) chain
; 
 479         u_int32_t       netagent_id
; 
 480         u_int8_t        default_action
; 
 481         u_int8_t        cellular_action
; 
 482         u_int8_t        wifi_action
; 
 483         u_int8_t        wired_action
; 
 484         u_int8_t        expensive_action
; 
 485         u_int8_t        constrained_action
; 
 486         u_int           exception_if_indices
[MAX_ROUTE_RULE_INTERFACES
]; 
 487         u_int8_t        exception_if_actions
[MAX_ROUTE_RULE_INTERFACES
]; 
 488         os_refcnt_t     refcount
; 
 490 static LIST_HEAD(necp_route_rule_list
, necp_route_rule
) necp_route_rules
; 
 491 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
); 
 492 static bool necp_remove_route_rule(struct necp_route_rule_list 
*list
, u_int32_t route_rule_id
); 
 493 static bool necp_route_is_allowed(struct rtentry 
*route
, ifnet_t interface
, u_int32_t route_rule_id
, u_int32_t 
*interface_type_denied
); 
 494 static uint32_t necp_route_get_netagent(struct rtentry 
*route
, u_int32_t route_rule_id
); 
 495 static struct necp_route_rule 
*necp_lookup_route_rule_locked(struct necp_route_rule_list 
*list
, u_int32_t route_rule_id
); 
 496 static inline void necp_get_parent_cred_result(proc_t proc
, struct necp_socket_info 
*info
); 
 498 #define MAX_AGGREGATE_ROUTE_RULES 16 
 499 struct necp_aggregate_route_rule 
{ 
 500         LIST_ENTRY(necp_aggregate_route_rule
) chain
; 
 502         u_int32_t       rule_ids
[MAX_AGGREGATE_ROUTE_RULES
]; 
 504 static LIST_HEAD(necp_aggregate_route_rule_list
, necp_aggregate_route_rule
) necp_aggregate_route_rules
; 
 505 static u_int32_t 
necp_create_aggregate_route_rule(u_int32_t 
*rule_ids
); 
 507 // Sysctl definitions 
 508 static int sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
; 
 509 static int sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS
; 
 511 SYSCTL_NODE(_net
, OID_AUTO
, necp
, CTLFLAG_RW 
| CTLFLAG_LOCKED
, 0, "NECP"); 
 512 SYSCTL_INT(_net_necp
, NECPCTL_DEDUP_POLICIES
, dedup_policies
, CTLFLAG_LOCKED 
| CTLFLAG_RW
, &necp_dedup_policies
, 0, ""); 
 513 SYSCTL_INT(_net_necp
, NECPCTL_RESTRICT_MULTICAST
, restrict_multicast
, CTLFLAG_LOCKED 
| CTLFLAG_RW
, &necp_restrict_multicast
, 0, ""); 
 514 SYSCTL_INT(_net_necp
, NECPCTL_PASS_LOOPBACK
, pass_loopback
, CTLFLAG_LOCKED 
| CTLFLAG_RW
, &necp_pass_loopback
, 0, ""); 
 515 SYSCTL_INT(_net_necp
, NECPCTL_PASS_KEEPALIVES
, pass_keepalives
, CTLFLAG_LOCKED 
| CTLFLAG_RW
, &necp_pass_keepalives
, 0, ""); 
 516 SYSCTL_INT(_net_necp
, NECPCTL_PASS_INTERPOSE
, pass_interpose
, CTLFLAG_LOCKED 
| CTLFLAG_RW
, &necp_pass_interpose
, 0, ""); 
 517 SYSCTL_INT(_net_necp
, NECPCTL_DEBUG
, debug
, CTLFLAG_LOCKED 
| CTLFLAG_RW
, &necp_debug
, 0, ""); 
 518 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", ""); 
 519 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", ""); 
 520 SYSCTL_LONG(_net_necp
, NECPCTL_SOCKET_POLICY_COUNT
, socket_policy_count
, CTLFLAG_LOCKED 
| CTLFLAG_RD
, &necp_kernel_socket_policies_count
, ""); 
 521 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
, ""); 
 522 SYSCTL_LONG(_net_necp
, NECPCTL_IP_POLICY_COUNT
, ip_policy_count
, CTLFLAG_LOCKED 
| CTLFLAG_RD
, &necp_kernel_ip_output_policies_count
, ""); 
 523 SYSCTL_INT(_net_necp
, NECPCTL_SESSION_COUNT
, session_count
, CTLFLAG_LOCKED 
| CTLFLAG_RD
, &necp_session_count
, 0, ""); 
 525 static struct necp_drop_dest_policy necp_drop_dest_policy
; 
 526 static int necp_drop_dest_debug 
= 0;    // 0: off, 1: match, >1: every evaluation 
 527 SYSCTL_INT(_net_necp
, OID_AUTO
, drop_dest_debug
, CTLFLAG_LOCKED 
| CTLFLAG_RW
, &necp_drop_dest_debug
, 0, ""); 
 529 static int sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS
; 
 530 SYSCTL_PROC(_net_necp
, OID_AUTO
, drop_dest_level
, CTLTYPE_STRUCT 
| CTLFLAG_LOCKED 
| CTLFLAG_ANYBODY 
| CTLFLAG_RW
, 
 531     0, 0, &sysctl_handle_necp_drop_dest_level
, "S,necp_drop_dest_level", ""); 
 533 static bool necp_address_matches_drop_dest_policy(union necp_sockaddr_union 
*, u_int32_t
); 
 535 // Session order allocation 
 537 necp_allocate_new_session_order(u_int32_t priority
, u_int32_t control_unit
) 
 539         u_int32_t new_order 
= 0; 
 541         // For now, just allocate 1000 orders for each priority 
 542         if (priority 
== NECP_SESSION_PRIORITY_UNKNOWN 
|| priority 
> NECP_SESSION_NUM_PRIORITIES
) { 
 543                 priority 
= NECP_SESSION_PRIORITY_DEFAULT
; 
 546         // Use the control unit to decide the offset into the priority list 
 547         new_order 
= (control_unit
) + ((priority 
- 1) * 1000); 
 552 static inline u_int32_t
 
 553 necp_get_first_order_for_priority(u_int32_t priority
) 
 558         return ((priority 
- 1) * 1000) + 1; 
 563 sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
 
 565 #pragma unused(arg1, arg2) 
 566         int error 
= sysctl_handle_int(oidp
, oidp
->oid_arg1
, oidp
->oid_arg2
, req
); 
 567         necp_drop_all_order 
= necp_get_first_order_for_priority(necp_drop_all_level
); 
 572 sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS
 
 574 #pragma unused(arg1, arg2) 
 575         int error 
= sysctl_handle_int(oidp
, oidp
->oid_arg1
, oidp
->oid_arg2
, req
); 
 576         necp_drop_unentitled_order 
= necp_get_first_order_for_priority(necp_drop_unentitled_level
); 
 580 // Use a macro here to avoid computing the kauth_cred_t when necp_drop_unentitled_level is 0 
 581 static inline u_int32_t
 
 582 _necp_process_drop_order_inner(kauth_cred_t cred
) 
 584         if (priv_check_cred(cred
, PRIV_NET_PRIVILEGED_CLIENT_ACCESS
, 0) != 0 && 
 585             priv_check_cred(cred
, PRIV_NET_PRIVILEGED_SERVER_ACCESS
, 0) != 0) { 
 586                 return necp_drop_unentitled_order
; 
 592 #define necp_process_drop_order(_cred) (necp_drop_unentitled_order != 0 ? _necp_process_drop_order_inner(_cred) : necp_drop_unentitled_order) 
 593 #pragma GCC poison _necp_process_drop_order_inner 
 597 static int necp_session_op_close(struct fileglob 
*, vfs_context_t
); 
 599 static const struct fileops necp_session_fd_ops 
= { 
 600         .fo_type     
= DTYPE_NETPOLICY
, 
 601         .fo_read     
= fo_no_read
, 
 602         .fo_write    
= fo_no_write
, 
 603         .fo_ioctl    
= fo_no_ioctl
, 
 604         .fo_select   
= fo_no_select
, 
 605         .fo_close    
= necp_session_op_close
, 
 606         .fo_drain    
= fo_no_drain
, 
 607         .fo_kqfilter 
= fo_no_kqfilter
, 
 611 necp_is_platform_binary(proc_t proc
) 
 613         return (proc 
!= NULL
) ? (csproc_get_platform_binary(proc
) && cs_valid(proc
)) : 0; 
 616 static inline necp_drop_all_bypass_check_result_t
 
 617 necp_check_drop_all_bypass_result(proc_t proc
) 
 620                 proc 
= current_proc(); 
 622                         return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
; 
 626 #if defined(XNU_TARGET_OS_OSX) 
 627         const char *signing_id 
= NULL
; 
 628         const bool isConfigd 
= (necp_is_platform_binary(proc
) && 
 629             (signing_id 
= cs_identity_get(proc
)) && 
 630             (strlen(signing_id
) == SIGNING_ID_CONFIGD_LEN
) && 
 631             (memcmp(signing_id
, SIGNING_ID_CONFIGD
, SIGNING_ID_CONFIGD_LEN
) == 0)); 
 633                 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE
; 
 637         const task_t task 
= proc_task(proc
); 
 638         if (task 
== NULL 
|| !IOTaskHasEntitlement(task
, "com.apple.private.necp.drop_all_bypass")) { 
 639                 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
; 
 641                 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE
; 
 646 necp_session_open(struct proc 
*p
, struct necp_session_open_args 
*uap
, int *retval
) 
 650         struct necp_session 
*session 
= NULL
; 
 651         struct fileproc 
*fp 
= NULL
; 
 654         uid_t uid 
= kauth_cred_getuid(proc_ucred(p
)); 
 655         if (uid 
!= 0 && priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES
, 0) != 0) { 
 656                 NECPLOG0(LOG_ERR
, "Process does not hold necessary entitlement to open NECP session"); 
 661         error 
= falloc(p
, &fp
, &fd
, vfs_context_current()); 
 666         session 
= necp_create_session(); 
 667         if (session 
== NULL
) { 
 672         fp
->fp_glob
->fg_flag 
= 0; 
 673         fp
->fp_glob
->fg_ops 
= &necp_session_fd_ops
; 
 674         fp
->fp_glob
->fg_data 
= session
; 
 677         FDFLAGS_SET(p
, fd
, (UF_EXCLOSE 
| UF_FORKCLOSE
)); 
 678         procfdtbl_releasefd(p
, fd
, NULL
); 
 679         fp_drop(p
, fd
, fp
, 1); 
 695 necp_session_op_close(struct fileglob 
*fg
, vfs_context_t ctx
) 
 698         struct necp_session 
*session 
= (struct necp_session 
*)fg
->fg_data
; 
 701         if (session 
!= NULL
) { 
 702                 necp_policy_mark_all_for_deletion(session
); 
 703                 necp_policy_apply_all(session
); 
 704                 necp_delete_session(session
); 
 712 necp_session_find_from_fd(struct proc 
*p
, int fd
, 
 713     struct fileproc 
**fpp
, struct necp_session 
**session
) 
 715         struct fileproc 
*fp 
= NULL
; 
 716         int error 
= fp_get_ftype(p
, fd
, DTYPE_NETPOLICY
, ENODEV
, &fp
); 
 720                 *session 
= (struct necp_session 
*)fp
->fp_glob
->fg_data
; 
 721                 if ((*session
)->necp_fd_type 
!= necp_fd_type_session
) { 
 722                         // Not a client fd, ignore 
 723                         fp_drop(p
, fd
, fp
, 0); 
 732 necp_session_add_policy(struct necp_session 
*session
, struct necp_session_action_args 
*uap
, int *retval
) 
 735         u_int8_t 
*tlv_buffer 
= NULL
; 
 737         if (uap
->in_buffer_length 
== 0 || uap
->in_buffer_length 
> NECP_MAX_POLICY_SIZE 
|| uap
->in_buffer 
== 0) { 
 738                 NECPLOG(LOG_ERR
, "necp_session_add_policy invalid input (%zu)", (size_t)uap
->in_buffer_length
); 
 743         if (uap
->out_buffer_length 
< sizeof(necp_policy_id
) || uap
->out_buffer 
== 0) { 
 744                 NECPLOG(LOG_ERR
, "necp_session_add_policy invalid output buffer (%zu)", (size_t)uap
->out_buffer_length
); 
 749         if ((tlv_buffer 
= _MALLOC(uap
->in_buffer_length
, M_NECP
, M_WAITOK 
| M_ZERO
)) == NULL
) { 
 754         error 
= copyin(uap
->in_buffer
, tlv_buffer
, uap
->in_buffer_length
); 
 756                 NECPLOG(LOG_ERR
, "necp_session_add_policy tlv copyin error (%d)", error
); 
 760         necp_policy_id new_policy_id 
= necp_handle_policy_add(session
, tlv_buffer
, uap
->in_buffer_length
, 0, &error
); 
 762                 NECPLOG(LOG_ERR
, "necp_session_add_policy failed to add policy (%d)", error
); 
 766         error 
= copyout(&new_policy_id
, uap
->out_buffer
, sizeof(new_policy_id
)); 
 768                 NECPLOG(LOG_ERR
, "necp_session_add_policy policy_id copyout error (%d)", error
); 
 773         if (tlv_buffer 
!= NULL
) { 
 774                 FREE(tlv_buffer
, M_NECP
); 
 783 necp_session_get_policy(struct necp_session 
*session
, struct necp_session_action_args 
*uap
, int *retval
) 
 786         u_int8_t 
*response 
= NULL
; 
 788         if (uap
->in_buffer_length 
< sizeof(necp_policy_id
) || uap
->in_buffer 
== 0) { 
 789                 NECPLOG(LOG_ERR
, "necp_session_get_policy invalid input (%zu)", (size_t)uap
->in_buffer_length
); 
 794         necp_policy_id policy_id 
= 0; 
 795         error 
= copyin(uap
->in_buffer
, &policy_id
, sizeof(policy_id
)); 
 797                 NECPLOG(LOG_ERR
, "necp_session_get_policy policy_id copyin error (%d)", error
); 
 801         struct necp_session_policy 
*policy 
= necp_policy_find(session
, policy_id
); 
 802         if (policy 
== NULL 
|| policy
->pending_deletion
) { 
 803                 NECPLOG(LOG_ERR
, "Failed to find policy with id %d", policy_id
); 
 808         u_int32_t order_tlv_size 
= sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(necp_policy_order
); 
 809         u_int32_t result_tlv_size 
= (policy
->result_size 
? (sizeof(u_int8_t
) + sizeof(u_int32_t
) + policy
->result_size
) : 0); 
 810         u_int32_t response_size 
= order_tlv_size 
+ result_tlv_size 
+ policy
->conditions_size
; 
 812         if (uap
->out_buffer_length 
< response_size 
|| uap
->out_buffer 
== 0) { 
 813                 NECPLOG(LOG_ERR
, "necp_session_get_policy buffer not large enough (%zu < %u)", (size_t)uap
->out_buffer_length
, response_size
); 
 818         if (response_size 
> NECP_MAX_POLICY_SIZE
) { 
 819                 NECPLOG(LOG_ERR
, "necp_session_get_policy size too large to copy (%u)", response_size
); 
 824         MALLOC(response
, u_int8_t 
*, response_size
, M_NECP
, M_WAITOK 
| M_ZERO
); 
 825         if (response 
== NULL
) { 
 830         u_int8_t 
*cursor 
= response
; 
 831         cursor 
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ORDER
, sizeof(necp_policy_order
), &policy
->order
, response
, response_size
); 
 832         if (result_tlv_size
) { 
 833                 cursor 
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_RESULT
, policy
->result_size
, &policy
->result
, response
, response_size
); 
 835         if (policy
->conditions_size
) { 
 836                 memcpy(((u_int8_t 
*)(void *)(cursor
)), policy
->conditions
, policy
->conditions_size
); 
 839         error 
= copyout(response
, uap
->out_buffer
, response_size
); 
 841                 NECPLOG(LOG_ERR
, "necp_session_get_policy TLV copyout error (%d)", error
); 
 846         if (response 
!= NULL
) { 
 847                 FREE(response
, M_NECP
); 
 856 necp_session_delete_policy(struct necp_session 
*session
, struct necp_session_action_args 
*uap
, int *retval
) 
 860         if (uap
->in_buffer_length 
< sizeof(necp_policy_id
) || uap
->in_buffer 
== 0) { 
 861                 NECPLOG(LOG_ERR
, "necp_session_delete_policy invalid input (%zu)", (size_t)uap
->in_buffer_length
); 
 866         necp_policy_id delete_policy_id 
= 0; 
 867         error 
= copyin(uap
->in_buffer
, &delete_policy_id
, sizeof(delete_policy_id
)); 
 869                 NECPLOG(LOG_ERR
, "necp_session_delete_policy policy_id copyin error (%d)", error
); 
 873         struct necp_session_policy 
*policy 
= necp_policy_find(session
, delete_policy_id
); 
 874         if (policy 
== NULL 
|| policy
->pending_deletion
) { 
 875                 NECPLOG(LOG_ERR
, "necp_session_delete_policy failed to find policy with id %u", delete_policy_id
); 
 880         necp_policy_mark_for_deletion(session
, policy
); 
 887 necp_session_apply_all(struct necp_session 
*session
, struct necp_session_action_args 
*uap
, int *retval
) 
 890         necp_policy_apply_all(session
); 
 896 necp_session_list_all(struct necp_session 
*session
, struct necp_session_action_args 
*uap
, int *retval
) 
 898         u_int32_t tlv_size 
= (sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(necp_policy_id
)); 
 899         u_int32_t response_size 
= 0; 
 900         u_int8_t 
*response 
= NULL
; 
 901         int num_policies 
= 0; 
 902         int cur_policy_index 
= 0; 
 904         struct necp_session_policy 
*policy
; 
 906         LIST_FOREACH(policy
, &session
->policies
, chain
) { 
 907                 if (!policy
->pending_deletion
) { 
 912         if (num_policies 
> NECP_MAX_POLICY_LIST_COUNT
) { 
 913                 NECPLOG(LOG_ERR
, "necp_session_list_all size too large to copy (%u policies)", num_policies
); 
 918         response_size 
= num_policies 
* tlv_size
; 
 919         if (uap
->out_buffer_length 
< response_size 
|| uap
->out_buffer 
== 0) { 
 920                 NECPLOG(LOG_ERR
, "necp_session_list_all buffer not large enough (%zu < %u)", (size_t)uap
->out_buffer_length
, response_size
); 
 925         // Create a response with one Policy ID TLV for each policy 
 926         MALLOC(response
, u_int8_t 
*, response_size
, M_NECP
, M_WAITOK 
| M_ZERO
); 
 927         if (response 
== NULL
) { 
 932         u_int8_t 
*cursor 
= response
; 
 933         LIST_FOREACH(policy
, &session
->policies
, chain
) { 
 934                 if (!policy
->pending_deletion 
&& cur_policy_index 
< num_policies
) { 
 935                         cursor 
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ID
, sizeof(u_int32_t
), &policy
->local_id
, response
, response_size
); 
 940         error 
= copyout(response
, uap
->out_buffer
, response_size
); 
 942                 NECPLOG(LOG_ERR
, "necp_session_list_all TLV copyout error (%d)", error
); 
 947         if (response 
!= NULL
) { 
 948                 FREE(response
, M_NECP
); 
 958 necp_session_delete_all(struct necp_session 
*session
, struct necp_session_action_args 
*uap
, int *retval
) 
 961         necp_policy_mark_all_for_deletion(session
); 
 967 necp_session_set_session_priority(struct necp_session 
*session
, struct necp_session_action_args 
*uap
, int *retval
) 
 970         struct necp_session_policy 
*policy 
= NULL
; 
 971         struct necp_session_policy 
*temp_policy 
= NULL
; 
 973         if (uap
->in_buffer_length 
< sizeof(necp_session_priority
) || uap
->in_buffer 
== 0) { 
 974                 NECPLOG(LOG_ERR
, "necp_session_set_session_priority invalid input (%zu)", (size_t)uap
->in_buffer_length
); 
 979         necp_session_priority requested_session_priority 
= 0; 
 980         error 
= copyin(uap
->in_buffer
, &requested_session_priority
, sizeof(requested_session_priority
)); 
 982                 NECPLOG(LOG_ERR
, "necp_session_set_session_priority priority copyin error (%d)", error
); 
 986         // Enforce special session priorities with entitlements 
 987         if (requested_session_priority 
== NECP_SESSION_PRIORITY_CONTROL 
|| 
 988             requested_session_priority 
== NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL 
|| 
 989             requested_session_priority 
== NECP_SESSION_PRIORITY_HIGH_RESTRICTED
) { 
 990                 errno_t cred_result 
= priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES
, 0); 
 991                 if (cred_result 
!= 0) { 
 992                         NECPLOG(LOG_ERR
, "Session does not hold necessary entitlement to claim priority level %d", requested_session_priority
); 
 998         if (session
->session_priority 
!= requested_session_priority
) { 
 999                 session
->session_priority 
= requested_session_priority
; 
1000                 session
->session_order 
= necp_allocate_new_session_order(session
->session_priority
, session
->control_unit
); 
1001                 session
->dirty 
= TRUE
; 
1003                 // Mark all policies as needing updates 
1004                 LIST_FOREACH_SAFE(policy
, &session
->policies
, chain
, temp_policy
) { 
1005                         policy
->pending_update 
= TRUE
; 
1015 necp_session_lock_to_process(struct necp_session 
*session
, struct necp_session_action_args 
*uap
, int *retval
) 
1018         session
->proc_locked 
= TRUE
; 
1024 necp_session_register_service(struct necp_session 
*session
, struct necp_session_action_args 
*uap
, int *retval
) 
1027         struct necp_service_registration 
*new_service 
= NULL
; 
1029         if (uap
->in_buffer_length 
< sizeof(uuid_t
) || uap
->in_buffer 
== 0) { 
1030                 NECPLOG(LOG_ERR
, "necp_session_register_service invalid input (%zu)", (size_t)uap
->in_buffer_length
); 
1035         uuid_t service_uuid
; 
1036         error 
= copyin(uap
->in_buffer
, service_uuid
, sizeof(service_uuid
)); 
1038                 NECPLOG(LOG_ERR
, "necp_session_register_service uuid copyin error (%d)", error
); 
1042         MALLOC(new_service
, struct necp_service_registration 
*, sizeof(*new_service
), M_NECP
, M_WAITOK 
| M_ZERO
); 
1043         if (new_service 
== NULL
) { 
1044                 NECPLOG0(LOG_ERR
, "Failed to allocate service registration"); 
1049         lck_rw_lock_exclusive(&necp_kernel_policy_lock
); 
1050         new_service
->service_id 
= necp_create_uuid_service_id_mapping(service_uuid
); 
1051         LIST_INSERT_HEAD(&session
->services
, new_service
, session_chain
); 
1052         LIST_INSERT_HEAD(&necp_registered_service_list
, new_service
, kernel_chain
); 
1053         lck_rw_done(&necp_kernel_policy_lock
); 
1061 necp_session_unregister_service(struct necp_session 
*session
, struct necp_session_action_args 
*uap
, int *retval
) 
1064         struct necp_service_registration 
*service 
= NULL
; 
1065         struct necp_service_registration 
*temp_service 
= NULL
; 
1066         struct necp_uuid_id_mapping 
*mapping 
= NULL
; 
1068         if (uap
->in_buffer_length 
< sizeof(uuid_t
) || uap
->in_buffer 
== 0) { 
1069                 NECPLOG(LOG_ERR
, "necp_session_unregister_service invalid input (%zu)", (size_t)uap
->in_buffer_length
); 
1074         uuid_t service_uuid
; 
1075         error 
= copyin(uap
->in_buffer
, service_uuid
, sizeof(service_uuid
)); 
1077                 NECPLOG(LOG_ERR
, "necp_session_unregister_service uuid copyin error (%d)", error
); 
1081         // Remove all matching services for this session 
1082         lck_rw_lock_exclusive(&necp_kernel_policy_lock
); 
1083         mapping 
= necp_uuid_lookup_service_id_locked(service_uuid
); 
1084         if (mapping 
!= NULL
) { 
1085                 LIST_FOREACH_SAFE(service
, &session
->services
, session_chain
, temp_service
) { 
1086                         if (service
->service_id 
== mapping
->id
) { 
1087                                 LIST_REMOVE(service
, session_chain
); 
1088                                 LIST_REMOVE(service
, kernel_chain
); 
1089                                 FREE(service
, M_NECP
); 
1092                 necp_remove_uuid_service_id_mapping(service_uuid
); 
1094         lck_rw_done(&necp_kernel_policy_lock
); 
1102 necp_session_dump_all(struct necp_session 
*session
, struct necp_session_action_args 
*uap
, int *retval
) 
1104 #pragma unused(session) 
1107         if (uap
->out_buffer_length 
== 0 || uap
->out_buffer 
== 0) { 
1108                 NECPLOG(LOG_ERR
, "necp_session_dump_all invalid output buffer (%zu)", (size_t)uap
->out_buffer_length
); 
1113         error 
= necp_handle_policy_dump_all(uap
->out_buffer
, uap
->out_buffer_length
); 
1120 necp_session_action(struct proc 
*p
, struct necp_session_action_args 
*uap
, int *retval
) 
1122         struct fileproc 
*fp
; 
1124         int return_value 
= 0; 
1125         struct necp_session 
*session 
= NULL
; 
1127         error 
= necp_session_find_from_fd(p
, uap
->necp_fd
, &fp
, &session
); 
1129                 NECPLOG(LOG_ERR
, "necp_session_action find fd error (%d)", error
); 
1133         NECP_SESSION_LOCK(session
); 
1135         if (session
->proc_locked
) { 
1136                 // Verify that the calling process is allowed to do actions 
1138                 proc_getexecutableuuid(current_proc(), proc_uuid
, sizeof(proc_uuid
)); 
1139                 if (uuid_compare(proc_uuid
, session
->proc_uuid
) != 0) { 
1144                 // If not locked, update the proc_uuid and proc_pid of the session 
1145                 proc_getexecutableuuid(current_proc(), session
->proc_uuid
, sizeof(session
->proc_uuid
)); 
1146                 session
->proc_pid 
= proc_pid(current_proc()); 
1149         u_int32_t action 
= uap
->action
; 
1151         case NECP_SESSION_ACTION_POLICY_ADD
: { 
1152                 return_value 
= necp_session_add_policy(session
, uap
, retval
); 
1155         case NECP_SESSION_ACTION_POLICY_GET
: { 
1156                 return_value 
= necp_session_get_policy(session
, uap
, retval
); 
1159         case NECP_SESSION_ACTION_POLICY_DELETE
:  { 
1160                 return_value 
= necp_session_delete_policy(session
, uap
, retval
); 
1163         case NECP_SESSION_ACTION_POLICY_APPLY_ALL
: { 
1164                 return_value 
= necp_session_apply_all(session
, uap
, retval
); 
1167         case NECP_SESSION_ACTION_POLICY_LIST_ALL
: { 
1168                 return_value 
= necp_session_list_all(session
, uap
, retval
); 
1171         case NECP_SESSION_ACTION_POLICY_DELETE_ALL
: { 
1172                 return_value 
= necp_session_delete_all(session
, uap
, retval
); 
1175         case NECP_SESSION_ACTION_SET_SESSION_PRIORITY
: { 
1176                 return_value 
= necp_session_set_session_priority(session
, uap
, retval
); 
1179         case NECP_SESSION_ACTION_LOCK_SESSION_TO_PROC
: { 
1180                 return_value 
= necp_session_lock_to_process(session
, uap
, retval
); 
1183         case NECP_SESSION_ACTION_REGISTER_SERVICE
: { 
1184                 return_value 
= necp_session_register_service(session
, uap
, retval
); 
1187         case NECP_SESSION_ACTION_UNREGISTER_SERVICE
: { 
1188                 return_value 
= necp_session_unregister_service(session
, uap
, retval
); 
1191         case NECP_SESSION_ACTION_POLICY_DUMP_ALL
: { 
1192                 return_value 
= necp_session_dump_all(session
, uap
, retval
); 
1196                 NECPLOG(LOG_ERR
, "necp_session_action unknown action (%u)", action
); 
1197                 return_value 
= EINVAL
; 
1203         NECP_SESSION_UNLOCK(session
); 
1204         fp_drop(p
, uap
->necp_fd
, fp
, 0); 
1205         return return_value
; 
1208 struct necp_resolver_key_state 
{ 
1209         const struct ccdigest_info 
*digest_info
; 
1210         uint8_t key
[CCSHA256_OUTPUT_SIZE
]; 
1212 static struct necp_resolver_key_state s_necp_resolver_key_state
; 
1215 necp_generate_resolver_key(void) 
1217         s_necp_resolver_key_state
.digest_info 
= ccsha256_di(); 
1218         cc_rand_generate(s_necp_resolver_key_state
.key
, sizeof(s_necp_resolver_key_state
.key
)); 
1222 necp_sign_update_context(const struct ccdigest_info 
*di
, 
1226     u_int32_t query_length
, 
1228     u_int32_t answer_length
) 
1230         const uint8_t context
[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times 
1231         const char *context_string 
= "NECP Resolver Binder"; 
1232         uint8_t separator 
= 0; 
1233         cchmac_update(di
, ctx
, sizeof(context
), context
); 
1234         cchmac_update(di
, ctx
, strlen(context_string
), context_string
); 
1235         cchmac_update(di
, ctx
, sizeof(separator
), &separator
); 
1236         cchmac_update(di
, ctx
, sizeof(uuid_t
), client_id
); 
1237         cchmac_update(di
, ctx
, sizeof(query_length
), &query_length
); 
1238         cchmac_update(di
, ctx
, query_length
, query
); 
1239         cchmac_update(di
, ctx
, sizeof(answer_length
), &answer_length
); 
1240         cchmac_update(di
, ctx
, answer_length
, answer
); 
1244 necp_sign_resolver_answer(uuid_t client_id
, u_int8_t 
*query
, u_int32_t query_length
, 
1245     u_int8_t 
*answer
, u_int32_t answer_length
, 
1246     u_int8_t 
*tag
, u_int32_t 
*out_tag_length
) 
1248         if (s_necp_resolver_key_state
.digest_info 
== NULL
) { 
1252         if (query 
== NULL 
|| 
1253             query_length 
== 0 || 
1255             answer_length 
== 0 || 
1257             out_tag_length 
== NULL
) { 
1261         size_t required_tag_length 
= s_necp_resolver_key_state
.digest_info
->output_size
; 
1262         if (*out_tag_length 
< required_tag_length
) { 
1266         *out_tag_length 
= required_tag_length
; 
1268         cchmac_ctx_decl(s_necp_resolver_key_state
.digest_info
->state_size
, 
1269             s_necp_resolver_key_state
.digest_info
->block_size
, ctx
); 
1270         cchmac_init(s_necp_resolver_key_state
.digest_info
, ctx
, 
1271             sizeof(s_necp_resolver_key_state
.key
), 
1272             s_necp_resolver_key_state
.key
); 
1273         necp_sign_update_context(s_necp_resolver_key_state
.digest_info
, 
1274             ctx
, client_id
, query
, query_length
, 
1275             answer
, answer_length
); 
1276         cchmac_final(s_necp_resolver_key_state
.digest_info
, ctx
, tag
); 
1282 necp_validate_resolver_answer(uuid_t client_id
, u_int8_t 
*query
, u_int32_t query_length
, 
1283     u_int8_t 
*answer
, u_int32_t answer_length
, 
1284     u_int8_t 
*tag
, u_int32_t tag_length
) 
1286         if (s_necp_resolver_key_state
.digest_info 
== NULL
) { 
1290         if (query 
== NULL 
|| 
1291             query_length 
== 0 || 
1293             answer_length 
== 0 || 
1299         size_t required_tag_length 
= s_necp_resolver_key_state
.digest_info
->output_size
; 
1300         if (tag_length 
!= required_tag_length
) { 
1304         uint8_t actual_tag
[required_tag_length
]; 
1306         cchmac_ctx_decl(s_necp_resolver_key_state
.digest_info
->state_size
, 
1307             s_necp_resolver_key_state
.digest_info
->block_size
, ctx
); 
1308         cchmac_init(s_necp_resolver_key_state
.digest_info
, ctx
, 
1309             sizeof(s_necp_resolver_key_state
.key
), 
1310             s_necp_resolver_key_state
.key
); 
1311         necp_sign_update_context(s_necp_resolver_key_state
.digest_info
, 
1312             ctx
, client_id
, query
, query_length
, 
1313             answer
, answer_length
); 
1314         cchmac_final(s_necp_resolver_key_state
.digest_info
, ctx
, actual_tag
); 
1316         return cc_cmp_safe(s_necp_resolver_key_state
.digest_info
->output_size
, tag
, actual_tag
) == 0; 
1324         necp_log_handle 
= os_log_create("com.apple.xnu.net.necp", "necp"); 
1326         necp_kernel_policy_grp_attr 
= lck_grp_attr_alloc_init(); 
1327         if (necp_kernel_policy_grp_attr 
== NULL
) { 
1328                 NECPLOG0(LOG_ERR
, "lck_grp_attr_alloc_init failed"); 
1333         necp_kernel_policy_mtx_grp 
= lck_grp_alloc_init(NECP_CONTROL_NAME
, necp_kernel_policy_grp_attr
); 
1334         if (necp_kernel_policy_mtx_grp 
== NULL
) { 
1335                 NECPLOG0(LOG_ERR
, "lck_grp_alloc_init failed"); 
1340         necp_kernel_policy_mtx_attr 
= lck_attr_alloc_init(); 
1341         if (necp_kernel_policy_mtx_attr 
== NULL
) { 
1342                 NECPLOG0(LOG_ERR
, "lck_attr_alloc_init failed"); 
1347         lck_rw_init(&necp_kernel_policy_lock
, necp_kernel_policy_mtx_grp
, necp_kernel_policy_mtx_attr
); 
1349         necp_route_rule_grp_attr 
= lck_grp_attr_alloc_init(); 
1350         if (necp_route_rule_grp_attr 
== NULL
) { 
1351                 NECPLOG0(LOG_ERR
, "lck_grp_attr_alloc_init failed"); 
1356         necp_route_rule_mtx_grp 
= lck_grp_alloc_init("necp_route_rule", necp_route_rule_grp_attr
); 
1357         if (necp_route_rule_mtx_grp 
== NULL
) { 
1358                 NECPLOG0(LOG_ERR
, "lck_grp_alloc_init failed"); 
1363         necp_route_rule_mtx_attr 
= lck_attr_alloc_init(); 
1364         if (necp_route_rule_mtx_attr 
== NULL
) { 
1365                 NECPLOG0(LOG_ERR
, "lck_attr_alloc_init failed"); 
1370         lck_rw_init(&necp_route_rule_lock
, necp_route_rule_mtx_grp
, necp_route_rule_mtx_attr
); 
1374         TAILQ_INIT(&necp_session_list
); 
1376         LIST_INIT(&necp_kernel_socket_policies
); 
1377         LIST_INIT(&necp_kernel_ip_output_policies
); 
1379         LIST_INIT(&necp_account_id_list
); 
1381         LIST_INIT(&necp_uuid_service_id_list
); 
1383         LIST_INIT(&necp_registered_service_list
); 
1385         LIST_INIT(&necp_route_rules
); 
1386         LIST_INIT(&necp_aggregate_route_rules
); 
1388         necp_generate_resolver_key(); 
1390         necp_uuid_app_id_hashtbl 
= hashinit(NECP_UUID_APP_ID_HASH_SIZE
, M_NECP
, &necp_uuid_app_id_hash_mask
); 
1391         necp_uuid_app_id_hash_num_buckets 
= necp_uuid_app_id_hash_mask 
+ 1; 
1392         necp_num_uuid_app_id_mappings 
= 0; 
1393         necp_uuid_app_id_mappings_dirty 
= FALSE
; 
1395         necp_kernel_application_policies_condition_mask 
= 0; 
1396         necp_kernel_socket_policies_condition_mask 
= 0; 
1397         necp_kernel_ip_output_policies_condition_mask 
= 0; 
1399         necp_kernel_application_policies_count 
= 0; 
1400         necp_kernel_socket_policies_count 
= 0; 
1401         necp_kernel_socket_policies_non_app_count 
= 0; 
1402         necp_kernel_ip_output_policies_count 
= 0; 
1403         necp_kernel_ip_output_policies_non_id_count 
= 0; 
1405         necp_kernel_socket_policies_gencount 
= 1; 
1407         memset(&necp_kernel_socket_policies_map
, 0, sizeof(necp_kernel_socket_policies_map
)); 
1408         memset(&necp_kernel_ip_output_policies_map
, 0, sizeof(necp_kernel_ip_output_policies_map
)); 
1409         necp_kernel_socket_policies_app_layer_map 
= NULL
; 
1411         necp_drop_unentitled_order 
= necp_get_first_order_for_priority(necp_drop_unentitled_level
); 
1415                 if (necp_kernel_policy_mtx_attr 
!= NULL
) { 
1416                         lck_attr_free(necp_kernel_policy_mtx_attr
); 
1417                         necp_kernel_policy_mtx_attr 
= NULL
; 
1419                 if (necp_kernel_policy_mtx_grp 
!= NULL
) { 
1420                         lck_grp_free(necp_kernel_policy_mtx_grp
); 
1421                         necp_kernel_policy_mtx_grp 
= NULL
; 
1423                 if (necp_kernel_policy_grp_attr 
!= NULL
) { 
1424                         lck_grp_attr_free(necp_kernel_policy_grp_attr
); 
1425                         necp_kernel_policy_grp_attr 
= NULL
; 
1427                 if (necp_route_rule_mtx_attr 
!= NULL
) { 
1428                         lck_attr_free(necp_route_rule_mtx_attr
); 
1429                         necp_route_rule_mtx_attr 
= NULL
; 
1431                 if (necp_route_rule_mtx_grp 
!= NULL
) { 
1432                         lck_grp_free(necp_route_rule_mtx_grp
); 
1433                         necp_route_rule_mtx_grp 
= NULL
; 
1435                 if (necp_route_rule_grp_attr 
!= NULL
) { 
1436                         lck_grp_attr_free(necp_route_rule_grp_attr
); 
1437                         necp_route_rule_grp_attr 
= NULL
; 
1444 necp_post_change_event(struct kev_necp_policies_changed_data 
*necp_event_data
) 
1446         struct kev_msg ev_msg
; 
1447         memset(&ev_msg
, 0, sizeof(ev_msg
)); 
1449         ev_msg
.vendor_code      
= KEV_VENDOR_APPLE
; 
1450         ev_msg
.kev_class        
= KEV_NETWORK_CLASS
; 
1451         ev_msg
.kev_subclass     
= KEV_NECP_SUBCLASS
; 
1452         ev_msg
.event_code       
= KEV_NECP_POLICIES_CHANGED
; 
1454         ev_msg
.dv
[0].data_ptr    
= necp_event_data
; 
1455         ev_msg
.dv
[0].data_length 
= sizeof(necp_event_data
->changed_count
); 
1456         ev_msg
.dv
[1].data_length 
= 0; 
1458         kev_post_msg(&ev_msg
); 
1462 necp_buffer_write_tlv_validate(u_int8_t 
*cursor
, u_int8_t type
, u_int32_t length
, 
1463     u_int8_t 
*buffer
, u_int32_t buffer_length
) 
1465         if (cursor 
< buffer 
|| (uintptr_t)(cursor 
- buffer
) > buffer_length
) { 
1466                 NECPLOG0(LOG_ERR
, "Cannot write TLV in buffer (invalid cursor)"); 
1469         u_int8_t 
*next_tlv 
= (u_int8_t 
*)(cursor 
+ sizeof(type
) + sizeof(length
) + length
); 
1470         if (next_tlv 
<= buffer 
|| // make sure the next TLV start doesn't overflow 
1471             (uintptr_t)(next_tlv 
- buffer
) > buffer_length
) {     // make sure the next TLV has enough room in buffer 
1472                 NECPLOG(LOG_ERR
, "Cannot write TLV in buffer (TLV length %u, buffer length %u)", 
1473                     length
, buffer_length
); 
1480 necp_buffer_write_tlv_if_different(u_int8_t 
*cursor
, u_int8_t type
, 
1481     u_int32_t length
, const void *value
, bool *updated
, 
1482     u_int8_t 
*buffer
, u_int32_t buffer_length
) 
1484         if (!necp_buffer_write_tlv_validate(cursor
, type
, length
, buffer
, buffer_length
)) { 
1485                 // If we can't fit this TLV, return the current cursor 
1488         u_int8_t 
*next_tlv 
= (u_int8_t 
*)(cursor 
+ sizeof(type
) + sizeof(length
) + length
); 
1489         if (*updated 
|| *(u_int8_t 
*)(cursor
) != type
) { 
1490                 *(u_int8_t 
*)(cursor
) = type
; 
1493         if (*updated 
|| *(u_int32_t 
*)(void *)(cursor 
+ sizeof(type
)) != length
) { 
1494                 *(u_int32_t 
*)(void *)(cursor 
+ sizeof(type
)) = length
; 
1498                 if (*updated 
|| memcmp((u_int8_t 
*)(cursor 
+ sizeof(type
) + sizeof(length
)), value
, length
) != 0) { 
1499                         memcpy((u_int8_t 
*)(cursor 
+ sizeof(type
) + sizeof(length
)), value
, length
); 
1507 necp_buffer_write_tlv(u_int8_t 
*cursor
, u_int8_t type
, 
1508     u_int32_t length
, const void *value
, 
1509     u_int8_t 
*buffer
, u_int32_t buffer_length
) 
1511         if (!necp_buffer_write_tlv_validate(cursor
, type
, length
, buffer
, buffer_length
)) { 
1514         u_int8_t 
*next_tlv 
= (u_int8_t 
*)(cursor 
+ sizeof(type
) + sizeof(length
) + length
); 
1515         *(u_int8_t 
*)(cursor
) = type
; 
1516         *(u_int32_t 
*)(void *)(cursor 
+ sizeof(type
)) = length
; 
1518                 memcpy((u_int8_t 
*)(cursor 
+ sizeof(type
) + sizeof(length
)), value
, length
); 
1525 necp_buffer_get_tlv_type(u_int8_t 
*buffer
, int tlv_offset
) 
1527         u_int8_t 
*type 
= NULL
; 
1529         if (buffer 
== NULL
) { 
1533         type 
= (u_int8_t 
*)((u_int8_t 
*)buffer 
+ tlv_offset
); 
1534         return type 
? *type 
: 0; 
1538 necp_buffer_get_tlv_length(u_int8_t 
*buffer
, int tlv_offset
) 
1540         u_int32_t 
*length 
= NULL
; 
1542         if (buffer 
== NULL
) { 
1546         length 
= (u_int32_t 
*)(void *)((u_int8_t 
*)buffer 
+ tlv_offset 
+ sizeof(u_int8_t
)); 
1547         return length 
? *length 
: 0; 
1551 necp_buffer_get_tlv_value(u_int8_t 
*buffer
, int tlv_offset
, u_int32_t 
*value_size
) 
1553         u_int8_t 
*value 
= NULL
; 
1554         u_int32_t length 
= necp_buffer_get_tlv_length(buffer
, tlv_offset
); 
1560                 *value_size 
= length
; 
1563         value 
= (u_int8_t 
*)((u_int8_t 
*)buffer 
+ tlv_offset 
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)); 
1568 necp_buffer_find_tlv(u_int8_t 
*buffer
, u_int32_t buffer_length
, int offset
, u_int8_t type
, int *err
, int next
) 
1579         int cursor 
= offset
; 
1581         u_int32_t curr_length
; 
1585                 if ((((u_int32_t
)cursor
) + sizeof(curr_type
) + sizeof(curr_length
)) > buffer_length
) { 
1589                         curr_type 
= necp_buffer_get_tlv_type(buffer
, cursor
); 
1592                         curr_type 
= NECP_TLV_NIL
; 
1594                 curr_length 
= necp_buffer_get_tlv_length(buffer
, cursor
); 
1595                 if (curr_length 
> buffer_length 
- ((u_int32_t
)cursor 
+ sizeof(curr_type
) + sizeof(curr_length
))) { 
1599                 next_cursor 
= (cursor 
+ sizeof(curr_type
) + sizeof(curr_length
) + curr_length
); 
1600                 if (curr_type 
== type
) { 
1601                         // check if entire TLV fits inside buffer 
1602                         if (((u_int32_t
)next_cursor
) <= buffer_length
) { 
1611                 cursor 
= next_cursor
; 
1616 necp_find_tlv(u_int8_t 
*buffer
, u_int32_t buffer_length
, int offset
, u_int8_t type
, int *err
, int next
) 
1619         if (buffer 
!= NULL
) { 
1620                 cursor 
= necp_buffer_find_tlv(buffer
, buffer_length
, offset
, type
, err
, next
); 
1626 necp_get_tlv_at_offset(u_int8_t 
*buffer
, u_int32_t buffer_length
, 
1627     int tlv_offset
, u_int32_t out_buffer_length
, void *out_buffer
, u_int32_t 
*value_size
) 
1629         if (buffer 
== NULL
) { 
1630                 NECPLOG0(LOG_ERR
, "necp_get_tlv_at_offset buffer is NULL"); 
1634         // Handle buffer parsing 
1636         // Validate that buffer has enough room for any TLV 
1637         if (tlv_offset 
+ sizeof(u_int8_t
) + sizeof(u_int32_t
) > buffer_length
) { 
1638                 NECPLOG(LOG_ERR
, "necp_get_tlv_at_offset buffer_length is too small for TLV (%u < %lu)", 
1639                     buffer_length
, tlv_offset 
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)); 
1643         // Validate that buffer has enough room for this TLV 
1644         u_int32_t tlv_length 
= necp_buffer_get_tlv_length(buffer
, tlv_offset
); 
1645         if (tlv_length 
> buffer_length 
- (tlv_offset 
+ sizeof(u_int8_t
) + sizeof(u_int32_t
))) { 
1646                 NECPLOG(LOG_ERR
, "necp_get_tlv_at_offset buffer_length is too small for TLV of length %u (%u < %lu)", 
1647                     tlv_length
, buffer_length
, tlv_offset 
+ sizeof(u_int8_t
) + sizeof(u_int32_t
) + tlv_length
); 
1651         if (out_buffer 
!= NULL 
&& out_buffer_length 
> 0) { 
1652                 // Validate that out buffer is large enough for  value 
1653                 if (out_buffer_length 
< tlv_length
) { 
1654                         NECPLOG(LOG_ERR
, "necp_get_tlv_at_offset out_buffer_length is too small for TLV value (%u < %u)", 
1655                             out_buffer_length
, tlv_length
); 
1659                 // Get value pointer 
1660                 u_int8_t 
*tlv_value 
= necp_buffer_get_tlv_value(buffer
, tlv_offset
, NULL
); 
1661                 if (tlv_value 
== NULL
) { 
1662                         NECPLOG0(LOG_ERR
, "necp_get_tlv_at_offset tlv_value is NULL"); 
1667                 memcpy(out_buffer
, tlv_value
, tlv_length
); 
1671         if (value_size 
!= NULL
) { 
1672                 *value_size 
= tlv_length
; 
1679 necp_get_tlv(u_int8_t 
*buffer
, u_int32_t buffer_length
, 
1680     int offset
, u_int8_t type
, u_int32_t buff_len
, void *buff
, u_int32_t 
*value_size
) 
1684         int tlv_offset 
= necp_find_tlv(buffer
, buffer_length
, offset
, type
, &error
, 0); 
1685         if (tlv_offset 
< 0) { 
1689         return necp_get_tlv_at_offset(buffer
, buffer_length
, tlv_offset
, buff_len
, buff
, value_size
); 
1692 // Session Management 
1694 static struct necp_session 
* 
1695 necp_create_session(void) 
1697         struct necp_session 
*new_session 
= NULL
; 
1699         MALLOC(new_session
, struct necp_session 
*, sizeof(*new_session
), M_NECP
, M_WAITOK 
| M_ZERO
); 
1700         if (new_session 
== NULL
) { 
1704         new_session
->necp_fd_type 
= necp_fd_type_session
; 
1705         new_session
->session_priority 
= NECP_SESSION_PRIORITY_UNKNOWN
; 
1706         new_session
->dirty 
= FALSE
; 
1707         LIST_INIT(&new_session
->policies
); 
1708         lck_mtx_init(&new_session
->lock
, necp_kernel_policy_mtx_grp
, necp_kernel_policy_mtx_attr
); 
1711         lck_rw_lock_exclusive(&necp_kernel_policy_lock
); 
1713         // Find the next available control unit 
1714         u_int32_t control_unit 
= 1; 
1715         struct necp_session 
*next_session 
= NULL
; 
1716         TAILQ_FOREACH(next_session
, &necp_session_list
, chain
) { 
1717                 if (next_session
->control_unit 
> control_unit
) { 
1718                         // Found a gap, grab this control unit 
1722                 // Try the next control unit, loop around 
1723                 control_unit 
= next_session
->control_unit 
+ 1; 
1726         new_session
->control_unit 
= control_unit
; 
1727         new_session
->session_order 
= necp_allocate_new_session_order(new_session
->session_priority
, control_unit
); 
1729         if (next_session 
!= NULL
) { 
1730                 TAILQ_INSERT_BEFORE(next_session
, new_session
, chain
); 
1732                 TAILQ_INSERT_TAIL(&necp_session_list
, new_session
, chain
); 
1735         necp_session_count
++; 
1736         lck_rw_done(&necp_kernel_policy_lock
); 
1739                 NECPLOG(LOG_DEBUG
, "Created NECP session, control unit %d", control_unit
); 
1747 necp_delete_session(struct necp_session 
*session
) 
1749         if (session 
!= NULL
) { 
1750                 struct necp_service_registration 
*service 
= NULL
; 
1751                 struct necp_service_registration 
*temp_service 
= NULL
; 
1752                 LIST_FOREACH_SAFE(service
, &session
->services
, session_chain
, temp_service
) { 
1753                         LIST_REMOVE(service
, session_chain
); 
1754                         lck_rw_lock_exclusive(&necp_kernel_policy_lock
); 
1755                         LIST_REMOVE(service
, kernel_chain
); 
1756                         lck_rw_done(&necp_kernel_policy_lock
); 
1757                         FREE(service
, M_NECP
); 
1760                         NECPLOG0(LOG_DEBUG
, "Deleted NECP session"); 
1763                 lck_rw_lock_exclusive(&necp_kernel_policy_lock
); 
1764                 TAILQ_REMOVE(&necp_session_list
, session
, chain
); 
1765                 necp_session_count
--; 
1766                 lck_rw_done(&necp_kernel_policy_lock
); 
1768                 lck_mtx_destroy(&session
->lock
, necp_kernel_policy_mtx_grp
); 
1769                 FREE(session
, M_NECP
); 
1773 // Session Policy Management 
1775 static inline u_int8_t
 
1776 necp_policy_result_get_type_from_buffer(u_int8_t 
*buffer
, u_int32_t length
) 
1778         return (buffer 
&& length 
>= sizeof(u_int8_t
)) ? buffer
[0] : 0; 
1781 static inline u_int32_t
 
1782 necp_policy_result_get_parameter_length_from_buffer(u_int8_t 
*buffer
, u_int32_t length
) 
1784         return (buffer 
&& length 
> sizeof(u_int8_t
)) ? (length 
- sizeof(u_int8_t
)) : 0; 
1787 static inline u_int8_t 
* 
1788 necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t 
*buffer
, u_int32_t length
) 
1790         return (buffer 
&& length 
> sizeof(u_int8_t
)) ? (buffer 
+ sizeof(u_int8_t
)) : NULL
; 
1794 necp_policy_result_requires_route_rules(u_int8_t 
*buffer
, u_int32_t length
) 
1796         u_int8_t type 
= necp_policy_result_get_type_from_buffer(buffer
, length
); 
1797         if (type 
== NECP_POLICY_RESULT_ROUTE_RULES
) { 
1804 necp_address_is_valid(struct sockaddr 
*address
) 
1806         if (address
->sa_family 
== AF_INET
) { 
1807                 return address
->sa_len 
== sizeof(struct sockaddr_in
); 
1808         } else if (address
->sa_family 
== AF_INET6
) { 
1809                 return address
->sa_len 
== sizeof(struct sockaddr_in6
); 
1816 necp_policy_result_is_valid(u_int8_t 
*buffer
, u_int32_t length
) 
1818         bool validated 
= FALSE
; 
1819         u_int8_t type 
= necp_policy_result_get_type_from_buffer(buffer
, length
); 
1820         u_int32_t parameter_length 
= necp_policy_result_get_parameter_length_from_buffer(buffer
, length
); 
1822         case NECP_POLICY_RESULT_PASS
: { 
1823                 if (parameter_length 
== 0 || parameter_length 
== sizeof(u_int32_t
)) { 
1828         case NECP_POLICY_RESULT_DROP
: { 
1829                 if (parameter_length 
== 0 || parameter_length 
== sizeof(u_int32_t
)) { 
1834         case NECP_POLICY_RESULT_ROUTE_RULES
: 
1835         case NECP_POLICY_RESULT_SCOPED_DIRECT
: 
1836         case NECP_POLICY_RESULT_ALLOW_UNENTITLED
: { 
1840         case NECP_POLICY_RESULT_SKIP
: 
1841         case NECP_POLICY_RESULT_SOCKET_DIVERT
: 
1842         case NECP_POLICY_RESULT_SOCKET_FILTER
: { 
1843                 if (parameter_length 
>= sizeof(u_int32_t
)) { 
1848         case NECP_POLICY_RESULT_IP_TUNNEL
: { 
1849                 if (parameter_length 
> sizeof(u_int32_t
)) { 
1854         case NECP_POLICY_RESULT_SOCKET_SCOPED
: { 
1855                 if (parameter_length 
> 0) { 
1860         case NECP_POLICY_RESULT_TRIGGER
: 
1861         case NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
: 
1862         case NECP_POLICY_RESULT_TRIGGER_SCOPED
: 
1863         case NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
: 
1864         case NECP_POLICY_RESULT_USE_NETAGENT
: 
1865         case NECP_POLICY_RESULT_NETAGENT_SCOPED
:{ 
1866                 if (parameter_length 
>= sizeof(uuid_t
)) { 
1878                 NECPLOG(LOG_DEBUG
, "Policy result type %d, valid %d", type
, validated
); 
1884 static inline u_int8_t
 
1885 necp_policy_condition_get_type_from_buffer(u_int8_t 
*buffer
, u_int32_t length
) 
1887         return (buffer 
&& length 
>= sizeof(u_int8_t
)) ? buffer
[0] : 0; 
1890 static inline u_int8_t
 
1891 necp_policy_condition_get_flags_from_buffer(u_int8_t 
*buffer
, u_int32_t length
) 
1893         return (buffer 
&& length 
>= (2 * sizeof(u_int8_t
))) ? buffer
[1] : 0; 
1896 static inline u_int32_t
 
1897 necp_policy_condition_get_value_length_from_buffer(u_int8_t 
*buffer
, u_int32_t length
) 
1899         return (buffer 
&& length 
>= (2 * sizeof(u_int8_t
))) ? (length 
- (2 * sizeof(u_int8_t
))) : 0; 
1902 static inline u_int8_t 
* 
1903 necp_policy_condition_get_value_pointer_from_buffer(u_int8_t 
*buffer
, u_int32_t length
) 
1905         return (buffer 
&& length 
> (2 * sizeof(u_int8_t
))) ? (buffer 
+ (2 * sizeof(u_int8_t
))) : NULL
; 
1909 necp_policy_condition_is_default(u_int8_t 
*buffer
, u_int32_t length
) 
1911         return necp_policy_condition_get_type_from_buffer(buffer
, length
) == NECP_POLICY_CONDITION_DEFAULT
; 
1915 necp_policy_condition_is_application(u_int8_t 
*buffer
, u_int32_t length
) 
1917         return necp_policy_condition_get_type_from_buffer(buffer
, length
) == NECP_POLICY_CONDITION_APPLICATION
; 
1921 necp_policy_condition_is_real_application(u_int8_t 
*buffer
, u_int32_t length
) 
1923         return necp_policy_condition_get_type_from_buffer(buffer
, length
) == NECP_POLICY_CONDITION_REAL_APPLICATION
; 
1927 necp_policy_condition_requires_application(u_int8_t 
*buffer
, u_int32_t length
) 
1929         u_int8_t type 
= necp_policy_condition_get_type_from_buffer(buffer
, length
); 
1930         return type 
== NECP_POLICY_CONDITION_REAL_APPLICATION
; 
1934 necp_policy_condition_requires_real_application(u_int8_t 
*buffer
, u_int32_t length
) 
1936         u_int8_t type 
= necp_policy_condition_get_type_from_buffer(buffer
, length
); 
1937         u_int32_t condition_length 
= necp_policy_condition_get_value_length_from_buffer(buffer
, length
); 
1938         return type 
== NECP_POLICY_CONDITION_ENTITLEMENT 
&& condition_length 
> 0; 
1942 necp_policy_condition_is_valid(u_int8_t 
*buffer
, u_int32_t length
, u_int8_t policy_result_type
) 
1944         bool validated 
= FALSE
; 
1945         bool result_cannot_have_ip_layer 
= (policy_result_type 
== NECP_POLICY_RESULT_SOCKET_DIVERT 
|| 
1946             policy_result_type 
== NECP_POLICY_RESULT_SOCKET_FILTER 
|| 
1947             policy_result_type 
== NECP_POLICY_RESULT_TRIGGER 
|| 
1948             policy_result_type 
== NECP_POLICY_RESULT_TRIGGER_IF_NEEDED 
|| 
1949             policy_result_type 
== NECP_POLICY_RESULT_TRIGGER_SCOPED 
|| 
1950             policy_result_type 
== NECP_POLICY_RESULT_NO_TRIGGER_SCOPED 
|| 
1951             policy_result_type 
== NECP_POLICY_RESULT_SOCKET_SCOPED 
|| 
1952             policy_result_type 
== NECP_POLICY_RESULT_ROUTE_RULES 
|| 
1953             policy_result_type 
== NECP_POLICY_RESULT_USE_NETAGENT 
|| 
1954             policy_result_type 
== NECP_POLICY_RESULT_NETAGENT_SCOPED 
|| 
1955             policy_result_type 
== NECP_POLICY_RESULT_SCOPED_DIRECT 
|| 
1956             policy_result_type 
== NECP_POLICY_RESULT_ALLOW_UNENTITLED
) ? TRUE 
: FALSE
; 
1957         u_int32_t condition_length 
= necp_policy_condition_get_value_length_from_buffer(buffer
, length
); 
1958         u_int8_t 
*condition_value 
= necp_policy_condition_get_value_pointer_from_buffer(buffer
, length
); 
1959         u_int8_t type 
= necp_policy_condition_get_type_from_buffer(buffer
, length
); 
1960         u_int8_t flags 
= necp_policy_condition_get_flags_from_buffer(buffer
, length
); 
1962         case NECP_POLICY_CONDITION_APPLICATION
: 
1963         case NECP_POLICY_CONDITION_REAL_APPLICATION
: { 
1964                 if (!(flags 
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
) && 
1965                     condition_length 
>= sizeof(uuid_t
) && 
1966                     condition_value 
!= NULL 
&& 
1967                     !uuid_is_null(condition_value
)) { 
1972         case NECP_POLICY_CONDITION_DOMAIN
: 
1973         case NECP_POLICY_CONDITION_ACCOUNT
: 
1974         case NECP_POLICY_CONDITION_BOUND_INTERFACE
: 
1975         case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER
: { 
1976                 if (condition_length 
> 0) { 
1981         case NECP_POLICY_CONDITION_TRAFFIC_CLASS
: { 
1982                 if (condition_length 
>= sizeof(struct necp_policy_condition_tc_range
)) { 
1987         case NECP_POLICY_CONDITION_DEFAULT
: 
1988         case NECP_POLICY_CONDITION_ALL_INTERFACES
: 
1989         case NECP_POLICY_CONDITION_ENTITLEMENT
: 
1990         case NECP_POLICY_CONDITION_PLATFORM_BINARY
: 
1991         case NECP_POLICY_CONDITION_HAS_CLIENT
: 
1992         case NECP_POLICY_CONDITION_LOCAL_NETWORKS
: { 
1993                 if (!(flags 
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
)) { 
1998         case NECP_POLICY_CONDITION_SDK_VERSION
: { 
1999                 if (!(flags 
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
) && 
2000                     condition_length 
>= sizeof(struct necp_policy_condition_sdk_version
)) { 
2005         case NECP_POLICY_CONDITION_IP_PROTOCOL
: { 
2006                 if (condition_length 
>= sizeof(u_int16_t
)) { 
2011         case NECP_POLICY_CONDITION_PID
: { 
2012                 if (condition_length 
>= sizeof(pid_t
) && 
2013                     condition_value 
!= NULL 
&& 
2014                     *((pid_t 
*)(void *)condition_value
) != 0) { 
2019         case NECP_POLICY_CONDITION_UID
: { 
2020                 if (condition_length 
>= sizeof(uid_t
)) { 
2025         case NECP_POLICY_CONDITION_LOCAL_ADDR
: 
2026         case NECP_POLICY_CONDITION_REMOTE_ADDR
: { 
2027                 if (!result_cannot_have_ip_layer 
&& condition_length 
>= sizeof(struct necp_policy_condition_addr
) && 
2028                     necp_address_is_valid(&((struct necp_policy_condition_addr 
*)(void *)condition_value
)->address
.sa
)) { 
2033         case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE
: 
2034         case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE
: { 
2035                 if (!result_cannot_have_ip_layer 
&& condition_length 
>= sizeof(struct necp_policy_condition_addr_range
) && 
2036                     necp_address_is_valid(&((struct necp_policy_condition_addr_range 
*)(void *)condition_value
)->start_address
.sa
) && 
2037                     necp_address_is_valid(&((struct necp_policy_condition_addr_range 
*)(void *)condition_value
)->end_address
.sa
)) { 
2042         case NECP_POLICY_CONDITION_AGENT_TYPE
: { 
2043                 if (!(flags 
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
) && 
2044                     condition_length 
>= sizeof(struct necp_policy_condition_agent_type
)) { 
2049         case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL
: { 
2050                 if (condition_length 
>= sizeof(u_int16_t
)) { 
2055         case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR
: 
2056         case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR
: { 
2057                 if (condition_length 
>= sizeof(struct necp_policy_condition_addr
) && 
2058                     necp_address_is_valid(&((struct necp_policy_condition_addr 
*)(void *)condition_value
)->address
.sa
)) { 
2063         case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE
: 
2064         case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE
: { 
2065                 if (condition_length 
>= sizeof(struct necp_policy_condition_addr_range
) && 
2066                     necp_address_is_valid(&((struct necp_policy_condition_addr_range 
*)(void *)condition_value
)->start_address
.sa
) && 
2067                     necp_address_is_valid(&((struct necp_policy_condition_addr_range 
*)(void *)condition_value
)->end_address
.sa
)) { 
2072         case NECP_POLICY_CONDITION_CLIENT_FLAGS
: { 
2073                 if (condition_length 
== 0 || condition_length 
>= sizeof(u_int32_t
)) { 
2078         case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY
: { 
2082         case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY
: { 
2086         case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS
: { 
2087                 if (condition_length 
>= sizeof(u_int16_t
)) { 
2088                         u_int16_t packet_filter_tags 
= *(u_int16_t 
*)(void *)condition_value
; 
2089                         if (packet_filter_tags 
> 0 && packet_filter_tags 
<= NECP_POLICY_CONDITION_PACKET_FILTER_TAG_MAX
) { 
2095         case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK
: { 
2099         case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY
: { 
2110                 NECPLOG(LOG_DEBUG
, "Policy condition type %d, valid %d", type
, validated
); 
2117 necp_policy_route_rule_is_default(u_int8_t 
*buffer
, u_int32_t length
) 
2119         return necp_policy_condition_get_value_length_from_buffer(buffer
, length
) == 0 && 
2120                necp_policy_condition_get_flags_from_buffer(buffer
, length
) == 0; 
2124 necp_policy_route_rule_is_valid(u_int8_t 
*buffer
, u_int32_t length
) 
2126         bool validated 
= FALSE
; 
2127         u_int8_t type 
= necp_policy_condition_get_type_from_buffer(buffer
, length
); 
2129         case NECP_ROUTE_RULE_ALLOW_INTERFACE
: { 
2133         case NECP_ROUTE_RULE_DENY_INTERFACE
: { 
2137         case NECP_ROUTE_RULE_QOS_MARKING
: { 
2141         case NECP_ROUTE_RULE_DENY_LQM_ABORT
: { 
2145         case NECP_ROUTE_RULE_USE_NETAGENT
: { 
2146                 u_int32_t rule_length 
= necp_policy_condition_get_value_length_from_buffer(buffer
, length
); 
2147                 validated 
= (rule_length 
>= sizeof(uuid_t
)); 
2157                 NECPLOG(LOG_DEBUG
, "Policy route rule type %d, valid %d", type
, validated
); 
2164 necp_get_posix_error_for_necp_error(int response_error
) 
2166         switch (response_error
) { 
2167         case NECP_ERROR_UNKNOWN_PACKET_TYPE
: 
2168         case NECP_ERROR_INVALID_TLV
: 
2169         case NECP_ERROR_POLICY_RESULT_INVALID
: 
2170         case NECP_ERROR_POLICY_CONDITIONS_INVALID
: 
2171         case NECP_ERROR_ROUTE_RULES_INVALID
: { 
2174         case NECP_ERROR_POLICY_ID_NOT_FOUND
: { 
2177         case NECP_ERROR_INVALID_PROCESS
: { 
2180         case NECP_ERROR_INTERNAL
: 
2187 static necp_policy_id
 
2188 necp_handle_policy_add(struct necp_session 
*session
, 
2189     u_int8_t 
*tlv_buffer
, size_t tlv_buffer_length
, int offset
, int *return_error
) 
2191         bool has_default_condition 
= FALSE
; 
2192         bool has_non_default_condition 
= FALSE
; 
2193         bool has_application_condition 
= FALSE
; 
2194         bool has_real_application_condition 
= FALSE
; 
2195         bool requires_application_condition 
= FALSE
; 
2196         bool requires_real_application_condition 
= FALSE
; 
2197         u_int8_t 
*conditions_array 
= NULL
; 
2198         u_int32_t conditions_array_size 
= 0; 
2199         int conditions_array_cursor
; 
2201         bool has_default_route_rule 
= FALSE
; 
2202         u_int8_t 
*route_rules_array 
= NULL
; 
2203         u_int32_t route_rules_array_size 
= 0; 
2204         int route_rules_array_cursor
; 
2208         u_int32_t response_error 
= NECP_ERROR_INTERNAL
; 
2210         necp_policy_order order 
= 0; 
2211         struct necp_session_policy 
*policy 
= NULL
; 
2212         u_int8_t 
*policy_result 
= NULL
; 
2213         u_int32_t policy_result_size 
= 0; 
2215         // Read policy order 
2216         error 
= necp_get_tlv(tlv_buffer
, tlv_buffer_length
, offset
, NECP_TLV_POLICY_ORDER
, sizeof(order
), &order
, NULL
); 
2218                 NECPLOG(LOG_ERR
, "Failed to get policy order: %d", error
); 
2219                 response_error 
= NECP_ERROR_INVALID_TLV
; 
2223         // Read policy result 
2224         cursor 
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, offset
, NECP_TLV_POLICY_RESULT
, &error
, 0); 
2225         if (error 
|| cursor 
< 0) { 
2226                 NECPLOG(LOG_ERR
, "Failed to find policy result TLV: %d", error
); 
2227                 response_error 
= NECP_ERROR_INVALID_TLV
; 
2230         error 
= necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, 0, NULL
, &policy_result_size
); 
2231         if (error 
|| policy_result_size 
== 0) { 
2232                 NECPLOG(LOG_ERR
, "Failed to get policy result length: %d", error
); 
2233                 response_error 
= NECP_ERROR_INVALID_TLV
; 
2236         if (policy_result_size 
> NECP_MAX_POLICY_RESULT_SIZE
) { 
2237                 NECPLOG(LOG_ERR
, "Policy result length too large: %u", policy_result_size
); 
2238                 response_error 
= NECP_ERROR_INVALID_TLV
; 
2241         MALLOC(policy_result
, u_int8_t 
*, policy_result_size
, M_NECP
, M_WAITOK
); 
2242         if (policy_result 
== NULL
) { 
2243                 NECPLOG(LOG_ERR
, "Failed to allocate a policy result buffer (size %d)", policy_result_size
); 
2244                 response_error 
= NECP_ERROR_INTERNAL
; 
2247         error 
= necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, policy_result_size
, policy_result
, NULL
); 
2249                 NECPLOG(LOG_ERR
, "Failed to get policy result: %d", error
); 
2250                 response_error 
= NECP_ERROR_POLICY_RESULT_INVALID
; 
2253         if (!necp_policy_result_is_valid(policy_result
, policy_result_size
)) { 
2254                 NECPLOG0(LOG_ERR
, "Failed to validate policy result"); 
2255                 response_error 
= NECP_ERROR_POLICY_RESULT_INVALID
; 
2259         if (necp_policy_result_requires_route_rules(policy_result
, policy_result_size
)) { 
2260                 // Read route rules conditions 
2261                 for (cursor 
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, offset
, NECP_TLV_ROUTE_RULE
, &error
, 0); 
2263                     cursor 
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, cursor
, NECP_TLV_ROUTE_RULE
, &error
, 1)) { 
2264                         u_int32_t route_rule_size 
= 0; 
2265                         necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, 0, NULL
, &route_rule_size
); 
2266                         if (os_add_overflow(route_rules_array_size
, 
2267                             (sizeof(u_int8_t
) + sizeof(u_int32_t
) + route_rule_size
), 
2268                             &route_rules_array_size
)) { 
2269                                 NECPLOG0(LOG_ERR
, "Route rules size overflowed, too large"); 
2270                                 response_error 
= NECP_ERROR_INVALID_TLV
; 
2275                 if (route_rules_array_size 
== 0) { 
2276                         NECPLOG0(LOG_ERR
, "Failed to get policy route rules"); 
2277                         response_error 
= NECP_ERROR_INVALID_TLV
; 
2280                 if (route_rules_array_size 
> NECP_MAX_ROUTE_RULES_ARRAY_SIZE
) { 
2281                         NECPLOG(LOG_ERR
, "Route rules length too large: %u", route_rules_array_size
); 
2282                         response_error 
= NECP_ERROR_INVALID_TLV
; 
2285                 MALLOC(route_rules_array
, u_int8_t 
*, route_rules_array_size
, M_NECP
, M_WAITOK
); 
2286                 if (route_rules_array 
== NULL
) { 
2287                         NECPLOG(LOG_ERR
, "Failed to allocate a policy route rules array (size %d)", route_rules_array_size
); 
2288                         response_error 
= NECP_ERROR_INTERNAL
; 
2292                 route_rules_array_cursor 
= 0; 
2293                 for (cursor 
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, offset
, NECP_TLV_ROUTE_RULE
, &error
, 0); 
2295                     cursor 
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, cursor
, NECP_TLV_ROUTE_RULE
, &error
, 1)) { 
2296                         u_int8_t route_rule_type 
= NECP_TLV_ROUTE_RULE
; 
2297                         u_int32_t route_rule_size 
= 0; 
2298                         necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, 0, NULL
, &route_rule_size
); 
2299                         if (route_rule_size 
> 0 && 
2300                             (sizeof(route_rule_type
) + sizeof(route_rule_size
) + route_rule_size
) <= (route_rules_array_size 
- route_rules_array_cursor
)) { 
2302                                 memcpy((route_rules_array 
+ route_rules_array_cursor
), &route_rule_type
, sizeof(route_rule_type
)); 
2303                                 route_rules_array_cursor 
+= sizeof(route_rule_type
); 
2306                                 memcpy((route_rules_array 
+ route_rules_array_cursor
), &route_rule_size
, sizeof(route_rule_size
)); 
2307                                 route_rules_array_cursor 
+= sizeof(route_rule_size
); 
2310                                 necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, route_rule_size
, (route_rules_array 
+ route_rules_array_cursor
), NULL
); 
2312                                 if (!necp_policy_route_rule_is_valid((route_rules_array 
+ route_rules_array_cursor
), route_rule_size
)) { 
2313                                         NECPLOG0(LOG_ERR
, "Failed to validate policy route rule"); 
2314                                         response_error 
= NECP_ERROR_ROUTE_RULES_INVALID
; 
2318                                 if (necp_policy_route_rule_is_default((route_rules_array 
+ route_rules_array_cursor
), route_rule_size
)) { 
2319                                         if (has_default_route_rule
) { 
2320                                                 NECPLOG0(LOG_ERR
, "Failed to validate route rule; contained multiple default route rules"); 
2321                                                 response_error 
= NECP_ERROR_ROUTE_RULES_INVALID
; 
2324                                         has_default_route_rule 
= TRUE
; 
2327                                 route_rules_array_cursor 
+= route_rule_size
; 
2332         // Read policy conditions 
2333         for (cursor 
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, offset
, NECP_TLV_POLICY_CONDITION
, &error
, 0); 
2335             cursor 
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, cursor
, NECP_TLV_POLICY_CONDITION
, &error
, 1)) { 
2336                 u_int32_t condition_size 
= 0; 
2337                 necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, 0, NULL
, &condition_size
); 
2339                 if (condition_size 
> 0) { 
2340                         if (os_add_overflow(conditions_array_size
, 
2341                             (sizeof(u_int8_t
) + sizeof(u_int32_t
) + condition_size
), 
2342                             &conditions_array_size
)) { 
2343                                 NECPLOG0(LOG_ERR
, "Conditions size overflowed, too large"); 
2344                                 response_error 
= NECP_ERROR_INVALID_TLV
; 
2350         if (conditions_array_size 
== 0) { 
2351                 NECPLOG0(LOG_ERR
, "Failed to get policy conditions"); 
2352                 response_error 
= NECP_ERROR_INVALID_TLV
; 
2355         if (conditions_array_size 
> NECP_MAX_CONDITIONS_ARRAY_SIZE
) { 
2356                 NECPLOG(LOG_ERR
, "Conditions length too large: %u", conditions_array_size
); 
2357                 response_error 
= NECP_ERROR_INVALID_TLV
; 
2360         MALLOC(conditions_array
, u_int8_t 
*, conditions_array_size
, M_NECP
, M_WAITOK
); 
2361         if (conditions_array 
== NULL
) { 
2362                 NECPLOG(LOG_ERR
, "Failed to allocate a policy conditions array (size %d)", conditions_array_size
); 
2363                 response_error 
= NECP_ERROR_INTERNAL
; 
2367         conditions_array_cursor 
= 0; 
2368         for (cursor 
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, offset
, NECP_TLV_POLICY_CONDITION
, &error
, 0); 
2370             cursor 
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, cursor
, NECP_TLV_POLICY_CONDITION
, &error
, 1)) { 
2371                 u_int8_t condition_type 
= NECP_TLV_POLICY_CONDITION
; 
2372                 u_int32_t condition_size 
= 0; 
2373                 necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, 0, NULL
, &condition_size
); 
2374                 if (condition_size 
> 0 && 
2375                     (sizeof(condition_type
) + sizeof(condition_size
) + condition_size
) <= (conditions_array_size 
- conditions_array_cursor
)) { 
2377                         memcpy((conditions_array 
+ conditions_array_cursor
), &condition_type
, sizeof(condition_type
)); 
2378                         conditions_array_cursor 
+= sizeof(condition_type
); 
2381                         memcpy((conditions_array 
+ conditions_array_cursor
), &condition_size
, sizeof(condition_size
)); 
2382                         conditions_array_cursor 
+= sizeof(condition_size
); 
2385                         necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, condition_size
, (conditions_array 
+ conditions_array_cursor
), NULL
); 
2386                         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
))) { 
2387                                 NECPLOG0(LOG_ERR
, "Failed to validate policy condition"); 
2388                                 response_error 
= NECP_ERROR_POLICY_CONDITIONS_INVALID
; 
2392                         if (necp_policy_condition_is_default((conditions_array 
+ conditions_array_cursor
), condition_size
)) { 
2393                                 has_default_condition 
= TRUE
; 
2395                                 has_non_default_condition 
= TRUE
; 
2397                         if (has_default_condition 
&& has_non_default_condition
) { 
2398                                 NECPLOG0(LOG_ERR
, "Failed to validate conditions; contained default and non-default conditions"); 
2399                                 response_error 
= NECP_ERROR_POLICY_CONDITIONS_INVALID
; 
2403                         if (necp_policy_condition_is_application((conditions_array 
+ conditions_array_cursor
), condition_size
)) { 
2404                                 has_application_condition 
= TRUE
; 
2407                         if (necp_policy_condition_is_real_application((conditions_array 
+ conditions_array_cursor
), condition_size
)) { 
2408                                 has_real_application_condition 
= TRUE
; 
2411                         if (necp_policy_condition_requires_application((conditions_array 
+ conditions_array_cursor
), condition_size
)) { 
2412                                 requires_application_condition 
= TRUE
; 
2415                         if (necp_policy_condition_requires_real_application((conditions_array 
+ conditions_array_cursor
), condition_size
)) { 
2416                                 requires_real_application_condition 
= TRUE
; 
2419                         conditions_array_cursor 
+= condition_size
; 
2423         if (requires_application_condition 
&& !has_application_condition
) { 
2424                 NECPLOG0(LOG_ERR
, "Failed to validate conditions; did not contain application condition"); 
2425                 response_error 
= NECP_ERROR_POLICY_CONDITIONS_INVALID
; 
2429         if (requires_real_application_condition 
&& !has_real_application_condition
) { 
2430                 NECPLOG0(LOG_ERR
, "Failed to validate conditions; did not contain real application condition"); 
2431                 response_error 
= NECP_ERROR_POLICY_CONDITIONS_INVALID
; 
2435         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
) { 
2436                 response_error 
= NECP_ERROR_INTERNAL
; 
2440         return policy
->local_id
; 
2443         if (policy_result 
!= NULL
) { 
2444                 FREE(policy_result
, M_NECP
); 
2446         if (conditions_array 
!= NULL
) { 
2447                 FREE(conditions_array
, M_NECP
); 
2449         if (route_rules_array 
!= NULL
) { 
2450                 FREE(route_rules_array
, M_NECP
); 
2453         if (return_error 
!= NULL
) { 
2454                 *return_error 
= necp_get_posix_error_for_necp_error(response_error
); 
2459 static necp_policy_id
 
2460 necp_policy_get_new_id(struct necp_session 
*session
) 
2462         session
->last_policy_id
++; 
2463         if (session
->last_policy_id 
< 1) { 
2464                 session
->last_policy_id 
= 1; 
2467         necp_policy_id newid 
= session
->last_policy_id
; 
2470                 NECPLOG0(LOG_ERR
, "Allocate policy id failed.\n"); 
2478  *      For the policy dump response this is the structure: 
2480  *      <NECP_PACKET_HEADER> 
2482  *              type    :       NECP_TLV_POLICY_DUMP 
2487  *                              type    :       NECP_TLV_POLICY_ID 
2492  *                              type    :       NECP_TLV_POLICY_ORDER 
2497  *                              type    :       NECP_TLV_POLICY_RESULT_STRING 
2502  *                              type    :       NECP_TLV_POLICY_OWNER 
2507  *                              type    :       NECP_TLV_POLICY_CONDITION 
2512  *                                              type    :       NECP_POLICY_CONDITION_ALL_INTERFACES 
2517  *                                              type    :       NECP_POLICY_CONDITION_BOUND_INTERFACES 
2527  *              type    :       NECP_TLV_POLICY_DUMP 
2532  *                              type    :       NECP_TLV_POLICY_ID 
2537  *                              type    :       NECP_TLV_POLICY_ORDER 
2542  *                              type    :       NECP_TLV_POLICY_RESULT_STRING 
2547  *                              type    :       NECP_TLV_POLICY_OWNER 
2552  *                              type    :       NECP_TLV_POLICY_CONDITION 
2557  *                                              type    :       NECP_POLICY_CONDITION_ALL_INTERFACES 
2562  *                                              type    :       NECP_POLICY_CONDITION_BOUND_INTERFACES 
2574 necp_handle_policy_dump_all(user_addr_t out_buffer
, size_t out_buffer_length
) 
2576         struct necp_kernel_socket_policy 
*policy 
= NULL
; 
2578         int policy_count 
= 0; 
2579         u_int8_t 
**tlv_buffer_pointers 
= NULL
; 
2580         u_int32_t 
*tlv_buffer_lengths 
= NULL
; 
2581         u_int32_t total_tlv_len 
= 0; 
2582         u_int8_t 
*result_buf 
= NULL
; 
2583         u_int8_t 
*result_buf_cursor 
= result_buf
; 
2584         char result_string
[MAX_RESULT_STRING_LEN
]; 
2585         char proc_name_string
[MAXCOMLEN 
+ 1]; 
2588         bool error_occured 
= false; 
2589         u_int32_t response_error 
= NECP_ERROR_INTERNAL
; 
2591 #define REPORT_ERROR(error) error_occured = true;               \ 
2592                                                         response_error = error;         \ 
2595 #define UNLOCK_AND_REPORT_ERROR(lock, error)    lck_rw_done(lock);      \ 
2598         errno_t cred_result 
= priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES
, 0); 
2599         if (cred_result 
!= 0) { 
2600                 NECPLOG0(LOG_ERR
, "Session does not hold the necessary entitlement to get Network Extension Policy information"); 
2601                 REPORT_ERROR(NECP_ERROR_INTERNAL
); 
2605         lck_rw_lock_shared(&necp_kernel_policy_lock
); 
2608                 NECPLOG0(LOG_DEBUG
, "Gathering policies"); 
2611         policy_count 
= necp_kernel_application_policies_count
; 
2613         MALLOC(tlv_buffer_pointers
, u_int8_t 
* *, sizeof(u_int8_t 
*) * policy_count
, M_NECP
, M_NOWAIT 
| M_ZERO
); 
2614         if (tlv_buffer_pointers 
== NULL
) { 
2615                 NECPLOG(LOG_DEBUG
, "Failed to allocate tlv_buffer_pointers (%lu bytes)", sizeof(u_int8_t 
*) * policy_count
); 
2616                 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock
, NECP_ERROR_INTERNAL
); 
2619         MALLOC(tlv_buffer_lengths
, u_int32_t 
*, sizeof(u_int32_t
) * policy_count
, M_NECP
, M_NOWAIT 
| M_ZERO
); 
2620         if (tlv_buffer_lengths 
== NULL
) { 
2621                 NECPLOG(LOG_DEBUG
, "Failed to allocate tlv_buffer_lengths (%lu bytes)", sizeof(u_int32_t
) * policy_count
); 
2622                 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock
, NECP_ERROR_INTERNAL
); 
2625         for (policy_i 
= 0; necp_kernel_socket_policies_app_layer_map 
!= NULL 
&& necp_kernel_socket_policies_app_layer_map
[policy_i
] != NULL
; policy_i
++) { 
2626                 policy 
= necp_kernel_socket_policies_app_layer_map
[policy_i
]; 
2628                 memset(result_string
, 0, MAX_RESULT_STRING_LEN
); 
2629                 memset(proc_name_string
, 0, MAXCOMLEN 
+ 1); 
2631                 necp_get_result_description(result_string
, policy
->result
, policy
->result_parameter
); 
2632                 proc_name(policy
->session_pid
, proc_name_string
, MAXCOMLEN
); 
2634                 u_int16_t proc_name_len 
= strlen(proc_name_string
) + 1; 
2635                 u_int16_t result_string_len 
= strlen(result_string
) + 1; 
2638                         NECPLOG(LOG_DEBUG
, "Policy: process: %s, result: %s", proc_name_string
, result_string
); 
2641                 u_int32_t total_allocated_bytes 
=       sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(policy
->id
) +                                     // NECP_TLV_POLICY_ID 
2642                     sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(policy
->order
) +                                                                                              // NECP_TLV_POLICY_ORDER 
2643                     sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(policy
->session_order
) +                                                                              // NECP_TLV_POLICY_SESSION_ORDER 
2644                     sizeof(u_int8_t
) + sizeof(u_int32_t
) + result_string_len 
+                                                                                                          // NECP_TLV_POLICY_RESULT_STRING 
2645                     sizeof(u_int8_t
) + sizeof(u_int32_t
) + proc_name_len 
+                                                                                                              // NECP_TLV_POLICY_OWNER 
2646                     sizeof(u_int8_t
) + sizeof(u_int32_t
);                                                                                                                                               // NECP_TLV_POLICY_CONDITION 
2648                 // We now traverse the condition_mask to see how much space we need to allocate 
2649                 u_int32_t condition_mask 
= policy
->condition_mask
; 
2650                 u_int8_t num_conditions 
= 0; 
2651                 struct necp_string_id_mapping 
*account_id_entry 
= NULL
; 
2652                 char if_name
[IFXNAMSIZ
]; 
2653                 u_int32_t condition_tlv_length 
= 0; 
2654                 memset(if_name
, 0, sizeof(if_name
)); 
2656                 if (condition_mask 
== NECP_POLICY_CONDITION_DEFAULT
) { 
2659                         if (condition_mask 
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) { 
2662                         if (condition_mask 
& NECP_KERNEL_CONDITION_HAS_CLIENT
) { 
2665                         if (condition_mask 
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) { 
2666                                 snprintf(if_name
, IFXNAMSIZ
, "%s%d", ifnet_name(policy
->cond_bound_interface
), ifnet_unit(policy
->cond_bound_interface
)); 
2667                                 condition_tlv_length 
+= strlen(if_name
) + 1; 
2670                         if (condition_mask 
& NECP_KERNEL_CONDITION_PROTOCOL
) { 
2671                                 condition_tlv_length 
+= sizeof(policy
->cond_protocol
); 
2674                         if (condition_mask 
& NECP_KERNEL_CONDITION_APP_ID
) { 
2675                                 condition_tlv_length 
+= sizeof(uuid_t
); 
2678                         if (condition_mask 
& NECP_KERNEL_CONDITION_REAL_APP_ID
) { 
2679                                 condition_tlv_length 
+= sizeof(uuid_t
); 
2682                         if (condition_mask 
& NECP_KERNEL_CONDITION_DOMAIN
) { 
2683                                 u_int32_t domain_len 
= strlen(policy
->cond_domain
) + 1; 
2684                                 condition_tlv_length 
+= domain_len
; 
2687                         if (condition_mask 
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) { 
2688                                 account_id_entry 
= necp_lookup_string_with_id_locked(&necp_account_id_list
, policy
->cond_account_id
); 
2689                                 u_int32_t account_id_len 
= 0; 
2690                                 if (account_id_entry
) { 
2691                                         account_id_len 
= account_id_entry
->string 
? strlen(account_id_entry
->string
) + 1 : 0; 
2693                                 condition_tlv_length 
+= account_id_len
; 
2696                         if (condition_mask 
& NECP_KERNEL_CONDITION_PID
) { 
2697                                 condition_tlv_length 
+= (sizeof(pid_t
) + sizeof(int32_t)); 
2700                         if (condition_mask 
& NECP_KERNEL_CONDITION_UID
) { 
2701                                 condition_tlv_length 
+= sizeof(uid_t
); 
2704                         if (condition_mask 
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) { 
2705                                 condition_tlv_length 
+= sizeof(struct necp_policy_condition_tc_range
); 
2708                         if (condition_mask 
& NECP_KERNEL_CONDITION_ENTITLEMENT
) { 
2711                         if (condition_mask 
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) { 
2712                                 u_int32_t entitlement_len 
= strlen(policy
->cond_custom_entitlement
) + 1; 
2713                                 condition_tlv_length 
+= entitlement_len
; 
2716                         if (condition_mask 
& NECP_KERNEL_CONDITION_PLATFORM_BINARY
) { 
2719                         if (condition_mask 
& NECP_KERNEL_CONDITION_SDK_VERSION
) { 
2720                                 condition_tlv_length 
+= sizeof(struct necp_policy_condition_sdk_version
); 
2723                         if (condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) { 
2726                         if (condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_START
) { 
2727                                 if (condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_END
) { 
2728                                         condition_tlv_length 
+= sizeof(struct necp_policy_condition_addr_range
); 
2730                                         condition_tlv_length 
+= sizeof(struct necp_policy_condition_addr
); 
2734                         if (condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_START
) { 
2735                                 if (condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_END
) { 
2736                                         condition_tlv_length 
+= sizeof(struct necp_policy_condition_addr_range
); 
2738                                         condition_tlv_length 
+= sizeof(struct necp_policy_condition_addr
); 
2742                         if (condition_mask 
& NECP_KERNEL_CONDITION_AGENT_TYPE
) { 
2743                                 condition_tlv_length 
+= sizeof(struct necp_policy_condition_agent_type
); 
2746                         if (condition_mask 
& NECP_KERNEL_CONDITION_CLIENT_FLAGS
) { 
2747                                 condition_tlv_length 
+= sizeof(u_int32_t
); 
2750                         if (condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_EMPTY
) { 
2753                         if (condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_EMPTY
) { 
2756                         if (condition_mask 
& NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
) { 
2757                                 u_int32_t identifier_len 
= strlen(policy
->cond_signing_identifier
) + 1; 
2758                                 condition_tlv_length 
+= identifier_len
; 
2761                         if (condition_mask 
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) { 
2762                                 condition_tlv_length 
+= sizeof(u_int16_t
); 
2765                         if (condition_mask 
& NECP_KERNEL_CONDITION_IS_LOOPBACK
) { 
2768                         if (condition_mask 
& NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY
) { 
2773                 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. 
2774                 total_allocated_bytes 
+= condition_tlv_length
; 
2776                 u_int8_t 
*tlv_buffer
; 
2777                 MALLOC(tlv_buffer
, u_int8_t 
*, total_allocated_bytes
, M_NECP
, M_NOWAIT 
| M_ZERO
); 
2778                 if (tlv_buffer 
== NULL
) { 
2779                         NECPLOG(LOG_DEBUG
, "Failed to allocate tlv_buffer (%u bytes)", total_allocated_bytes
); 
2783                 u_int8_t 
*cursor 
= tlv_buffer
; 
2784                 cursor 
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ID
, sizeof(policy
->id
), &policy
->id
, tlv_buffer
, total_allocated_bytes
); 
2785                 cursor 
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ORDER
, sizeof(necp_policy_order
), &policy
->order
, tlv_buffer
, total_allocated_bytes
); 
2786                 cursor 
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_SESSION_ORDER
, sizeof(policy
->session_order
), &policy
->session_order
, tlv_buffer
, total_allocated_bytes
); 
2787                 cursor 
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_RESULT_STRING
, result_string_len
, result_string
, tlv_buffer
, total_allocated_bytes
); 
2788                 cursor 
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_OWNER
, proc_name_len
, proc_name_string
, tlv_buffer
, total_allocated_bytes
); 
2791                 u_int8_t q_cond_buf
[N_QUICK
]; // Minor optimization 
2793                 u_int8_t 
*cond_buf
; // To be used for condition TLVs 
2794                 if (condition_tlv_length 
<= N_QUICK
) { 
2795                         cond_buf 
= q_cond_buf
; 
2797                         MALLOC(cond_buf
, u_int8_t 
*, condition_tlv_length
, M_NECP
, M_NOWAIT
); 
2798                         if (cond_buf 
== NULL
) { 
2799                                 NECPLOG(LOG_DEBUG
, "Failed to allocate cond_buffer (%u bytes)", condition_tlv_length
); 
2800                                 FREE(tlv_buffer
, M_NECP
); 
2805                 memset(cond_buf
, 0, condition_tlv_length
); 
2806                 u_int8_t 
*cond_buf_cursor 
= cond_buf
; 
2807                 if (condition_mask 
== NECP_POLICY_CONDITION_DEFAULT
) { 
2808                         cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_DEFAULT
, 0, "", cond_buf
, condition_tlv_length
); 
2810                         if (condition_mask 
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) { 
2811                                 cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_ALL_INTERFACES
, 0, "", cond_buf
, condition_tlv_length
); 
2813                         if (condition_mask 
& NECP_KERNEL_CONDITION_HAS_CLIENT
) { 
2814                                 cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_HAS_CLIENT
, 0, "", cond_buf
, condition_tlv_length
); 
2816                         if (condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) { 
2817                                 cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_LOCAL_NETWORKS
, 0, "", cond_buf
, condition_tlv_length
); 
2819                         if (condition_mask 
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) { 
2820                                 cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_BOUND_INTERFACE
, strlen(if_name
) + 1, 
2821                                     if_name
, cond_buf
, condition_tlv_length
); 
2823                         if (condition_mask 
& NECP_KERNEL_CONDITION_PROTOCOL
) { 
2824                                 cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_IP_PROTOCOL
, sizeof(policy
->cond_protocol
), &policy
->cond_protocol
, 
2825                                     cond_buf
, condition_tlv_length
); 
2827                         if (condition_mask 
& NECP_KERNEL_CONDITION_APP_ID
) { 
2828                                 struct necp_uuid_id_mapping 
*entry 
= necp_uuid_lookup_uuid_with_app_id_locked(policy
->cond_app_id
); 
2829                                 if (entry 
!= NULL
) { 
2830                                         cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_APPLICATION
, sizeof(entry
->uuid
), entry
->uuid
, 
2831                                             cond_buf
, condition_tlv_length
); 
2834                         if (condition_mask 
& NECP_KERNEL_CONDITION_REAL_APP_ID
) { 
2835                                 struct necp_uuid_id_mapping 
*entry 
= necp_uuid_lookup_uuid_with_app_id_locked(policy
->cond_real_app_id
); 
2836                                 if (entry 
!= NULL
) { 
2837                                         cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_REAL_APPLICATION
, sizeof(entry
->uuid
), entry
->uuid
, 
2838                                             cond_buf
, condition_tlv_length
); 
2841                         if (condition_mask 
& NECP_KERNEL_CONDITION_DOMAIN
) { 
2842                                 cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_DOMAIN
, strlen(policy
->cond_domain
) + 1, policy
->cond_domain
, 
2843                                     cond_buf
, condition_tlv_length
); 
2845                         if (condition_mask 
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) { 
2846                                 if (account_id_entry 
!= NULL
) { 
2847                                         cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_ACCOUNT
, strlen(account_id_entry
->string
) + 1, account_id_entry
->string
, 
2848                                             cond_buf
, condition_tlv_length
); 
2851                         if (condition_mask 
& NECP_KERNEL_CONDITION_PID
) { 
2852                                 uint8_t pid_buffer
[sizeof(policy
->cond_pid
) + sizeof(policy
->cond_pid_version
)] = { }; 
2853                                 memcpy(pid_buffer
, &policy
->cond_pid
, sizeof(policy
->cond_pid
)); 
2854                                 memcpy(pid_buffer 
+ sizeof(policy
->cond_pid
), &policy
->cond_pid_version
, sizeof(policy
->cond_pid_version
)); 
2855                                 cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_PID
, sizeof(pid_buffer
), &pid_buffer
, 
2856                                     cond_buf
, condition_tlv_length
); 
2858                         if (condition_mask 
& NECP_KERNEL_CONDITION_UID
) { 
2859                                 cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_UID
, sizeof(policy
->cond_uid
), &policy
->cond_uid
, 
2860                                     cond_buf
, condition_tlv_length
); 
2862                         if (condition_mask 
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) { 
2863                                 cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_TRAFFIC_CLASS
, sizeof(policy
->cond_traffic_class
), &policy
->cond_traffic_class
, 
2864                                     cond_buf
, condition_tlv_length
); 
2866                         if (condition_mask 
& NECP_KERNEL_CONDITION_ENTITLEMENT
) { 
2867                                 cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_ENTITLEMENT
, 0, "", 
2868                                     cond_buf
, condition_tlv_length
); 
2870                         if (condition_mask 
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) { 
2871                                 cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_ENTITLEMENT
, strlen(policy
->cond_custom_entitlement
) + 1, policy
->cond_custom_entitlement
, 
2872                                     cond_buf
, condition_tlv_length
); 
2874                         if (condition_mask 
& NECP_KERNEL_CONDITION_PLATFORM_BINARY
) { 
2875                                 cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_PLATFORM_BINARY
, 0, "", cond_buf
, condition_tlv_length
); 
2877                         if (condition_mask 
& NECP_KERNEL_CONDITION_SDK_VERSION
) { 
2878                                 cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_SDK_VERSION
, 
2879                                     sizeof(policy
->cond_sdk_version
), &policy
->cond_sdk_version
, 
2880                                     cond_buf
, condition_tlv_length
); 
2882                         if (condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_START
) { 
2883                                 if (condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_END
) { 
2884                                         struct necp_policy_condition_addr_range range
; 
2885                                         memcpy(&range
.start_address
, &policy
->cond_local_start
, sizeof(policy
->cond_local_start
)); 
2886                                         memcpy(&range
.end_address
, &policy
->cond_local_end
, sizeof(policy
->cond_local_end
)); 
2887                                         cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE
, sizeof(range
), &range
, 
2888                                             cond_buf
, condition_tlv_length
); 
2890                                         struct necp_policy_condition_addr addr
; 
2891                                         addr
.prefix 
= policy
->cond_local_prefix
; 
2892                                         memcpy(&addr
.address
, &policy
->cond_local_start
, sizeof(policy
->cond_local_start
)); 
2893                                         cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_LOCAL_ADDR
, sizeof(addr
), &addr
, 
2894                                             cond_buf
, condition_tlv_length
); 
2897                         if (condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_START
) { 
2898                                 if (condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_END
) { 
2899                                         struct necp_policy_condition_addr_range range
; 
2900                                         memcpy(&range
.start_address
, &policy
->cond_remote_start
, sizeof(policy
->cond_remote_start
)); 
2901                                         memcpy(&range
.end_address
, &policy
->cond_remote_end
, sizeof(policy
->cond_remote_end
)); 
2902                                         cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE
, sizeof(range
), &range
, 
2903                                             cond_buf
, condition_tlv_length
); 
2905                                         struct necp_policy_condition_addr addr
; 
2906                                         addr
.prefix 
= policy
->cond_remote_prefix
; 
2907                                         memcpy(&addr
.address
, &policy
->cond_remote_start
, sizeof(policy
->cond_remote_start
)); 
2908                                         cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_REMOTE_ADDR
, sizeof(addr
), &addr
, 
2909                                             cond_buf
, condition_tlv_length
); 
2912                         if (condition_mask 
& NECP_KERNEL_CONDITION_AGENT_TYPE
) { 
2913                                 cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_AGENT_TYPE
, 
2914                                     sizeof(policy
->cond_agent_type
), &policy
->cond_agent_type
, 
2915                                     cond_buf
, condition_tlv_length
); 
2917                         if (condition_mask 
& NECP_KERNEL_CONDITION_CLIENT_FLAGS
) { 
2918                                 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
); 
2920                         if (condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_EMPTY
) { 
2921                                 cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY
, 0, "", cond_buf
, condition_tlv_length
); 
2923                         if (condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_EMPTY
) { 
2924                                 cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY
, 0, "", cond_buf
, condition_tlv_length
); 
2926                         if (condition_mask 
& NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
) { 
2927                                 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
, 
2928                                     cond_buf
, condition_tlv_length
); 
2930                         if (condition_mask 
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) { 
2931                                 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
); 
2933                         if (condition_mask 
& NECP_KERNEL_CONDITION_IS_LOOPBACK
) { 
2934                                 cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK
, 0, "", cond_buf
, condition_tlv_length
); 
2936                         if (condition_mask 
& NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY
) { 
2937                                 cond_buf_cursor 
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY
, 0, "", cond_buf
, condition_tlv_length
); 
2941                 cursor 
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_CONDITION
, cond_buf_cursor 
- cond_buf
, cond_buf
, tlv_buffer
, total_allocated_bytes
); 
2942                 if (cond_buf 
!= q_cond_buf
) { 
2943                         FREE(cond_buf
, M_NECP
); 
2946                 tlv_buffer_pointers
[policy_i
] = tlv_buffer
; 
2947                 tlv_buffer_lengths
[policy_i
] = (cursor 
- tlv_buffer
); 
2949                 // This is the length of the TLV for NECP_TLV_POLICY_DUMP 
2950                 total_tlv_len 
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + (cursor 
- tlv_buffer
); 
2954         lck_rw_done(&necp_kernel_policy_lock
); 
2957         if (out_buffer 
!= 0) { 
2958                 if (out_buffer_length 
< total_tlv_len 
+ sizeof(u_int32_t
)) { 
2959                         NECPLOG(LOG_DEBUG
, "out_buffer_length too small (%lu < %lu)", out_buffer_length
, total_tlv_len 
+ sizeof(u_int32_t
)); 
2960                         REPORT_ERROR(NECP_ERROR_INVALID_TLV
); 
2963                 // Allow malloc to wait, since the total buffer may be large and we are not holding any locks 
2964                 MALLOC(result_buf
, u_int8_t 
*, total_tlv_len 
+ sizeof(u_int32_t
), M_NECP
, M_WAITOK 
| M_ZERO
); 
2965                 if (result_buf 
== NULL
) { 
2966                         NECPLOG(LOG_DEBUG
, "Failed to allocate result_buffer (%lu bytes)", total_tlv_len 
+ sizeof(u_int32_t
)); 
2967                         REPORT_ERROR(NECP_ERROR_INTERNAL
); 
2970                 // Add four bytes for total length at the start 
2971                 memcpy(result_buf
, &total_tlv_len
, sizeof(u_int32_t
)); 
2974                 result_buf_cursor 
= result_buf 
+ sizeof(u_int32_t
); 
2975                 for (int i 
= 0; i 
< policy_count
; i
++) { 
2976                         if (tlv_buffer_pointers
[i
] != NULL
) { 
2977                                 result_buf_cursor 
= necp_buffer_write_tlv(result_buf_cursor
, NECP_TLV_POLICY_DUMP
, tlv_buffer_lengths
[i
], tlv_buffer_pointers
[i
], 
2978                                     result_buf
, total_tlv_len 
+ sizeof(u_int32_t
)); 
2982                 int copy_error 
= copyout(result_buf
, out_buffer
, total_tlv_len 
+ sizeof(u_int32_t
)); 
2984                         NECPLOG(LOG_DEBUG
, "Failed to copy out result_buffer (%lu bytes)", total_tlv_len 
+ sizeof(u_int32_t
)); 
2985                         REPORT_ERROR(NECP_ERROR_INTERNAL
); 
2991         if (error_occured
) { 
2992                 error_code 
= necp_get_posix_error_for_necp_error(response_error
); 
2995         if (result_buf 
!= NULL
) { 
2996                 FREE(result_buf
, M_NECP
); 
2999         if (tlv_buffer_pointers 
!= NULL
) { 
3000                 for (int i 
= 0; i 
< policy_count
; i
++) { 
3001                         if (tlv_buffer_pointers
[i
] != NULL
) { 
3002                                 FREE(tlv_buffer_pointers
[i
], M_NECP
); 
3003                                 tlv_buffer_pointers
[i
] = NULL
; 
3006                 FREE(tlv_buffer_pointers
, M_NECP
); 
3009         if (tlv_buffer_lengths 
!= NULL
) { 
3010                 FREE(tlv_buffer_lengths
, M_NECP
); 
3013 #undef RESET_COND_BUF 
3015 #undef UNLOCK_AND_REPORT_ERROR 
3020 static struct necp_session_policy 
* 
3021 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
) 
3023         struct necp_session_policy 
*new_policy 
= NULL
; 
3024         struct necp_session_policy 
*tmp_policy 
= NULL
; 
3026         if (session 
== NULL 
|| conditions_array 
== NULL 
|| result 
== NULL 
|| result_size 
== 0) { 
3030         new_policy 
= zalloc_flags(necp_session_policy_zone
, Z_WAITOK 
| Z_ZERO
); 
3031         new_policy
->applied 
= FALSE
; 
3032         new_policy
->pending_deletion 
= FALSE
; 
3033         new_policy
->pending_update 
= FALSE
; 
3034         new_policy
->order 
= order
; 
3035         new_policy
->conditions 
= conditions_array
; 
3036         new_policy
->conditions_size 
= conditions_array_size
; 
3037         new_policy
->route_rules 
= route_rules_array
; 
3038         new_policy
->route_rules_size 
= route_rules_array_size
; 
3039         new_policy
->result 
= result
; 
3040         new_policy
->result_size 
= result_size
; 
3041         new_policy
->local_id 
= necp_policy_get_new_id(session
); 
3043         LIST_INSERT_SORTED_ASCENDING(&session
->policies
, new_policy
, chain
, order
, tmp_policy
); 
3045         session
->dirty 
= TRUE
; 
3048                 NECPLOG(LOG_DEBUG
, "Created NECP policy, order %d", order
); 
3054 static struct necp_session_policy 
* 
3055 necp_policy_find(struct necp_session 
*session
, necp_policy_id policy_id
) 
3057         struct necp_session_policy 
*policy 
= NULL
; 
3058         if (policy_id 
== 0) { 
3062         LIST_FOREACH(policy
, &session
->policies
, chain
) { 
3063                 if (policy
->local_id 
== policy_id
) { 
3071 static inline u_int8_t
 
3072 necp_policy_get_result_type(struct necp_session_policy 
*policy
) 
3074         return policy 
? necp_policy_result_get_type_from_buffer(policy
->result
, policy
->result_size
) : 0; 
3077 static inline u_int32_t
 
3078 necp_policy_get_result_parameter_length(struct necp_session_policy 
*policy
) 
3080         return policy 
? necp_policy_result_get_parameter_length_from_buffer(policy
->result
, policy
->result_size
) : 0; 
3084 necp_policy_get_result_parameter(struct necp_session_policy 
*policy
, u_int8_t 
*parameter_buffer
, u_int32_t parameter_buffer_length
) 
3087                 u_int32_t parameter_length 
= necp_policy_result_get_parameter_length_from_buffer(policy
->result
, policy
->result_size
); 
3088                 if (parameter_buffer_length 
>= parameter_length
) { 
3089                         u_int8_t 
*parameter 
= necp_policy_result_get_parameter_pointer_from_buffer(policy
->result
, policy
->result_size
); 
3090                         if (parameter 
&& parameter_buffer
) { 
3091                                 memcpy(parameter_buffer
, parameter
, parameter_length
); 
3101 necp_policy_mark_for_deletion(struct necp_session 
*session
, struct necp_session_policy 
*policy
) 
3103         if (session 
== NULL 
|| policy 
== NULL
) { 
3107         policy
->pending_deletion 
= TRUE
; 
3108         session
->dirty 
= TRUE
; 
3111                 NECPLOG0(LOG_DEBUG
, "Marked NECP policy for removal"); 
3117 necp_policy_mark_all_for_deletion(struct necp_session 
*session
) 
3119         struct necp_session_policy 
*policy 
= NULL
; 
3120         struct necp_session_policy 
*temp_policy 
= NULL
; 
3122         LIST_FOREACH_SAFE(policy
, &session
->policies
, chain
, temp_policy
) { 
3123                 necp_policy_mark_for_deletion(session
, policy
); 
3130 necp_policy_delete(struct necp_session 
*session
, struct necp_session_policy 
*policy
) 
3132         if (session 
== NULL 
|| policy 
== NULL
) { 
3136         LIST_REMOVE(policy
, chain
); 
3138         if (policy
->result
) { 
3139                 FREE(policy
->result
, M_NECP
); 
3140                 policy
->result 
= NULL
; 
3143         if (policy
->conditions
) { 
3144                 FREE(policy
->conditions
, M_NECP
); 
3145                 policy
->conditions 
= NULL
; 
3148         if (policy
->route_rules
) { 
3149                 FREE(policy
->route_rules
, M_NECP
); 
3150                 policy
->route_rules 
= NULL
; 
3153         zfree(necp_session_policy_zone
, policy
); 
3156                 NECPLOG0(LOG_DEBUG
, "Removed NECP policy"); 
3162 necp_policy_unapply(struct necp_session_policy 
*policy
) 
3165         if (policy 
== NULL
) { 
3169         LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
); 
3171         // Release local uuid mappings 
3172         if (!uuid_is_null(policy
->applied_app_uuid
)) { 
3173                 bool removed_mapping 
= FALSE
; 
3174                 if (necp_remove_uuid_app_id_mapping(policy
->applied_app_uuid
, &removed_mapping
, TRUE
) && removed_mapping
) { 
3175                         necp_uuid_app_id_mappings_dirty 
= TRUE
; 
3176                         necp_num_uuid_app_id_mappings
--; 
3178                 uuid_clear(policy
->applied_app_uuid
); 
3180         if (!uuid_is_null(policy
->applied_real_app_uuid
)) { 
3181                 necp_remove_uuid_app_id_mapping(policy
->applied_real_app_uuid
, NULL
, FALSE
); 
3182                 uuid_clear(policy
->applied_real_app_uuid
); 
3184         if (!uuid_is_null(policy
->applied_result_uuid
)) { 
3185                 necp_remove_uuid_service_id_mapping(policy
->applied_result_uuid
); 
3186                 uuid_clear(policy
->applied_result_uuid
); 
3189         // Release string mappings 
3190         if (policy
->applied_account 
!= NULL
) { 
3191                 necp_remove_string_to_id_mapping(&necp_account_id_list
, policy
->applied_account
); 
3192                 FREE(policy
->applied_account
, M_NECP
); 
3193                 policy
->applied_account 
= NULL
; 
3196         // Release route rule 
3197         if (policy
->applied_route_rules_id 
!= 0) { 
3198                 necp_remove_route_rule(&necp_route_rules
, policy
->applied_route_rules_id
); 
3199                 policy
->applied_route_rules_id 
= 0; 
3202         // Remove socket policies 
3203         for (i 
= 0; i 
< MAX_KERNEL_SOCKET_POLICIES
; i
++) { 
3204                 if (policy
->kernel_socket_policies
[i
] != 0) { 
3205                         necp_kernel_socket_policy_delete(policy
->kernel_socket_policies
[i
]); 
3206                         policy
->kernel_socket_policies
[i
] = 0; 
3210         // Remove IP output policies 
3211         for (i 
= 0; i 
< MAX_KERNEL_IP_OUTPUT_POLICIES
; i
++) { 
3212                 if (policy
->kernel_ip_output_policies
[i
] != 0) { 
3213                         necp_kernel_ip_output_policy_delete(policy
->kernel_ip_output_policies
[i
]); 
3214                         policy
->kernel_ip_output_policies
[i
] = 0; 
3218         policy
->applied 
= FALSE
; 
3223 #define NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION                 0 
3224 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION             1 
3225 #define NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION                                2 
3226 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS                   3 
3227 struct necp_policy_result_ip_tunnel 
{ 
3228         u_int32_t secondary_result
; 
3229         char interface_name
[IFXNAMSIZ
]; 
3230 } __attribute__((__packed__
)); 
3232 struct necp_policy_result_service 
{ 
3235 } __attribute__((__packed__
)); 
3238 necp_policy_apply(struct necp_session 
*session
, struct necp_session_policy 
*policy
) 
3240         bool socket_only_conditions 
= FALSE
; 
3241         bool socket_ip_conditions 
= FALSE
; 
3243         bool socket_layer_non_id_conditions 
= FALSE
; 
3244         bool ip_output_layer_non_id_conditions 
= FALSE
; 
3245         bool ip_output_layer_non_id_only 
= FALSE
; 
3246         bool ip_output_layer_id_condition 
= FALSE
; 
3247         bool ip_output_layer_tunnel_condition_from_id 
= FALSE
; 
3248         bool ip_output_layer_tunnel_condition_from_non_id 
= FALSE
; 
3249         necp_kernel_policy_id cond_ip_output_layer_id 
= NECP_KERNEL_POLICY_ID_NONE
; 
3251         u_int32_t master_condition_mask 
= 0; 
3252         u_int32_t master_condition_negated_mask 
= 0; 
3253         ifnet_t cond_bound_interface 
= NULL
; 
3254         u_int32_t cond_account_id 
= 0; 
3255         char *cond_domain 
= NULL
; 
3256         char *cond_custom_entitlement 
= NULL
; 
3257         char *cond_signing_identifier 
= NULL
; 
3259         int32_t cond_pid_version 
= 0; 
3261         necp_app_id cond_app_id 
= 0; 
3262         necp_app_id cond_real_app_id 
= 0; 
3263         struct necp_policy_condition_tc_range cond_traffic_class
; 
3264         cond_traffic_class
.start_tc 
= 0; 
3265         cond_traffic_class
.end_tc 
= 0; 
3266         u_int16_t cond_protocol 
= 0; 
3267         union necp_sockaddr_union cond_local_start
; 
3268         union necp_sockaddr_union cond_local_end
; 
3269         u_int8_t cond_local_prefix 
= 0; 
3270         union necp_sockaddr_union cond_remote_start
; 
3271         union necp_sockaddr_union cond_remote_end
; 
3272         u_int8_t cond_remote_prefix 
= 0; 
3273         u_int32_t cond_client_flags 
= 0; 
3274         u_int32_t offset 
= 0; 
3275         u_int8_t ultimate_result 
= 0; 
3276         u_int32_t secondary_result 
= 0; 
3277         struct necp_policy_condition_agent_type cond_agent_type 
= {}; 
3278         struct necp_policy_condition_sdk_version cond_sdk_version 
= {}; 
3279         u_int16_t cond_packet_filter_tags 
= 0; 
3280         necp_kernel_policy_result_parameter secondary_result_parameter
; 
3281         memset(&secondary_result_parameter
, 0, sizeof(secondary_result_parameter
)); 
3282         u_int32_t cond_last_interface_index 
= 0; 
3283         necp_kernel_policy_result_parameter ultimate_result_parameter
; 
3284         memset(&ultimate_result_parameter
, 0, sizeof(ultimate_result_parameter
)); 
3286         if (policy 
== NULL
) { 
3290         LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
); 
3292         // Process conditions 
3293         while (offset 
< policy
->conditions_size
) { 
3294                 u_int32_t length 
= 0; 
3295                 u_int8_t 
*value 
= necp_buffer_get_tlv_value(policy
->conditions
, offset
, &length
); 
3297                 u_int8_t condition_type 
= necp_policy_condition_get_type_from_buffer(value
, length
); 
3298                 u_int8_t condition_flags 
= necp_policy_condition_get_flags_from_buffer(value
, length
); 
3299                 bool condition_is_negative 
= condition_flags 
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
; 
3300                 u_int32_t condition_length 
= necp_policy_condition_get_value_length_from_buffer(value
, length
); 
3301                 u_int8_t 
*condition_value 
= necp_policy_condition_get_value_pointer_from_buffer(value
, length
); 
3302                 switch (condition_type
) { 
3303                 case NECP_POLICY_CONDITION_DEFAULT
: { 
3304                         socket_ip_conditions 
= TRUE
; 
3307                 case NECP_POLICY_CONDITION_ALL_INTERFACES
: { 
3308                         master_condition_mask 
|= NECP_KERNEL_CONDITION_ALL_INTERFACES
; 
3309                         socket_ip_conditions 
= TRUE
; 
3312                 case NECP_POLICY_CONDITION_HAS_CLIENT
: { 
3313                         master_condition_mask 
|= NECP_KERNEL_CONDITION_HAS_CLIENT
; 
3314                         socket_only_conditions 
= TRUE
; 
3317                 case NECP_POLICY_CONDITION_ENTITLEMENT
: { 
3318                         if (condition_length 
> 0) { 
3319                                 if (cond_custom_entitlement 
== NULL
) { 
3320                                         cond_custom_entitlement 
= necp_copy_string((char *)condition_value
, condition_length
); 
3321                                         if (cond_custom_entitlement 
!= NULL
) { 
3322                                                 master_condition_mask 
|= NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
; 
3323                                                 socket_only_conditions 
= TRUE
; 
3327                                 master_condition_mask 
|= NECP_KERNEL_CONDITION_ENTITLEMENT
; 
3328                                 socket_only_conditions 
= TRUE
; 
3332                 case NECP_POLICY_CONDITION_PLATFORM_BINARY
: { 
3333                         master_condition_mask 
|= NECP_KERNEL_CONDITION_PLATFORM_BINARY
; 
3334                         socket_only_conditions 
= TRUE
; 
3337                 case NECP_POLICY_CONDITION_SDK_VERSION
: { 
3338                         if (condition_length 
>= sizeof(cond_sdk_version
)) { 
3339                                 master_condition_mask 
|= NECP_KERNEL_CONDITION_SDK_VERSION
; 
3340                                 memcpy(&cond_sdk_version
, condition_value
, sizeof(cond_sdk_version
)); 
3341                                 socket_only_conditions 
= TRUE
; 
3345                 case NECP_POLICY_CONDITION_DOMAIN
: { 
3346                         // Make sure there is only one such rule 
3347                         if (condition_length 
> 0 && cond_domain 
== NULL
) { 
3348                                 cond_domain 
= necp_create_trimmed_domain((char *)condition_value
, condition_length
); 
3349                                 if (cond_domain 
!= NULL
) { 
3350                                         master_condition_mask 
|= NECP_KERNEL_CONDITION_DOMAIN
; 
3351                                         if (condition_is_negative
) { 
3352                                                 master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_DOMAIN
; 
3354                                         socket_only_conditions 
= TRUE
; 
3359                 case NECP_POLICY_CONDITION_ACCOUNT
: { 
3360                         // Make sure there is only one such rule 
3361                         if (condition_length 
> 0 && cond_account_id 
== 0 && policy
->applied_account 
== NULL
) { 
3362                                 char *string 
= NULL
; 
3363                                 MALLOC(string
, char *, condition_length 
+ 1, M_NECP
, M_WAITOK
); 
3364                                 if (string 
!= NULL
) { 
3365                                         memcpy(string
, condition_value
, condition_length
); 
3366                                         string
[condition_length
] = 0; 
3367                                         cond_account_id 
= necp_create_string_to_id_mapping(&necp_account_id_list
, string
); 
3368                                         if (cond_account_id 
!= 0) { 
3369                                                 policy
->applied_account 
= string
;         // Save the string in parent policy 
3370                                                 master_condition_mask 
|= NECP_KERNEL_CONDITION_ACCOUNT_ID
; 
3371                                                 if (condition_is_negative
) { 
3372                                                         master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_ACCOUNT_ID
; 
3374                                                 socket_only_conditions 
= TRUE
; 
3376                                                 FREE(string
, M_NECP
); 
3382                 case NECP_POLICY_CONDITION_APPLICATION
: { 
3383                         // Make sure there is only one such rule, because we save the uuid in the policy 
3384                         if (condition_length 
>= sizeof(uuid_t
) && cond_app_id 
== 0) { 
3385                                 bool allocated_mapping 
= FALSE
; 
3386                                 uuid_t application_uuid
; 
3387                                 memcpy(application_uuid
, condition_value
, sizeof(uuid_t
)); 
3388                                 cond_app_id 
= necp_create_uuid_app_id_mapping(application_uuid
, &allocated_mapping
, TRUE
); 
3389                                 if (cond_app_id 
!= 0) { 
3390                                         if (allocated_mapping
) { 
3391                                                 necp_uuid_app_id_mappings_dirty 
= TRUE
; 
3392                                                 necp_num_uuid_app_id_mappings
++; 
3394                                         uuid_copy(policy
->applied_app_uuid
, application_uuid
); 
3395                                         master_condition_mask 
|= NECP_KERNEL_CONDITION_APP_ID
; 
3396                                         if (condition_is_negative
) { 
3397                                                 master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_APP_ID
; 
3399                                         socket_only_conditions 
= TRUE
; 
3404                 case NECP_POLICY_CONDITION_REAL_APPLICATION
: { 
3405                         // Make sure there is only one such rule, because we save the uuid in the policy 
3406                         if (condition_length 
>= sizeof(uuid_t
) && cond_real_app_id 
== 0) { 
3407                                 uuid_t real_application_uuid
; 
3408                                 memcpy(real_application_uuid
, condition_value
, sizeof(uuid_t
)); 
3409                                 cond_real_app_id 
= necp_create_uuid_app_id_mapping(real_application_uuid
, NULL
, FALSE
); 
3410                                 if (cond_real_app_id 
!= 0) { 
3411                                         uuid_copy(policy
->applied_real_app_uuid
, real_application_uuid
); 
3412                                         master_condition_mask 
|= NECP_KERNEL_CONDITION_REAL_APP_ID
; 
3413                                         if (condition_is_negative
) { 
3414                                                 master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_REAL_APP_ID
; 
3416                                         socket_only_conditions 
= TRUE
; 
3421                 case NECP_POLICY_CONDITION_PID
: { 
3422                         if (condition_length 
>= sizeof(pid_t
)) { 
3423                                 master_condition_mask 
|= NECP_KERNEL_CONDITION_PID
; 
3424                                 if (condition_is_negative
) { 
3425                                         master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_PID
; 
3427                                 memcpy(&cond_pid
, condition_value
, sizeof(cond_pid
)); 
3428                                 if (condition_length 
>= (sizeof(pid_t
) + sizeof(cond_pid_version
))) { 
3429                                         memcpy(&cond_pid_version
, (condition_value 
+ sizeof(pid_t
)), sizeof(cond_pid_version
)); 
3431                                 socket_only_conditions 
= TRUE
; 
3435                 case NECP_POLICY_CONDITION_UID
: { 
3436                         if (condition_length 
>= sizeof(uid_t
)) { 
3437                                 master_condition_mask 
|= NECP_KERNEL_CONDITION_UID
; 
3438                                 if (condition_is_negative
) { 
3439                                         master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_UID
; 
3441                                 memcpy(&cond_uid
, condition_value
, sizeof(cond_uid
)); 
3442                                 socket_only_conditions 
= TRUE
; 
3446                 case NECP_POLICY_CONDITION_TRAFFIC_CLASS
: { 
3447                         if (condition_length 
>= sizeof(struct necp_policy_condition_tc_range
)) { 
3448                                 master_condition_mask 
|= NECP_KERNEL_CONDITION_TRAFFIC_CLASS
; 
3449                                 if (condition_is_negative
) { 
3450                                         master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_TRAFFIC_CLASS
; 
3452                                 memcpy(&cond_traffic_class
, condition_value
, sizeof(cond_traffic_class
)); 
3453                                 socket_only_conditions 
= TRUE
; 
3457                 case NECP_POLICY_CONDITION_BOUND_INTERFACE
: { 
3458                         if (condition_length 
<= IFXNAMSIZ 
&& condition_length 
> 0) { 
3459                                 char interface_name
[IFXNAMSIZ
]; 
3460                                 memcpy(interface_name
, condition_value
, condition_length
); 
3461                                 interface_name
[condition_length 
- 1] = 0;         // Make sure the string is NULL terminated 
3462                                 if (ifnet_find_by_name(interface_name
, &cond_bound_interface
) == 0) { 
3463                                         master_condition_mask 
|= NECP_KERNEL_CONDITION_BOUND_INTERFACE
; 
3464                                         if (condition_is_negative
) { 
3465                                                 master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_BOUND_INTERFACE
; 
3468                                 socket_ip_conditions 
= TRUE
; 
3472                 case NECP_POLICY_CONDITION_IP_PROTOCOL
: 
3473                 case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL
: { 
3474                         if (condition_length 
>= sizeof(u_int16_t
)) { 
3475                                 master_condition_mask 
|= NECP_KERNEL_CONDITION_PROTOCOL
; 
3476                                 if (condition_is_negative
) { 
3477                                         master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_PROTOCOL
; 
3479                                 memcpy(&cond_protocol
, condition_value
, sizeof(cond_protocol
)); 
3480                                 if (condition_type 
== NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL
) { 
3481                                         socket_only_conditions 
= TRUE
; 
3483                                         socket_ip_conditions 
= TRUE
; 
3488                 case NECP_POLICY_CONDITION_LOCAL_NETWORKS
: { 
3489                         master_condition_mask 
|= NECP_KERNEL_CONDITION_LOCAL_NETWORKS
; 
3490                         socket_ip_conditions 
= TRUE
; 
3493                 case NECP_POLICY_CONDITION_LOCAL_ADDR
: 
3494                 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR
: { 
3495                         struct necp_policy_condition_addr 
*address_struct 
= (struct necp_policy_condition_addr 
*)(void *)condition_value
; 
3496                         if (!necp_address_is_valid(&address_struct
->address
.sa
)) { 
3500                         cond_local_prefix 
= address_struct
->prefix
; 
3501                         memcpy(&cond_local_start
, &address_struct
->address
, sizeof(address_struct
->address
)); 
3502                         master_condition_mask 
|= NECP_KERNEL_CONDITION_LOCAL_START
; 
3503                         master_condition_mask 
|= NECP_KERNEL_CONDITION_LOCAL_PREFIX
; 
3504                         if (condition_is_negative
) { 
3505                                 master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_LOCAL_START
; 
3506                                 master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_LOCAL_PREFIX
; 
3508                         if (condition_type 
== NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR
) { 
3509                                 socket_only_conditions 
= TRUE
; 
3511                                 socket_ip_conditions 
= TRUE
; 
3515                 case NECP_POLICY_CONDITION_REMOTE_ADDR
: 
3516                 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR
: { 
3517                         struct necp_policy_condition_addr 
*address_struct 
= (struct necp_policy_condition_addr 
*)(void *)condition_value
; 
3518                         if (!necp_address_is_valid(&address_struct
->address
.sa
)) { 
3522                         cond_remote_prefix 
= address_struct
->prefix
; 
3523                         memcpy(&cond_remote_start
, &address_struct
->address
, sizeof(address_struct
->address
)); 
3524                         master_condition_mask 
|= NECP_KERNEL_CONDITION_REMOTE_START
; 
3525                         master_condition_mask 
|= NECP_KERNEL_CONDITION_REMOTE_PREFIX
; 
3526                         if (condition_is_negative
) { 
3527                                 master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_REMOTE_START
; 
3528                                 master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_REMOTE_PREFIX
; 
3530                         if (condition_type 
== NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR
) { 
3531                                 socket_only_conditions 
= TRUE
; 
3533                                 socket_ip_conditions 
= TRUE
; 
3537                 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE
: 
3538                 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE
: { 
3539                         struct necp_policy_condition_addr_range 
*address_struct 
= (struct necp_policy_condition_addr_range 
*)(void *)condition_value
; 
3540                         if (!necp_address_is_valid(&address_struct
->start_address
.sa
) || 
3541                             !necp_address_is_valid(&address_struct
->end_address
.sa
)) { 
3545                         memcpy(&cond_local_start
, &address_struct
->start_address
, sizeof(address_struct
->start_address
)); 
3546                         memcpy(&cond_local_end
, &address_struct
->end_address
, sizeof(address_struct
->end_address
)); 
3547                         master_condition_mask 
|= NECP_KERNEL_CONDITION_LOCAL_START
; 
3548                         master_condition_mask 
|= NECP_KERNEL_CONDITION_LOCAL_END
; 
3549                         if (condition_is_negative
) { 
3550                                 master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_LOCAL_START
; 
3551                                 master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_LOCAL_END
; 
3553                         if (condition_type 
== NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE
) { 
3554                                 socket_only_conditions 
= TRUE
; 
3556                                 socket_ip_conditions 
= TRUE
; 
3560                 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE
: 
3561                 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE
: { 
3562                         struct necp_policy_condition_addr_range 
*address_struct 
= (struct necp_policy_condition_addr_range 
*)(void *)condition_value
; 
3563                         if (!necp_address_is_valid(&address_struct
->start_address
.sa
) || 
3564                             !necp_address_is_valid(&address_struct
->end_address
.sa
)) { 
3568                         memcpy(&cond_remote_start
, &address_struct
->start_address
, sizeof(address_struct
->start_address
)); 
3569                         memcpy(&cond_remote_end
, &address_struct
->end_address
, sizeof(address_struct
->end_address
)); 
3570                         master_condition_mask 
|= NECP_KERNEL_CONDITION_REMOTE_START
; 
3571                         master_condition_mask 
|= NECP_KERNEL_CONDITION_REMOTE_END
; 
3572                         if (condition_is_negative
) { 
3573                                 master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_REMOTE_START
; 
3574                                 master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_REMOTE_END
; 
3576                         if (condition_type 
== NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE
) { 
3577                                 socket_only_conditions 
= TRUE
; 
3579                                 socket_ip_conditions 
= TRUE
; 
3583                 case NECP_POLICY_CONDITION_AGENT_TYPE
: { 
3584                         if (condition_length 
>= sizeof(cond_agent_type
)) { 
3585                                 master_condition_mask 
|= NECP_KERNEL_CONDITION_AGENT_TYPE
; 
3586                                 memcpy(&cond_agent_type
, condition_value
, sizeof(cond_agent_type
)); 
3587                                 socket_only_conditions 
= TRUE
; 
3591                 case NECP_POLICY_CONDITION_CLIENT_FLAGS
: { 
3592                         if (condition_is_negative
) { 
3593                                 master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_CLIENT_FLAGS
; 
3595                         master_condition_mask 
|= NECP_KERNEL_CONDITION_CLIENT_FLAGS
; 
3596                         socket_only_conditions 
= TRUE
; 
3597                         if (condition_length 
>= sizeof(u_int32_t
)) { 
3598                                 memcpy(&cond_client_flags
, condition_value
, sizeof(cond_client_flags
)); 
3600                                 // Empty means match on fallback traffic 
3601                                 cond_client_flags 
= NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC
; 
3605                 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY
: { 
3606                         master_condition_mask 
|= NECP_KERNEL_CONDITION_LOCAL_EMPTY
; 
3607                         if (condition_is_negative
) { 
3608                                 master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_LOCAL_EMPTY
; 
3610                         socket_only_conditions 
= TRUE
; 
3613                 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY
: { 
3614                         master_condition_mask 
|= NECP_KERNEL_CONDITION_REMOTE_EMPTY
; 
3615                         if (condition_is_negative
) { 
3616                                 master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_REMOTE_EMPTY
; 
3618                         socket_only_conditions 
= TRUE
; 
3621                 case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER
: { 
3622                         if (condition_length 
> 0) { 
3623                                 if (cond_signing_identifier 
== NULL
) { 
3624                                         cond_signing_identifier 
= necp_copy_string((char *)condition_value
, condition_length
); 
3625                                         if (cond_signing_identifier 
!= NULL
) { 
3626                                                 master_condition_mask 
|= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
; 
3627                                                 socket_only_conditions 
= TRUE
; 
3628                                                 if (condition_is_negative
) { 
3629                                                         master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
; 
3636                 case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS
: { 
3637                         if (condition_length 
>= sizeof(u_int16_t
)) { 
3638                                 master_condition_mask 
|= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
; 
3639                                 if (condition_is_negative
) { 
3640                                         master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
; 
3642                                 memcpy(&cond_packet_filter_tags
, condition_value
, sizeof(cond_packet_filter_tags
)); 
3643                                 socket_ip_conditions 
= TRUE
; 
3647                 case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK
: { 
3648                         master_condition_mask 
|= NECP_KERNEL_CONDITION_IS_LOOPBACK
; 
3649                         if (condition_is_negative
) { 
3650                                 master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_IS_LOOPBACK
; 
3652                         socket_only_conditions 
= TRUE
; 
3655                 case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY
: { 
3656                         master_condition_mask 
|= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY
; 
3657                         if (condition_is_negative
) { 
3658                                 master_condition_negated_mask 
|= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY
; 
3660                         socket_only_conditions 
= TRUE
; 
3668                 offset 
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
; 
3672         ultimate_result 
= necp_policy_get_result_type(policy
); 
3673         switch (ultimate_result
) { 
3674         case NECP_POLICY_RESULT_PASS
: { 
3675                 u_int32_t pass_flags 
= 0; 
3676                 if (necp_policy_result_get_parameter_length_from_buffer(policy
->result
, policy
->result_size
) > 0) { 
3677                         if (necp_policy_get_result_parameter(policy
, (u_int8_t 
*)&pass_flags
, sizeof(pass_flags
))) { 
3678                                 ultimate_result_parameter
.pass_flags 
= pass_flags
; 
3681                 if (socket_only_conditions
) {         // socket_ip_conditions can be TRUE or FALSE 
3682                         socket_layer_non_id_conditions 
= TRUE
; 
3683                         ip_output_layer_id_condition 
= TRUE
; 
3684                 } else if (socket_ip_conditions
) { 
3685                         socket_layer_non_id_conditions 
= TRUE
; 
3686                         ip_output_layer_id_condition 
= TRUE
; 
3687                         ip_output_layer_non_id_conditions 
= TRUE
; 
3691         case NECP_POLICY_RESULT_DROP
: { 
3692                 u_int32_t drop_flags 
= 0; 
3693                 if (necp_policy_result_get_parameter_length_from_buffer(policy
->result
, policy
->result_size
) > 0) { 
3694                         if (necp_policy_get_result_parameter(policy
, (u_int8_t 
*)&drop_flags
, sizeof(drop_flags
))) { 
3695                                 ultimate_result_parameter
.drop_flags 
= drop_flags
; 
3698                 if (socket_only_conditions
) {         // socket_ip_conditions can be TRUE or FALSE 
3699                         socket_layer_non_id_conditions 
= TRUE
; 
3700                 } else if (socket_ip_conditions
) { 
3701                         socket_layer_non_id_conditions 
= TRUE
; 
3702                         ip_output_layer_non_id_conditions 
= TRUE
; 
3703                         ip_output_layer_non_id_only 
= TRUE
;         // Only apply drop to packets that didn't go through socket layer 
3707         case NECP_POLICY_RESULT_SKIP
: { 
3708                 u_int32_t skip_policy_order 
= 0; 
3709                 if (necp_policy_get_result_parameter(policy
, (u_int8_t 
*)&skip_policy_order
, sizeof(skip_policy_order
))) { 
3710                         ultimate_result_parameter
.skip_policy_order 
= skip_policy_order
; 
3713                 if (socket_only_conditions
) {         // socket_ip_conditions can be TRUE or FALSE 
3714                         socket_layer_non_id_conditions 
= TRUE
; 
3715                         ip_output_layer_id_condition 
= TRUE
; 
3716                 } else if (socket_ip_conditions
) { 
3717                         socket_layer_non_id_conditions 
= TRUE
; 
3718                         ip_output_layer_non_id_conditions 
= TRUE
; 
3722         case NECP_POLICY_RESULT_SOCKET_DIVERT
: 
3723         case NECP_POLICY_RESULT_SOCKET_FILTER
: { 
3724                 u_int32_t control_unit 
= 0; 
3725                 if (necp_policy_get_result_parameter(policy
, (u_int8_t 
*)&control_unit
, sizeof(control_unit
))) { 
3726                         ultimate_result_parameter
.flow_divert_control_unit 
= control_unit
; 
3728                 socket_layer_non_id_conditions 
= TRUE
; 
3731         case NECP_POLICY_RESULT_IP_TUNNEL
: { 
3732                 struct necp_policy_result_ip_tunnel tunnel_parameters
; 
3733                 u_int32_t tunnel_parameters_length 
= necp_policy_get_result_parameter_length(policy
); 
3734                 if (tunnel_parameters_length 
> sizeof(u_int32_t
) && 
3735                     tunnel_parameters_length 
<= sizeof(struct necp_policy_result_ip_tunnel
) && 
3736                     necp_policy_get_result_parameter(policy
, (u_int8_t 
*)&tunnel_parameters
, sizeof(tunnel_parameters
))) { 
3737                         ifnet_t tunnel_interface 
= NULL
; 
3738                         tunnel_parameters
.interface_name
[tunnel_parameters_length 
- sizeof(u_int32_t
) - 1] = 0;         // Make sure the string is NULL terminated 
3739                         if (ifnet_find_by_name(tunnel_parameters
.interface_name
, &tunnel_interface
) == 0) { 
3740                                 ultimate_result_parameter
.tunnel_interface_index 
= tunnel_interface
->if_index
; 
3741                                 ifnet_release(tunnel_interface
); 
3744                         secondary_result 
= tunnel_parameters
.secondary_result
; 
3745                         if (secondary_result
) { 
3746                                 cond_last_interface_index 
= ultimate_result_parameter
.tunnel_interface_index
; 
3750                 if (socket_only_conditions
) {         // socket_ip_conditions can be TRUE or FALSE 
3751                         socket_layer_non_id_conditions 
= TRUE
; 
3752                         ip_output_layer_id_condition 
= TRUE
; 
3753                         if (secondary_result
) { 
3754                                 ip_output_layer_tunnel_condition_from_id 
= TRUE
; 
3756                 } else if (socket_ip_conditions
) { 
3757                         socket_layer_non_id_conditions 
= TRUE
; 
3758                         ip_output_layer_id_condition 
= TRUE
; 
3759                         ip_output_layer_non_id_conditions 
= TRUE
; 
3760                         if (secondary_result
) { 
3761                                 ip_output_layer_tunnel_condition_from_id 
= TRUE
; 
3762                                 ip_output_layer_tunnel_condition_from_non_id 
= TRUE
; 
3767         case NECP_POLICY_RESULT_TRIGGER
: 
3768         case NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
: 
3769         case NECP_POLICY_RESULT_TRIGGER_SCOPED
: 
3770         case NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
: { 
3771                 struct necp_policy_result_service service_parameters
; 
3772                 u_int32_t service_result_length 
= necp_policy_get_result_parameter_length(policy
); 
3773                 bool has_extra_service_data 
= FALSE
; 
3774                 if (service_result_length 
>= (sizeof(service_parameters
))) { 
3775                         has_extra_service_data 
= TRUE
; 
3777                 if (necp_policy_get_result_parameter(policy
, (u_int8_t 
*)&service_parameters
, sizeof(service_parameters
))) { 
3778                         ultimate_result_parameter
.service
.identifier 
= necp_create_uuid_service_id_mapping(service_parameters
.identifier
); 
3779                         if (ultimate_result_parameter
.service
.identifier 
!= 0) { 
3780                                 uuid_copy(policy
->applied_result_uuid
, service_parameters
.identifier
); 
3781                                 socket_layer_non_id_conditions 
= TRUE
; 
3782                                 if (has_extra_service_data
) { 
3783                                         ultimate_result_parameter
.service
.data 
= service_parameters
.data
; 
3785                                         ultimate_result_parameter
.service
.data 
= 0; 
3791         case NECP_POLICY_RESULT_USE_NETAGENT
: 
3792         case NECP_POLICY_RESULT_NETAGENT_SCOPED
: { 
3793                 uuid_t netagent_uuid
; 
3794                 if (necp_policy_get_result_parameter(policy
, (u_int8_t 
*)&netagent_uuid
, sizeof(netagent_uuid
))) { 
3795                         ultimate_result_parameter
.netagent_id 
= necp_create_uuid_service_id_mapping(netagent_uuid
); 
3796                         if (ultimate_result_parameter
.netagent_id 
!= 0) { 
3797                                 uuid_copy(policy
->applied_result_uuid
, netagent_uuid
); 
3798                                 socket_layer_non_id_conditions 
= TRUE
; 
3803         case NECP_POLICY_RESULT_SOCKET_SCOPED
: { 
3804                 u_int32_t interface_name_length 
= necp_policy_get_result_parameter_length(policy
); 
3805                 if (interface_name_length 
<= IFXNAMSIZ 
&& interface_name_length 
> 0) { 
3806                         char interface_name
[IFXNAMSIZ
]; 
3807                         ifnet_t scope_interface 
= NULL
; 
3808                         necp_policy_get_result_parameter(policy
, (u_int8_t 
*)interface_name
, interface_name_length
); 
3809                         interface_name
[interface_name_length 
- 1] = 0;         // Make sure the string is NULL terminated 
3810                         if (ifnet_find_by_name(interface_name
, &scope_interface
) == 0) { 
3811                                 ultimate_result_parameter
.scoped_interface_index 
= scope_interface
->if_index
; 
3812                                 socket_layer_non_id_conditions 
= TRUE
; 
3813                                 ifnet_release(scope_interface
); 
3818         case NECP_POLICY_RESULT_SCOPED_DIRECT
: { 
3819                 socket_layer_non_id_conditions 
= TRUE
; 
3822         case NECP_POLICY_RESULT_ALLOW_UNENTITLED
: { 
3823                 socket_layer_non_id_conditions 
= TRUE
; 
3826         case NECP_POLICY_RESULT_ROUTE_RULES
: { 
3827                 if (policy
->route_rules 
!= NULL 
&& policy
->route_rules_size 
> 0) { 
3828                         u_int32_t route_rule_id 
= necp_create_route_rule(&necp_route_rules
, policy
->route_rules
, policy
->route_rules_size
); 
3829                         if (route_rule_id 
> 0) { 
3830                                 policy
->applied_route_rules_id 
= route_rule_id
; 
3831                                 ultimate_result_parameter
.route_rule_id 
= route_rule_id
; 
3832                                 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE 
3833                                         socket_layer_non_id_conditions 
= TRUE
; 
3834                                 } else if (socket_ip_conditions
) { 
3835                                         socket_layer_non_id_conditions 
= TRUE
; 
3836                                         ip_output_layer_non_id_conditions 
= TRUE
; 
3837                                         ip_output_layer_non_id_only 
= TRUE
; // Only apply route rules to packets that didn't go through socket layer 
3848         if (socket_layer_non_id_conditions
) { 
3849                 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_pid_version
, 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
); 
3851                 if (policy_id 
== 0) { 
3852                         NECPLOG0(LOG_DEBUG
, "Error applying socket kernel policy"); 
3856                 cond_ip_output_layer_id 
= policy_id
; 
3857                 policy
->kernel_socket_policies
[0] = policy_id
; 
3860         if (ip_output_layer_non_id_conditions
) { 
3861                 u_int32_t condition_mask 
= master_condition_mask
; 
3862                 if (ip_output_layer_non_id_only
) { 
3863                         condition_mask 
|= NECP_KERNEL_CONDITION_POLICY_ID
; 
3866                 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
); 
3868                 if (policy_id 
== 0) { 
3869                         NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy"); 
3873                 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS
] = policy_id
; 
3876         if (ip_output_layer_id_condition
) { 
3877                 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
); 
3879                 if (policy_id 
== 0) { 
3880                         NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy"); 
3884                 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION
] = policy_id
; 
3887         // Extra policies for IP Output tunnels for when packets loop back 
3888         if (ip_output_layer_tunnel_condition_from_id
) { 
3889                 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
); 
3891                 if (policy_id 
== 0) { 
3892                         NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy"); 
3896                 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION
] = policy_id
; 
3899         if (ip_output_layer_tunnel_condition_from_id
) { 
3900                 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
); 
3902                 if (policy_id 
== 0) { 
3903                         NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy"); 
3907                 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION
] = policy_id
; 
3910         policy
->applied 
= TRUE
; 
3911         policy
->pending_update 
= FALSE
; 
3919 necp_policy_apply_all(struct necp_session 
*session
) 
3921         struct necp_session_policy 
*policy 
= NULL
; 
3922         struct necp_session_policy 
*temp_policy 
= NULL
; 
3923         struct kev_necp_policies_changed_data kev_data
; 
3924         kev_data
.changed_count 
= 0; 
3926         lck_rw_lock_exclusive(&necp_kernel_policy_lock
); 
3928         // Remove exisiting applied policies 
3929         if (session
->dirty
) { 
3930                 LIST_FOREACH_SAFE(policy
, &session
->policies
, chain
, temp_policy
) { 
3931                         if (policy
->pending_deletion
) { 
3932                                 if (policy
->applied
) { 
3933                                         necp_policy_unapply(policy
); 
3935                                 // Delete the policy 
3936                                 necp_policy_delete(session
, policy
); 
3937                         } else if (!policy
->applied
) { 
3938                                 necp_policy_apply(session
, policy
); 
3939                         } else if (policy
->pending_update
) { 
3940                                 // Must have been applied, but needs an update. Remove and re-add. 
3941                                 necp_policy_unapply(policy
); 
3942                                 necp_policy_apply(session
, policy
); 
3946                 necp_kernel_socket_policies_update_uuid_table(); 
3947                 necp_kernel_socket_policies_reprocess(); 
3948                 necp_kernel_ip_output_policies_reprocess(); 
3950                 // Clear dirty bit flags 
3951                 session
->dirty 
= FALSE
; 
3954         lck_rw_done(&necp_kernel_policy_lock
); 
3956         necp_update_all_clients(); 
3957         necp_post_change_event(&kev_data
); 
3960                 NECPLOG0(LOG_DEBUG
, "Applied NECP policies"); 
3964 // Kernel Policy Management 
3965 // --------------------- 
3966 // Kernel policies are derived from session policies 
3967 static necp_kernel_policy_id
 
3968 necp_kernel_policy_get_new_id(bool socket_level
) 
3970         static necp_kernel_policy_id necp_last_kernel_socket_policy_id 
= 0; 
3971         static necp_kernel_policy_id necp_last_kernel_ip_policy_id 
= 0; 
3973         necp_kernel_policy_id newid 
= NECP_KERNEL_POLICY_ID_NONE
; 
3975         LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
); 
3978                 bool wrapped 
= FALSE
; 
3980                         necp_last_kernel_socket_policy_id
++; 
3981                         if (necp_last_kernel_socket_policy_id 
< NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET 
|| 
3982                             necp_last_kernel_socket_policy_id 
>= NECP_KERNEL_POLICY_ID_FIRST_VALID_IP
) { 
3984                                         // Already wrapped, give up 
3985                                         NECPLOG0(LOG_ERR
, "Failed to find a free socket kernel policy ID.\n"); 
3986                                         return NECP_KERNEL_POLICY_ID_NONE
; 
3988                                 necp_last_kernel_socket_policy_id 
= NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET
; 
3991                         newid 
= necp_last_kernel_socket_policy_id
; 
3992                 } while (necp_kernel_socket_policy_find(newid
) != NULL
); // If already used, keep trying 
3994                 bool wrapped 
= FALSE
; 
3996                         necp_last_kernel_ip_policy_id
++; 
3997                         if (necp_last_kernel_ip_policy_id 
< NECP_KERNEL_POLICY_ID_FIRST_VALID_IP
) { 
3999                                         // Already wrapped, give up 
4000                                         NECPLOG0(LOG_ERR
, "Failed to find a free IP kernel policy ID.\n"); 
4001                                         return NECP_KERNEL_POLICY_ID_NONE
; 
4003                                 necp_last_kernel_ip_policy_id 
= NECP_KERNEL_POLICY_ID_FIRST_VALID_IP
; 
4006                         newid 
= necp_last_kernel_ip_policy_id
; 
4007                 } while (necp_kernel_ip_output_policy_find(newid
) != NULL
); // If already used, keep trying 
4010         if (newid 
== NECP_KERNEL_POLICY_ID_NONE
) { 
4011                 NECPLOG0(LOG_ERR
, "Allocate kernel policy id failed.\n"); 
4012                 return NECP_KERNEL_POLICY_ID_NONE
; 
4018 #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 | NECP_KERNEL_CONDITION_IS_LOOPBACK | NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) 
4020 static necp_kernel_policy_id
 
4021 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
, int32_t cond_pid_version
, 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
) 
4023         struct necp_kernel_socket_policy 
*new_kernel_policy 
= NULL
; 
4024         struct necp_kernel_socket_policy 
*tmp_kernel_policy 
= NULL
; 
4026         new_kernel_policy 
= zalloc_flags(necp_socket_policy_zone
, Z_WAITOK 
| Z_ZERO
); 
4028         new_kernel_policy
->id 
= necp_kernel_policy_get_new_id(true); 
4029         new_kernel_policy
->order 
= order
; 
4030         new_kernel_policy
->session_order 
= session_order
; 
4031         new_kernel_policy
->session_pid 
= session_pid
; 
4033         // Sanitize condition mask 
4034         new_kernel_policy
->condition_mask 
= (condition_mask 
& NECP_KERNEL_VALID_SOCKET_CONDITIONS
); 
4035         if ((new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
)) { 
4036                 new_kernel_policy
->condition_mask 
&= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE
; 
4038         if ((new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REAL_APP_ID
) && !(new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_APP_ID
)) { 
4039                 new_kernel_policy
->condition_mask 
&= ~NECP_KERNEL_CONDITION_REAL_APP_ID
; 
4041         if ((new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) && !(new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_APP_ID
)) { 
4042                 new_kernel_policy
->condition_mask 
&= ~NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
; 
4044         if ((new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_END
) && (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
)) { 
4045                 new_kernel_policy
->condition_mask 
&= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX
; 
4047         if ((new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_END
) && (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
)) { 
4048                 new_kernel_policy
->condition_mask 
&= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX
; 
4050         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_EMPTY
) { 
4051                 new_kernel_policy
->condition_mask 
&= ~(NECP_KERNEL_CONDITION_LOCAL_PREFIX 
| NECP_KERNEL_CONDITION_LOCAL_END
); 
4053         if ((new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_EMPTY
)) { 
4054                 new_kernel_policy
->condition_mask 
&= ~(NECP_KERNEL_CONDITION_REMOTE_PREFIX 
| NECP_KERNEL_CONDITION_REMOTE_END
); 
4056         new_kernel_policy
->condition_negated_mask 
= condition_negated_mask 
& new_kernel_policy
->condition_mask
; 
4058         // Set condition values 
4059         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_APP_ID
) { 
4060                 new_kernel_policy
->cond_app_id 
= cond_app_id
; 
4062         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REAL_APP_ID
) { 
4063                 new_kernel_policy
->cond_real_app_id 
= cond_real_app_id
; 
4065         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) { 
4066                 new_kernel_policy
->cond_custom_entitlement 
= cond_custom_entitlement
; 
4067                 new_kernel_policy
->cond_custom_entitlement_matched 
= necp_boolean_state_unknown
; 
4069         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) { 
4070                 new_kernel_policy
->cond_account_id 
= cond_account_id
; 
4072         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_DOMAIN
) { 
4073                 new_kernel_policy
->cond_domain 
= cond_domain
; 
4074                 new_kernel_policy
->cond_domain_dot_count 
= necp_count_dots(cond_domain
, strlen(cond_domain
)); 
4076         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_PID
) { 
4077                 new_kernel_policy
->cond_pid 
= cond_pid
; 
4078                 new_kernel_policy
->cond_pid_version 
= cond_pid_version
; 
4080         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_UID
) { 
4081                 new_kernel_policy
->cond_uid 
= cond_uid
; 
4083         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) { 
4084                 if (cond_bound_interface
) { 
4085                         ifnet_reference(cond_bound_interface
); 
4087                 new_kernel_policy
->cond_bound_interface 
= cond_bound_interface
; 
4089         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) { 
4090                 new_kernel_policy
->cond_traffic_class 
= cond_traffic_class
; 
4092         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_PROTOCOL
) { 
4093                 new_kernel_policy
->cond_protocol 
= cond_protocol
; 
4095         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_START
) { 
4096                 memcpy(&new_kernel_policy
->cond_local_start
, cond_local_start
, cond_local_start
->sa
.sa_len
); 
4098         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_END
) { 
4099                 memcpy(&new_kernel_policy
->cond_local_end
, cond_local_end
, cond_local_end
->sa
.sa_len
); 
4101         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) { 
4102                 new_kernel_policy
->cond_local_prefix 
= cond_local_prefix
; 
4104         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_START
) { 
4105                 memcpy(&new_kernel_policy
->cond_remote_start
, cond_remote_start
, cond_remote_start
->sa
.sa_len
); 
4107         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_END
) { 
4108                 memcpy(&new_kernel_policy
->cond_remote_end
, cond_remote_end
, cond_remote_end
->sa
.sa_len
); 
4110         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) { 
4111                 new_kernel_policy
->cond_remote_prefix 
= cond_remote_prefix
; 
4113         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_AGENT_TYPE
) { 
4114                 memcpy(&new_kernel_policy
->cond_agent_type
, cond_agent_type
, sizeof(*cond_agent_type
)); 
4116         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_SDK_VERSION
) { 
4117                 memcpy(&new_kernel_policy
->cond_sdk_version
, cond_sdk_version
, sizeof(*cond_sdk_version
)); 
4119         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_CLIENT_FLAGS
) { 
4120                 new_kernel_policy
->cond_client_flags 
= cond_client_flags
; 
4122         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
) { 
4123                 new_kernel_policy
->cond_signing_identifier 
= cond_signing_identifier
; 
4125         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) { 
4126                 new_kernel_policy
->cond_packet_filter_tags 
= cond_packet_filter_tags
; 
4129         new_kernel_policy
->result 
= result
; 
4130         memcpy(&new_kernel_policy
->result_parameter
, &result_parameter
, sizeof(result_parameter
)); 
4133                 NECPLOG(LOG_DEBUG
, "Added kernel policy: socket, id=%d, mask=%x\n", new_kernel_policy
->id
, new_kernel_policy
->condition_mask
); 
4135         LIST_INSERT_SORTED_TWICE_ASCENDING(&necp_kernel_socket_policies
, new_kernel_policy
, chain
, session_order
, order
, tmp_kernel_policy
); 
4137         return new_kernel_policy 
? new_kernel_policy
->id 
: 0; 
4140 static struct necp_kernel_socket_policy 
* 
4141 necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id
) 
4143         struct necp_kernel_socket_policy 
*kernel_policy 
= NULL
; 
4144         struct necp_kernel_socket_policy 
*tmp_kernel_policy 
= NULL
; 
4146         if (policy_id 
== 0) { 
4150         LIST_FOREACH_SAFE(kernel_policy
, &necp_kernel_socket_policies
, chain
, tmp_kernel_policy
) { 
4151                 if (kernel_policy
->id 
== policy_id
) { 
4152                         return kernel_policy
; 
4160 necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id
) 
4162         struct necp_kernel_socket_policy 
*policy 
= NULL
; 
4164         LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
); 
4166         policy 
= necp_kernel_socket_policy_find(policy_id
); 
4168                 LIST_REMOVE(policy
, chain
); 
4170                 if (policy
->cond_bound_interface
) { 
4171                         ifnet_release(policy
->cond_bound_interface
); 
4172                         policy
->cond_bound_interface 
= NULL
; 
4175                 if (policy
->cond_domain
) { 
4176                         FREE(policy
->cond_domain
, M_NECP
); 
4177                         policy
->cond_domain 
= NULL
; 
4180                 if (policy
->cond_custom_entitlement
) { 
4181                         FREE(policy
->cond_custom_entitlement
, M_NECP
); 
4182                         policy
->cond_custom_entitlement 
= NULL
; 
4185                 if (policy
->cond_signing_identifier
) { 
4186                         FREE(policy
->cond_signing_identifier
, M_NECP
); 
4187                         policy
->cond_signing_identifier 
= NULL
; 
4190                 zfree(necp_socket_policy_zone
, policy
); 
4197 static inline const char * 
4198 necp_get_result_description(char *result_string
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
) 
4200         uuid_string_t uuid_string
; 
4202         case NECP_KERNEL_POLICY_RESULT_NONE
: { 
4203                 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "None"); 
4206         case NECP_KERNEL_POLICY_RESULT_PASS
: { 
4207                 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Pass (%X)", result_parameter
.pass_flags
); 
4210         case NECP_KERNEL_POLICY_RESULT_SKIP
: { 
4211                 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Skip (%u)", result_parameter
.skip_policy_order
); 
4214         case NECP_KERNEL_POLICY_RESULT_DROP
: { 
4215                 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Drop (%X)", result_parameter
.drop_flags
); 
4218         case NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
: { 
4219                 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "SocketDivert (%d)", result_parameter
.flow_divert_control_unit
); 
4222         case NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER
: { 
4223                 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "SocketFilter (%d)", result_parameter
.filter_control_unit
); 
4226         case NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
: { 
4227                 ifnet_t interface 
= ifindex2ifnet
[result_parameter
.tunnel_interface_index
]; 
4228                 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "IPTunnel (%s%d)", ifnet_name(interface
), ifnet_unit(interface
)); 
4231         case NECP_KERNEL_POLICY_RESULT_IP_FILTER
: { 
4232                 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "IPFilter"); 
4235         case NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
: { 
4236                 ifnet_t interface 
= ifindex2ifnet
[result_parameter
.scoped_interface_index
]; 
4237                 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "SocketScoped (%s%d)", ifnet_name(interface
), ifnet_unit(interface
)); 
4240         case NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT
: { 
4241                 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "ScopedDirect"); 
4244         case NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED
: { 
4245                 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "AllowUnentitled"); 
4248         case NECP_KERNEL_POLICY_RESULT_ROUTE_RULES
: { 
4250                 char interface_names
[MAX_ROUTE_RULE_INTERFACES
][IFXNAMSIZ
]; 
4251                 struct necp_route_rule 
*route_rule 
= necp_lookup_route_rule_locked(&necp_route_rules
, result_parameter
.route_rule_id
); 
4252                 if (route_rule 
!= NULL
) { 
4253                         for (index 
= 0; index 
< MAX_ROUTE_RULE_INTERFACES
; index
++) { 
4254                                 if (route_rule
->exception_if_indices
[index
] != 0) { 
4255                                         ifnet_t interface 
= ifindex2ifnet
[route_rule
->exception_if_indices
[index
]]; 
4256                                         snprintf(interface_names
[index
], IFXNAMSIZ
, "%s%d", ifnet_name(interface
), ifnet_unit(interface
)); 
4258                                         memset(interface_names
[index
], 0, IFXNAMSIZ
); 
4261                         switch (route_rule
->default_action
) { 
4262                         case NECP_ROUTE_RULE_DENY_INTERFACE
: 
4263                                 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)", 
4264                                     (route_rule
->cellular_action 
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "Cell " : "", 
4265                                     (route_rule
->wifi_action 
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "WiFi " : "", 
4266                                     (route_rule
->wired_action 
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "Wired " : "", 
4267                                     (route_rule
->expensive_action 
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "Exp " : "", 
4268                                     (route_rule
->constrained_action 
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "Constrained " : "", 
4269                                     (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[0] : "", 
4270                                     (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "", 
4271                                     (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[1] : "", 
4272                                     (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "", 
4273                                     (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[2] : "", 
4274                                     (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "", 
4275                                     (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[3] : "", 
4276                                     (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "", 
4277                                     (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[4] : "", 
4278                                     (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "", 
4279                                     (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[5] : "", 
4280                                     (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "", 
4281                                     (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[6] : "", 
4282                                     (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "", 
4283                                     (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[7] : "", 
4284                                     (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "", 
4285                                     (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[8] : "", 
4286                                     (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "", 
4287                                     (route_rule
->exception_if_actions
[9] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[9] : ""); 
4289                         case NECP_ROUTE_RULE_ALLOW_INTERFACE
: 
4290                                 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)", 
4291                                     (route_rule
->cellular_action 
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!Cell " : "", 
4292                                     (route_rule
->wifi_action 
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!WiFi " : "", 
4293                                     (route_rule
->wired_action 
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!Wired " : "", 
4294                                     (route_rule
->expensive_action 
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!Exp " : "", 
4295                                     (route_rule
->constrained_action 
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!Constrained " : "", 
4296                                     (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "", 
4297                                     (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[0] : "", 
4298                                     (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "", 
4299                                     (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[1] : "", 
4300                                     (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "", 
4301                                     (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[2] : "", 
4302                                     (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "", 
4303                                     (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[3] : "", 
4304                                     (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "", 
4305                                     (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[4] : "", 
4306                                     (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "", 
4307                                     (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[5] : "", 
4308                                     (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "", 
4309                                     (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[6] : "", 
4310                                     (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "", 
4311                                     (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[7] : "", 
4312                                     (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "", 
4313                                     (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[8] : "", 
4314                                     (route_rule
->exception_if_actions
[9] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "", 
4315                                     (route_rule
->exception_if_actions
[9] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[9] : ""); 
4317                         case NECP_ROUTE_RULE_QOS_MARKING
: 
4318                                 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)", 
4319                                     (route_rule
->cellular_action 
== NECP_ROUTE_RULE_QOS_MARKING
) ? "Cell " : "", 
4320                                     (route_rule
->wifi_action 
== NECP_ROUTE_RULE_QOS_MARKING
) ? "WiFi " : "", 
4321                                     (route_rule
->wired_action 
== NECP_ROUTE_RULE_QOS_MARKING
) ? "Wired " : "", 
4322                                     (route_rule
->expensive_action 
== NECP_ROUTE_RULE_QOS_MARKING
) ? "Exp " : "", 
4323                                     (route_rule
->constrained_action 
== NECP_ROUTE_RULE_QOS_MARKING
) ? "Constrained " : "", 
4324                                     (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[0] : "", 
4325                                     (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "", 
4326                                     (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[1] : "", 
4327                                     (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "", 
4328                                     (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[2] : "", 
4329                                     (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "", 
4330                                     (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[3] : "", 
4331                                     (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "", 
4332                                     (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[4] : "", 
4333                                     (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "", 
4334                                     (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[5] : "", 
4335                                     (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "", 
4336                                     (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[6] : "", 
4337                                     (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "", 
4338                                     (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[7] : "", 
4339                                     (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "", 
4340                                     (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[8] : "", 
4341                                     (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "", 
4342                                     (route_rule
->exception_if_actions
[9] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[9] : ""); 
4345                                 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "RouteRules (Unknown)"); 
4351         case NECP_KERNEL_POLICY_RESULT_USE_NETAGENT
: { 
4352                 bool found_mapping 
= FALSE
; 
4353                 struct necp_uuid_id_mapping 
*mapping 
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.netagent_id
); 
4354                 if (mapping 
!= NULL
) { 
4355                         uuid_unparse(mapping
->uuid
, uuid_string
); 
4356                         found_mapping 
= TRUE
; 
4358                 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "UseNetAgent (%s)", found_mapping 
? uuid_string 
: "Unknown"); 
4361         case NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED
: { 
4362                 bool found_mapping 
= FALSE
; 
4363                 struct necp_uuid_id_mapping 
*mapping 
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.netagent_id
); 
4364                 if (mapping 
!= NULL
) { 
4365                         uuid_unparse(mapping
->uuid
, uuid_string
); 
4366                         found_mapping 
= TRUE
; 
4368                 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "NetAgentScoped (%s)", found_mapping 
? uuid_string 
: "Unknown"); 
4371         case NECP_POLICY_RESULT_TRIGGER
: { 
4372                 bool found_mapping 
= FALSE
; 
4373                 struct necp_uuid_id_mapping 
*mapping 
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.service
.identifier
); 
4374                 if (mapping 
!= NULL
) { 
4375                         uuid_unparse(mapping
->uuid
, uuid_string
); 
4376                         found_mapping 
= TRUE
; 
4378                 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Trigger (%s.%d)", found_mapping 
? uuid_string 
: "Unknown", result_parameter
.service
.data
); 
4381         case NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
: { 
4382                 bool found_mapping 
= FALSE
; 
4383                 struct necp_uuid_id_mapping 
*mapping 
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.service
.identifier
); 
4384                 if (mapping 
!= NULL
) { 
4385                         uuid_unparse(mapping
->uuid
, uuid_string
); 
4386                         found_mapping 
= TRUE
; 
4388                 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "TriggerIfNeeded (%s.%d)", found_mapping 
? uuid_string 
: "Unknown", result_parameter
.service
.data
); 
4391         case NECP_POLICY_RESULT_TRIGGER_SCOPED
: { 
4392                 bool found_mapping 
= FALSE
; 
4393                 struct necp_uuid_id_mapping 
*mapping 
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.service
.identifier
); 
4394                 if (mapping 
!= NULL
) { 
4395                         uuid_unparse(mapping
->uuid
, uuid_string
); 
4396                         found_mapping 
= TRUE
; 
4398                 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "TriggerScoped (%s.%d)", found_mapping 
? uuid_string 
: "Unknown", result_parameter
.service
.data
); 
4401         case NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
: { 
4402                 bool found_mapping 
= FALSE
; 
4403                 struct necp_uuid_id_mapping 
*mapping 
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.service
.identifier
); 
4404                 if (mapping 
!= NULL
) { 
4405                         uuid_unparse(mapping
->uuid
, uuid_string
); 
4406                         found_mapping 
= TRUE
; 
4408                 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "NoTriggerScoped (%s.%d)", found_mapping 
? uuid_string 
: "Unknown", result_parameter
.service
.data
); 
4412                 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Unknown %d (%d)", result
, result_parameter
.tunnel_interface_index
); 
4416         return result_string
; 
4420 necp_kernel_socket_policies_dump_all(void) 
4423                 struct necp_kernel_socket_policy 
*policy 
= NULL
; 
4426                 char result_string
[MAX_RESULT_STRING_LEN
]; 
4427                 char proc_name_string
[MAXCOMLEN 
+ 1]; 
4428                 memset(result_string
, 0, MAX_RESULT_STRING_LEN
); 
4429                 memset(proc_name_string
, 0, MAXCOMLEN 
+ 1); 
4431                 NECPLOG0(LOG_DEBUG
, "NECP Application Policies:\n"); 
4432                 NECPLOG0(LOG_DEBUG
, "-----------\n"); 
4433                 for (policy_i 
= 0; necp_kernel_socket_policies_app_layer_map 
!= NULL 
&& necp_kernel_socket_policies_app_layer_map
[policy_i
] != NULL
; policy_i
++) { 
4434                         policy 
= necp_kernel_socket_policies_app_layer_map
[policy_i
]; 
4435                         proc_name(policy
->session_pid
, proc_name_string
, MAXCOMLEN
); 
4436                         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
)); 
4438                 if (necp_kernel_socket_policies_app_layer_map
[0] != NULL
) { 
4439                         NECPLOG0(LOG_DEBUG
, "-----------\n"); 
4442                 NECPLOG0(LOG_DEBUG
, "NECP Socket Policies:\n"); 
4443                 NECPLOG0(LOG_DEBUG
, "-----------\n"); 
4444                 for (app_i 
= 0; app_i 
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) { 
4445                         NECPLOG(LOG_DEBUG
, "\tApp Bucket: %d\n", app_i
); 
4446                         for (policy_i 
= 0; necp_kernel_socket_policies_map
[app_i
] != NULL 
&& (necp_kernel_socket_policies_map
[app_i
])[policy_i
] != NULL
; policy_i
++) { 
4447                                 policy 
= (necp_kernel_socket_policies_map
[app_i
])[policy_i
]; 
4448                                 proc_name(policy
->session_pid
, proc_name_string
, MAXCOMLEN
); 
4449                                 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
)); 
4451                         NECPLOG0(LOG_DEBUG
, "-----------\n"); 
4457 necp_kernel_socket_result_is_trigger_service_type(struct necp_kernel_socket_policy 
*kernel_policy
) 
4459         return kernel_policy
->result 
>= NECP_KERNEL_POLICY_RESULT_TRIGGER 
&& kernel_policy
->result 
<= NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED
; 
4463 necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy 
*upper_policy
, struct necp_kernel_socket_policy 
*lower_policy
) 
4465         if (upper_policy
->result 
== NECP_KERNEL_POLICY_RESULT_DROP
) { 
4466                 // Drop always cancels out lower policies 
4468         } else if (upper_policy
->result 
== NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER 
|| 
4469             upper_policy
->result 
== NECP_KERNEL_POLICY_RESULT_ROUTE_RULES 
|| 
4470             upper_policy
->result 
== NECP_KERNEL_POLICY_RESULT_USE_NETAGENT 
|| 
4471             upper_policy
->result 
== NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED 
|| 
4472             upper_policy
->result 
== NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED
) { 
4473                 // Filters and route rules never cancel out lower policies 
4475         } else if (necp_kernel_socket_result_is_trigger_service_type(upper_policy
)) { 
4476                 // Trigger/Scoping policies can overlap one another, but not other results 
4477                 return necp_kernel_socket_result_is_trigger_service_type(lower_policy
); 
4478         } else if (upper_policy
->result 
== NECP_KERNEL_POLICY_RESULT_SKIP
) { 
4479                 if (upper_policy
->session_order 
!= lower_policy
->session_order
) { 
4480                         // A skip cannot override a policy of a different session 
4483                         if (upper_policy
->result_parameter
.skip_policy_order 
== 0 || 
4484                             lower_policy
->order 
>= upper_policy
->result_parameter
.skip_policy_order
) { 
4485                                 // This policy is beyond the skip 
4488                                 // This policy is inside the skip 
4494         // A hard pass, flow divert, tunnel, or scope will currently block out lower policies 
4499 necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy 
*policy
, struct necp_kernel_socket_policy 
**policy_array
, int valid_indices
) 
4501         bool can_skip 
= FALSE
; 
4502         u_int32_t highest_skip_session_order 
= 0; 
4503         u_int32_t highest_skip_order 
= 0; 
4505         for (i 
= 0; i 
< valid_indices
; i
++) { 
4506                 struct necp_kernel_socket_policy 
*compared_policy 
= policy_array
[i
]; 
4508                 // For policies in a skip window, we can't mark conflicting policies as unnecessary 
4510                         if (highest_skip_session_order 
!= compared_policy
->session_order 
|| 
4511                             (highest_skip_order 
!= 0 && compared_policy
->order 
>= highest_skip_order
)) { 
4512                                 // If we've moved on to the next session, or passed the skip window 
4513                                 highest_skip_session_order 
= 0; 
4514                                 highest_skip_order 
= 0; 
4517                                 // If this policy is also a skip, in can increase the skip window 
4518                                 if (compared_policy
->result 
== NECP_KERNEL_POLICY_RESULT_SKIP
) { 
4519                                         if (compared_policy
->result_parameter
.skip_policy_order 
> highest_skip_order
) { 
4520                                                 highest_skip_order 
= compared_policy
->result_parameter
.skip_policy_order
; 
4527                 if (compared_policy
->result 
== NECP_KERNEL_POLICY_RESULT_SKIP
) { 
4528                         // This policy is a skip. Set the skip window accordingly 
4530                         highest_skip_session_order 
= compared_policy
->session_order
; 
4531                         highest_skip_order 
= compared_policy
->result_parameter
.skip_policy_order
; 
4534                 // The result of the compared policy must be able to block out this policy result 
4535                 if (!necp_kernel_socket_policy_results_overlap(compared_policy
, policy
)) { 
4539                 // If new policy matches All Interfaces, compared policy must also 
4540                 if ((policy
->condition_mask 
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && !(compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) { 
4544                 // If new policy matches Local Networks, compared policy must also 
4545                 if ((policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) && !(compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
)) { 
4549                 // Default makes lower policies unecessary always 
4550                 if (compared_policy
->condition_mask 
== 0) { 
4554                 // Compared must be more general than policy, and include only conditions within policy 
4555                 if ((policy
->condition_mask 
& compared_policy
->condition_mask
) != compared_policy
->condition_mask
) { 
4559                 // Negative conditions must match for the overlapping conditions 
4560                 if ((policy
->condition_negated_mask 
& compared_policy
->condition_mask
) != (compared_policy
->condition_negated_mask 
& compared_policy
->condition_mask
)) { 
4564                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_DOMAIN 
&& 
4565                     strcmp(compared_policy
->cond_domain
, policy
->cond_domain
) != 0) { 
4569                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT 
&& 
4570                     strcmp(compared_policy
->cond_custom_entitlement
, policy
->cond_custom_entitlement
) != 0) { 
4574                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_ACCOUNT_ID 
&& 
4575                     compared_policy
->cond_account_id 
!= policy
->cond_account_id
) { 
4579                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_POLICY_ID 
&& 
4580                     compared_policy
->cond_policy_id 
!= policy
->cond_policy_id
) { 
4584                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_APP_ID 
&& 
4585                     compared_policy
->cond_app_id 
!= policy
->cond_app_id
) { 
4589                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REAL_APP_ID 
&& 
4590                     compared_policy
->cond_real_app_id 
!= policy
->cond_real_app_id
) { 
4594                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_PID 
&& 
4595                     (compared_policy
->cond_pid 
!= policy
->cond_pid 
|| compared_policy
->cond_pid_version 
!= policy
->cond_pid_version
)) { 
4599                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_UID 
&& 
4600                     compared_policy
->cond_uid 
!= policy
->cond_uid
) { 
4604                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_BOUND_INTERFACE 
&& 
4605                     compared_policy
->cond_bound_interface 
!= policy
->cond_bound_interface
) { 
4609                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_PROTOCOL 
&& 
4610                     compared_policy
->cond_protocol 
!= policy
->cond_protocol
) { 
4614                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_CLIENT_FLAGS 
&& 
4615                     compared_policy
->cond_client_flags 
!= policy
->cond_client_flags
) { 
4619                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS 
&& 
4620                     !(compared_policy
->cond_traffic_class
.start_tc 
<= policy
->cond_traffic_class
.start_tc 
&& 
4621                     compared_policy
->cond_traffic_class
.end_tc 
>= policy
->cond_traffic_class
.end_tc
)) { 
4625                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_START
) { 
4626                         if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_END
) { 
4627                                 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
)) { 
4630                         } else if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) { 
4631                                 if (compared_policy
->cond_local_prefix 
> policy
->cond_local_prefix 
|| 
4632                                     !necp_is_addr_in_subnet((struct sockaddr 
*)&policy
->cond_local_start
, (struct sockaddr 
*)&compared_policy
->cond_local_start
, compared_policy
->cond_local_prefix
)) { 
4638                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_START
) { 
4639                         if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_END
) { 
4640                                 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
)) { 
4643                         } else if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) { 
4644                                 if (compared_policy
->cond_remote_prefix 
> policy
->cond_remote_prefix 
|| 
4645                                     !necp_is_addr_in_subnet((struct sockaddr 
*)&policy
->cond_remote_start
, (struct sockaddr 
*)&compared_policy
->cond_remote_start
, compared_policy
->cond_remote_prefix
)) { 
4651                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_AGENT_TYPE 
&& 
4652                     memcmp(&compared_policy
->cond_agent_type
, &policy
->cond_agent_type
, sizeof(policy
->cond_agent_type
)) == 0) { 
4656                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_SDK_VERSION 
&& 
4657                     memcmp(&compared_policy
->cond_sdk_version
, &policy
->cond_sdk_version
, sizeof(policy
->cond_sdk_version
)) == 0) { 
4661                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS 
&& 
4662                     memcmp(&compared_policy
->cond_packet_filter_tags
, &policy
->cond_packet_filter_tags
, sizeof(policy
->cond_packet_filter_tags
)) == 0) { 
4673 necp_kernel_socket_policies_reprocess(void) 
4676         int bucket_allocation_counts
[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
]; 
4677         int bucket_current_free_index
[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
]; 
4678         int app_layer_allocation_count 
= 0; 
4679         int app_layer_current_free_index 
= 0; 
4680         struct necp_kernel_socket_policy 
*kernel_policy 
= NULL
; 
4682         LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
); 
4685         necp_kernel_application_policies_condition_mask 
= 0; 
4686         necp_kernel_socket_policies_condition_mask 
= 0; 
4687         necp_kernel_application_policies_count 
= 0; 
4688         necp_kernel_socket_policies_count 
= 0; 
4689         necp_kernel_socket_policies_non_app_count 
= 0; 
4691         // Reset all maps to NULL 
4692         for (app_i 
= 0; app_i 
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) { 
4693                 if (necp_kernel_socket_policies_map
[app_i
] != NULL
) { 
4694                         FREE(necp_kernel_socket_policies_map
[app_i
], M_NECP
); 
4695                         necp_kernel_socket_policies_map
[app_i
] = NULL
; 
4699                 bucket_allocation_counts
[app_i
] = 0; 
4701         if (necp_kernel_socket_policies_app_layer_map 
!= NULL
) { 
4702                 FREE(necp_kernel_socket_policies_app_layer_map
, M_NECP
); 
4703                 necp_kernel_socket_policies_app_layer_map 
= NULL
; 
4706         // Create masks and counts 
4707         LIST_FOREACH(kernel_policy
, &necp_kernel_socket_policies
, chain
) { 
4708                 // App layer mask/count 
4709                 necp_kernel_application_policies_condition_mask 
|= kernel_policy
->condition_mask
; 
4710                 necp_kernel_application_policies_count
++; 
4711                 app_layer_allocation_count
++; 
4713                 if ((kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_AGENT_TYPE
)) { 
4714                         // Agent type conditions only apply to app layer 
4718                 // Update socket layer bucket mask/counts 
4719                 necp_kernel_socket_policies_condition_mask 
|= kernel_policy
->condition_mask
; 
4720                 necp_kernel_socket_policies_count
++; 
4722                 if (!(kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_APP_ID
) || 
4723                     kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_APP_ID
) { 
4724                         necp_kernel_socket_policies_non_app_count
++; 
4725                         for (app_i 
= 0; app_i 
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) { 
4726                                 bucket_allocation_counts
[app_i
]++; 
4729                         bucket_allocation_counts
[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy
->cond_app_id
)]++; 
4734         for (app_i 
= 0; app_i 
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) { 
4735                 if (bucket_allocation_counts
[app_i
] > 0) { 
4736                         // Allocate a NULL-terminated array of policy pointers for each bucket 
4737                         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
); 
4738                         if (necp_kernel_socket_policies_map
[app_i
] == NULL
) { 
4742                         // Initialize the first entry to NULL 
4743                         (necp_kernel_socket_policies_map
[app_i
])[0] = NULL
; 
4745                 bucket_current_free_index
[app_i
] = 0; 
4747         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
); 
4748         if (necp_kernel_socket_policies_app_layer_map 
== NULL
) { 
4751         necp_kernel_socket_policies_app_layer_map
[0] = NULL
; 
4754         LIST_FOREACH(kernel_policy
, &necp_kernel_socket_policies
, chain
) { 
4755                 // Add app layer policies 
4756                 if (!necp_dedup_policies 
|| !necp_kernel_socket_policy_is_unnecessary(kernel_policy
, necp_kernel_socket_policies_app_layer_map
, app_layer_current_free_index
)) { 
4757                         necp_kernel_socket_policies_app_layer_map
[app_layer_current_free_index
] = kernel_policy
; 
4758                         app_layer_current_free_index
++; 
4759                         necp_kernel_socket_policies_app_layer_map
[app_layer_current_free_index
] = NULL
; 
4762                 if ((kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_AGENT_TYPE
)) { 
4763                         // Agent type conditions only apply to app layer 
4767                 // Add socket policies 
4768                 if (!(kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_APP_ID
) || 
4769                     kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_APP_ID
) { 
4770                         for (app_i 
= 0; app_i 
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) { 
4771                                 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
])) { 
4772                                         (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = kernel_policy
; 
4773                                         bucket_current_free_index
[app_i
]++; 
4774                                         (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = NULL
; 
4778                         app_i 
= NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy
->cond_app_id
); 
4779                         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
])) { 
4780                                 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = kernel_policy
; 
4781                                 bucket_current_free_index
[app_i
]++; 
4782                                 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = NULL
; 
4786         necp_kernel_socket_policies_dump_all(); 
4787         BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT(); 
4791         // Free memory, reset masks to 0 
4792         necp_kernel_application_policies_condition_mask 
= 0; 
4793         necp_kernel_socket_policies_condition_mask 
= 0; 
4794         necp_kernel_application_policies_count 
= 0; 
4795         necp_kernel_socket_policies_count 
= 0; 
4796         necp_kernel_socket_policies_non_app_count 
= 0; 
4797         for (app_i 
= 0; app_i 
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) { 
4798                 if (necp_kernel_socket_policies_map
[app_i
] != NULL
) { 
4799                         FREE(necp_kernel_socket_policies_map
[app_i
], M_NECP
); 
4800                         necp_kernel_socket_policies_map
[app_i
] = NULL
; 
4803         if (necp_kernel_socket_policies_app_layer_map 
!= NULL
) { 
4804                 FREE(necp_kernel_socket_policies_app_layer_map
, M_NECP
); 
4805                 necp_kernel_socket_policies_app_layer_map 
= NULL
; 
4811 necp_get_new_string_id(void) 
4813         static u_int32_t necp_last_string_id 
= 0; 
4815         u_int32_t newid 
= 0; 
4817         LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
); 
4819         bool wrapped 
= FALSE
; 
4821                 necp_last_string_id
++; 
4822                 if (necp_last_string_id 
< 1) { 
4824                                 // Already wrapped, give up 
4825                                 NECPLOG0(LOG_ERR
, "Failed to find a free app UUID.\n"); 
4828                         necp_last_string_id 
= 1; 
4831                 newid 
= necp_last_string_id
; 
4832         } while (necp_lookup_string_with_id_locked(&necp_account_id_list
, newid
) != NULL
); // If already used, keep trying 
4835                 NECPLOG0(LOG_ERR
, "Allocate string id failed.\n"); 
4842 static struct necp_string_id_mapping 
* 
4843 necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list 
*list
, char *string
) 
4845         struct necp_string_id_mapping 
*searchentry 
= NULL
; 
4846         struct necp_string_id_mapping 
*foundentry 
= NULL
; 
4848         LIST_FOREACH(searchentry
, list
, chain
) { 
4849                 if (strcmp(searchentry
->string
, string
) == 0) { 
4850                         foundentry 
= searchentry
; 
4858 static struct necp_string_id_mapping 
* 
4859 necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list 
*list
, u_int32_t local_id
) 
4861         struct necp_string_id_mapping 
*searchentry 
= NULL
; 
4862         struct necp_string_id_mapping 
*foundentry 
= NULL
; 
4864         LIST_FOREACH(searchentry
, list
, chain
) { 
4865                 if (searchentry
->id 
== local_id
) { 
4866                         foundentry 
= searchentry
; 
4875 necp_create_string_to_id_mapping(struct necp_string_id_mapping_list 
*list
, char *string
) 
4877         u_int32_t string_id 
= 0; 
4878         struct necp_string_id_mapping 
*existing_mapping 
= NULL
; 
4880         LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
); 
4882         existing_mapping 
= necp_lookup_string_to_id_locked(list
, string
); 
4883         if (existing_mapping 
!= NULL
) { 
4884                 string_id 
= existing_mapping
->id
; 
4885                 os_ref_retain_locked(&existing_mapping
->refcount
); 
4887                 struct necp_string_id_mapping 
*new_mapping 
= NULL
; 
4888                 MALLOC(new_mapping
, struct necp_string_id_mapping 
*, sizeof(struct necp_string_id_mapping
), M_NECP
, M_WAITOK
); 
4889                 if (new_mapping 
!= NULL
) { 
4890                         memset(new_mapping
, 0, sizeof(struct necp_string_id_mapping
)); 
4892                         size_t length 
= strlen(string
) + 1; 
4893                         MALLOC(new_mapping
->string
, char *, length
, M_NECP
, M_WAITOK
); 
4894                         if (new_mapping
->string 
!= NULL
) { 
4895                                 memcpy(new_mapping
->string
, string
, length
); 
4896                                 new_mapping
->id 
= necp_get_new_string_id(); 
4897                                 os_ref_init(&new_mapping
->refcount
, &necp_refgrp
); 
4898                                 LIST_INSERT_HEAD(list
, new_mapping
, chain
); 
4899                                 string_id 
= new_mapping
->id
; 
4901                                 FREE(new_mapping
, M_NECP
); 
4910 necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list 
*list
, char *string
) 
4912         struct necp_string_id_mapping 
*existing_mapping 
= NULL
; 
4914         LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
); 
4916         existing_mapping 
= necp_lookup_string_to_id_locked(list
, string
); 
4917         if (existing_mapping 
!= NULL
) { 
4918                 if (os_ref_release_locked(&existing_mapping
->refcount
) == 0) { 
4919                         LIST_REMOVE(existing_mapping
, chain
); 
4920                         FREE(existing_mapping
->string
, M_NECP
); 
4921                         FREE(existing_mapping
, M_NECP
); 
4929 #define NECP_FIRST_VALID_ROUTE_RULE_ID 1 
4930 #define NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID UINT16_MAX 
4932 necp_get_new_route_rule_id(bool aggregate
) 
4934         static u_int32_t necp_last_route_rule_id 
= 0; 
4935         static u_int32_t necp_last_aggregate_route_rule_id 
= 0; 
4937         u_int32_t newid 
= 0; 
4940                 // Main necp_kernel_policy_lock protects non-aggregate rule IDs 
4941                 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
); 
4943                 bool wrapped 
= FALSE
; 
4945                         necp_last_route_rule_id
++; 
4946                         if (necp_last_route_rule_id 
< NECP_FIRST_VALID_ROUTE_RULE_ID 
|| 
4947                             necp_last_route_rule_id 
>= NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID
) { 
4949                                         // Already wrapped, give up 
4950                                         NECPLOG0(LOG_ERR
, "Failed to find a free route rule id.\n"); 
4953                                 necp_last_route_rule_id 
= NECP_FIRST_VALID_ROUTE_RULE_ID
; 
4956                         newid 
= necp_last_route_rule_id
; 
4957                 } while (necp_lookup_route_rule_locked(&necp_route_rules
, newid
) != NULL
); // If already used, keep trying 
4959                 // necp_route_rule_lock protects aggregate rule IDs 
4960                 LCK_RW_ASSERT(&necp_route_rule_lock
, LCK_RW_ASSERT_EXCLUSIVE
); 
4962                 bool wrapped 
= FALSE
; 
4964                         necp_last_aggregate_route_rule_id
++; 
4965                         if (necp_last_aggregate_route_rule_id 
< NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID
) { 
4967                                         // Already wrapped, give up 
4968                                         NECPLOG0(LOG_ERR
, "Failed to find a free aggregate route rule id.\n"); 
4971                                 necp_last_aggregate_route_rule_id 
= NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID
; 
4974                         newid 
= necp_last_aggregate_route_rule_id
; 
4975                 } while (necp_lookup_route_rule_locked(&necp_route_rules
, newid
) != NULL
); // If already used, keep trying 
4979                 NECPLOG0(LOG_ERR
, "Allocate route rule ID failed.\n"); 
4986 static struct necp_route_rule 
* 
4987 necp_lookup_route_rule_locked(struct necp_route_rule_list 
*list
, u_int32_t route_rule_id
) 
4989         struct necp_route_rule 
*searchentry 
= NULL
; 
4990         struct necp_route_rule 
*foundentry 
= NULL
; 
4992         LIST_FOREACH(searchentry
, list
, chain
) { 
4993                 if (searchentry
->id 
== route_rule_id
) { 
4994                         foundentry 
= searchentry
; 
5002 static struct necp_route_rule 
* 
5003 necp_lookup_route_rule_by_contents_locked(struct necp_route_rule_list 
*list
, u_int8_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
, uuid_t netagent_uuid
) 
5005         struct necp_route_rule 
*searchentry 
= NULL
; 
5006         struct necp_route_rule 
*foundentry 
= NULL
; 
5008         LIST_FOREACH(searchentry
, list
, chain
) { 
5009                 if (searchentry
->default_action 
== default_action 
&& 
5010                     searchentry
->cellular_action 
== cellular_action 
&& 
5011                     searchentry
->wifi_action 
== wifi_action 
&& 
5012                     searchentry
->wired_action 
== wired_action 
&& 
5013                     searchentry
->expensive_action 
== expensive_action 
&& 
5014                     searchentry
->constrained_action 
== constrained_action
) { 
5015                         bool match_failed 
= FALSE
; 
5020                         for (index_a 
= 0; index_a 
< MAX_ROUTE_RULE_INTERFACES
; index_a
++) { 
5021                                 bool found_index 
= FALSE
; 
5022                                 if (searchentry
->exception_if_indices
[index_a
] == 0) { 
5026                                 for (index_b 
= 0; index_b 
< MAX_ROUTE_RULE_INTERFACES
; index_b
++) { 
5027                                         if (if_indices
[index_b
] == 0) { 
5030                                         if (index_b 
>= count_b
) { 
5031                                                 count_b 
= index_b 
+ 1; 
5033                                         if (searchentry
->exception_if_indices
[index_a
] == if_indices
[index_b
] && 
5034                                             searchentry
->exception_if_actions
[index_a
] == if_actions
[index_b
]) { 
5040                                         match_failed 
= TRUE
; 
5045                         if (match_failed 
|| count_a 
!= count_b
) { 
5049                         bool has_agent_a 
= uuid_is_null(netagent_uuid
); 
5050                         bool has_agent_b 
= (searchentry
->netagent_id 
!= 0); 
5051                         if (has_agent_a 
!= has_agent_b
) { 
5056                                 struct necp_uuid_id_mapping 
*mapping 
= necp_uuid_lookup_uuid_with_service_id_locked(searchentry
->netagent_id
); 
5057                                 if (mapping 
== NULL
) { 
5058                                         // Bad mapping, doesn't match 
5061                                 if (uuid_compare(mapping
->uuid
, netagent_uuid
) != 0) { 
5062                                         // UUIDs don't match 
5068                         foundentry 
= searchentry
; 
5077 necp_create_route_rule(struct necp_route_rule_list 
*list
, u_int8_t 
*route_rules_array
, u_int32_t route_rules_array_size
) 
5080         u_int32_t route_rule_id 
= 0; 
5081         struct necp_route_rule 
*existing_rule 
= NULL
; 
5082         u_int8_t default_action 
= NECP_ROUTE_RULE_ALLOW_INTERFACE
; 
5083         u_int8_t cellular_action 
= NECP_ROUTE_RULE_NONE
; 
5084         u_int8_t wifi_action 
= NECP_ROUTE_RULE_NONE
; 
5085         u_int8_t wired_action 
= NECP_ROUTE_RULE_NONE
; 
5086         u_int8_t expensive_action 
= NECP_ROUTE_RULE_NONE
; 
5087         u_int8_t constrained_action 
= NECP_ROUTE_RULE_NONE
; 
5088         u_int32_t if_indices
[MAX_ROUTE_RULE_INTERFACES
]; 
5089         size_t num_valid_indices 
= 0; 
5090         memset(&if_indices
, 0, sizeof(if_indices
)); 
5091         u_int8_t if_actions
[MAX_ROUTE_RULE_INTERFACES
]; 
5092         memset(&if_actions
, 0, sizeof(if_actions
)); 
5094         uuid_t netagent_uuid 
= {}; 
5096         LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
); 
5098         if (route_rules_array 
== NULL 
|| route_rules_array_size 
== 0) { 
5103         while ((offset 
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)) < route_rules_array_size
) { 
5104                 ifnet_t rule_interface 
= NULL
; 
5105                 char interface_name
[IFXNAMSIZ
]; 
5106                 u_int32_t length 
= 0; 
5107                 u_int8_t 
*value 
= necp_buffer_get_tlv_value(route_rules_array
, offset
, &length
); 
5109                 if (offset 
+ sizeof(u_int8_t
) + sizeof(u_int32_t
) + length 
> route_rules_array_size
) { 
5110                         // Invalid TLV goes beyond end of the rules array 
5114                 // Increment offset for the next time through the loop 
5115                 offset 
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
; 
5117                 u_int8_t rule_type 
= necp_policy_condition_get_type_from_buffer(value
, length
); 
5118                 u_int8_t rule_flags 
= necp_policy_condition_get_flags_from_buffer(value
, length
); 
5119                 u_int32_t rule_length 
= necp_policy_condition_get_value_length_from_buffer(value
, length
); 
5120                 u_int8_t 
*rule_value 
= necp_policy_condition_get_value_pointer_from_buffer(value
, length
); 
5122                 if (rule_type 
== NECP_ROUTE_RULE_NONE
) { 
5123                         // Don't allow an explicit rule to be None action 
5127                 if (rule_type 
== NECP_ROUTE_RULE_USE_NETAGENT
) { 
5128                         if (rule_length 
< sizeof(uuid_t
)) { 
5133                         if (!uuid_is_null(netagent_uuid
)) { 
5134                                 if (uuid_compare(netagent_uuid
, rule_value
) != 0) { 
5135                                         // UUIDs don't match, skip 
5139                                 // Copy out agent UUID 
5140                                 memcpy(netagent_uuid
, rule_value
, sizeof(netagent_uuid
)); 
5143                         // Adjust remaining length 
5144                         rule_value 
+= sizeof(netagent_uuid
); 
5145                         rule_length 
-= sizeof(netagent_uuid
); 
5148                 if (rule_length 
== 0) { 
5149                         if (rule_flags 
& NECP_ROUTE_RULE_FLAG_CELLULAR
) { 
5150                                 cellular_action 
= rule_type
; 
5152                         if (rule_flags 
& NECP_ROUTE_RULE_FLAG_WIFI
) { 
5153                                 wifi_action 
= rule_type
; 
5155                         if (rule_flags 
& NECP_ROUTE_RULE_FLAG_WIRED
) { 
5156                                 wired_action 
= rule_type
; 
5158                         if (rule_flags 
& NECP_ROUTE_RULE_FLAG_EXPENSIVE
) { 
5159                                 expensive_action 
= rule_type
; 
5161                         if (rule_flags 
& NECP_ROUTE_RULE_FLAG_CONSTRAINED
) { 
5162                                 constrained_action 
= rule_type
; 
5164                         if (rule_flags 
== 0) { 
5165                                 default_action 
= rule_type
; 
5170                 if (num_valid_indices 
>= MAX_ROUTE_RULE_INTERFACES
) { 
5174                 if (rule_length 
<= IFXNAMSIZ
) { 
5175                         memcpy(interface_name
, rule_value
, rule_length
); 
5176                         interface_name
[rule_length 
- 1] = 0; // Make sure the string is NULL terminated 
5177                         if (ifnet_find_by_name(interface_name
, &rule_interface
) == 0) { 
5178                                 if_actions
[num_valid_indices
] = rule_type
; 
5179                                 if_indices
[num_valid_indices
++] = rule_interface
->if_index
; 
5180                                 ifnet_release(rule_interface
); 
5185         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
, netagent_uuid
); 
5186         if (existing_rule 
!= NULL
) { 
5187                 route_rule_id 
= existing_rule
->id
; 
5188                 os_ref_retain_locked(&existing_rule
->refcount
); 
5190                 struct necp_route_rule 
*new_rule 
= NULL
; 
5191                 MALLOC(new_rule
, struct necp_route_rule 
*, sizeof(struct necp_route_rule
), M_NECP
, M_WAITOK
); 
5192                 if (new_rule 
!= NULL
) { 
5193                         memset(new_rule
, 0, sizeof(struct necp_route_rule
)); 
5194                         route_rule_id 
= new_rule
->id 
= necp_get_new_route_rule_id(false); 
5195                         if (!uuid_is_null(netagent_uuid
)) { 
5196                                 new_rule
->netagent_id 
= necp_create_uuid_service_id_mapping(netagent_uuid
); 
5198                         new_rule
->default_action 
= default_action
; 
5199                         new_rule
->cellular_action 
= cellular_action
; 
5200                         new_rule
->wifi_action 
= wifi_action
; 
5201                         new_rule
->wired_action 
= wired_action
; 
5202                         new_rule
->expensive_action 
= expensive_action
; 
5203                         new_rule
->constrained_action 
=  constrained_action
; 
5204                         memcpy(&new_rule
->exception_if_indices
, &if_indices
, sizeof(if_indices
)); 
5205                         memcpy(&new_rule
->exception_if_actions
, &if_actions
, sizeof(if_actions
)); 
5206                         os_ref_init(&new_rule
->refcount
, &necp_refgrp
); 
5207                         LIST_INSERT_HEAD(list
, new_rule
, chain
); 
5210         return route_rule_id
; 
5214 necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id
) 
5217                 lck_rw_lock_exclusive(&necp_route_rule_lock
); 
5219                 struct necp_aggregate_route_rule 
*existing_rule 
= NULL
; 
5220                 struct necp_aggregate_route_rule 
*tmp_rule 
= NULL
; 
5222                 LIST_FOREACH_SAFE(existing_rule
, &necp_aggregate_route_rules
, chain
, tmp_rule
) { 
5224                         for (index 
= 0; index 
< MAX_AGGREGATE_ROUTE_RULES
; index
++) { 
5225                                 u_int32_t route_rule_id 
= existing_rule
->rule_ids
[index
]; 
5226                                 if (route_rule_id 
== rule_id
) { 
5227                                         LIST_REMOVE(existing_rule
, chain
); 
5228                                         FREE(existing_rule
, M_NECP
); 
5234                 lck_rw_done(&necp_route_rule_lock
); 
5239 necp_remove_route_rule(struct necp_route_rule_list 
*list
, u_int32_t route_rule_id
) 
5241         struct necp_route_rule 
*existing_rule 
= NULL
; 
5243         LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
); 
5245         existing_rule 
= necp_lookup_route_rule_locked(list
, route_rule_id
); 
5246         if (existing_rule 
!= NULL
) { 
5247                 if (os_ref_release_locked(&existing_rule
->refcount
) == 0) { 
5248                         necp_remove_aggregate_route_rule_for_id(existing_rule
->id
); 
5249                         necp_remove_uuid_service_id_mapping_with_service_id(existing_rule
->netagent_id
); 
5250                         LIST_REMOVE(existing_rule
, chain
); 
5251                         FREE(existing_rule
, M_NECP
); 
5259 static struct necp_aggregate_route_rule 
* 
5260 necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id
) 
5262         struct necp_aggregate_route_rule 
*searchentry 
= NULL
; 
5263         struct necp_aggregate_route_rule 
*foundentry 
= NULL
; 
5265         lck_rw_lock_shared(&necp_route_rule_lock
); 
5267         LIST_FOREACH(searchentry
, &necp_aggregate_route_rules
, chain
) { 
5268                 if (searchentry
->id 
== route_rule_id
) { 
5269                         foundentry 
= searchentry
; 
5274         lck_rw_done(&necp_route_rule_lock
); 
5280 necp_create_aggregate_route_rule(u_int32_t 
*rule_ids
) 
5282         u_int32_t aggregate_route_rule_id 
= 0; 
5283         struct necp_aggregate_route_rule 
*new_rule 
= NULL
; 
5284         struct necp_aggregate_route_rule 
*existing_rule 
= NULL
; 
5286         lck_rw_lock_exclusive(&necp_route_rule_lock
); 
5288         // Check if the rule already exists 
5289         LIST_FOREACH(existing_rule
, &necp_aggregate_route_rules
, chain
) { 
5290                 if (memcmp(existing_rule
->rule_ids
, rule_ids
, (sizeof(u_int32_t
) * MAX_AGGREGATE_ROUTE_RULES
)) == 0) { 
5291                         lck_rw_done(&necp_route_rule_lock
); 
5292                         return existing_rule
->id
; 
5296         MALLOC(new_rule
, struct necp_aggregate_route_rule 
*, sizeof(struct necp_aggregate_route_rule
), M_NECP
, M_WAITOK
); 
5297         if (new_rule 
!= NULL
) { 
5298                 memset(new_rule
, 0, sizeof(struct necp_aggregate_route_rule
)); 
5299                 aggregate_route_rule_id 
= new_rule
->id 
= necp_get_new_route_rule_id(true); 
5300                 new_rule
->id 
= aggregate_route_rule_id
; 
5301                 memcpy(new_rule
->rule_ids
, rule_ids
, (sizeof(u_int32_t
) * MAX_AGGREGATE_ROUTE_RULES
)); 
5302                 LIST_INSERT_HEAD(&necp_aggregate_route_rules
, new_rule
, chain
); 
5304         lck_rw_done(&necp_route_rule_lock
); 
5306         return aggregate_route_rule_id
; 
5309 #define NECP_NULL_SERVICE_ID 1 
5310 #define NECP_FIRST_VALID_SERVICE_ID  2 
5311 #define NECP_FIRST_VALID_APP_ID  UINT16_MAX 
5313 necp_get_new_uuid_id(bool service
) 
5315         static u_int32_t necp_last_service_uuid_id 
= 0; 
5316         static u_int32_t necp_last_app_uuid_id 
= 0; 
5318         u_int32_t newid 
= 0; 
5320         LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
); 
5323                 bool wrapped 
= FALSE
; 
5325                         necp_last_service_uuid_id
++; 
5326                         if (necp_last_service_uuid_id 
< NECP_FIRST_VALID_SERVICE_ID 
|| 
5327                             necp_last_service_uuid_id 
>= NECP_FIRST_VALID_APP_ID
) { 
5329                                         // Already wrapped, give up 
5330                                         NECPLOG0(LOG_ERR
, "Failed to find a free service UUID.\n"); 
5331                                         return NECP_NULL_SERVICE_ID
; 
5333                                 necp_last_service_uuid_id 
= NECP_FIRST_VALID_SERVICE_ID
; 
5336                         newid 
= necp_last_service_uuid_id
; 
5337                 } while (necp_uuid_lookup_uuid_with_service_id_locked(newid
) != NULL
); // If already used, keep trying 
5339                 bool wrapped 
= FALSE
; 
5341                         necp_last_app_uuid_id
++; 
5342                         if (necp_last_app_uuid_id 
< NECP_FIRST_VALID_APP_ID
) { 
5344                                         // Already wrapped, give up 
5345                                         NECPLOG0(LOG_ERR
, "Failed to find a free app UUID.\n"); 
5346                                         return NECP_NULL_SERVICE_ID
; 
5348                                 necp_last_app_uuid_id 
= NECP_FIRST_VALID_APP_ID
; 
5351                         newid 
= necp_last_app_uuid_id
; 
5352                 } while (necp_uuid_lookup_uuid_with_app_id_locked(newid
) != NULL
); // If already used, keep trying 
5355         if (newid 
== NECP_NULL_SERVICE_ID
) { 
5356                 NECPLOG0(LOG_ERR
, "Allocate uuid ID failed.\n"); 
5357                 return NECP_NULL_SERVICE_ID
; 
5363 static struct necp_uuid_id_mapping 
* 
5364 necp_uuid_lookup_app_id_locked(uuid_t uuid
) 
5366         struct necp_uuid_id_mapping 
*searchentry 
= NULL
; 
5367         struct necp_uuid_id_mapping 
*foundentry 
= NULL
; 
5369         LIST_FOREACH(searchentry
, APPUUIDHASH(uuid
), chain
) { 
5370                 if (uuid_compare(searchentry
->uuid
, uuid
) == 0) { 
5371                         foundentry 
= searchentry
; 
5379 static struct necp_uuid_id_mapping 
* 
5380 necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id
) 
5382         struct necp_uuid_id_mapping 
*searchentry 
= NULL
; 
5383         struct necp_uuid_id_mapping 
*foundentry 
= NULL
; 
5385         struct necp_uuid_id_mapping_head 
*uuid_list_head 
= NULL
; 
5386         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
--) { 
5387                 LIST_FOREACH(searchentry
, uuid_list_head
, chain
) { 
5388                         if (searchentry
->id 
== local_id
) { 
5389                                 foundentry 
= searchentry
; 
5399 necp_create_uuid_app_id_mapping(uuid_t uuid
, bool *allocated_mapping
, bool uuid_policy_table
) 
5401         u_int32_t local_id 
= 0; 
5402         struct necp_uuid_id_mapping 
*existing_mapping 
= NULL
; 
5404         LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
); 
5406         if (allocated_mapping
) { 
5407                 *allocated_mapping 
= FALSE
; 
5410         existing_mapping 
= necp_uuid_lookup_app_id_locked(uuid
); 
5411         if (existing_mapping 
!= NULL
) { 
5412                 local_id 
= existing_mapping
->id
; 
5413                 os_ref_retain_locked(&existing_mapping
->refcount
); 
5414                 if (uuid_policy_table
) { 
5415                         existing_mapping
->table_usecount
++; 
5418                 struct necp_uuid_id_mapping 
*new_mapping 
= NULL
; 
5419                 MALLOC(new_mapping
, struct necp_uuid_id_mapping 
*, sizeof(*new_mapping
), M_NECP
, M_WAITOK
); 
5420                 if (new_mapping 
!= NULL
) { 
5421                         uuid_copy(new_mapping
->uuid
, uuid
); 
5422                         new_mapping
->id 
= necp_get_new_uuid_id(false); 
5423                         os_ref_init(&new_mapping
->refcount
, &necp_refgrp
); 
5424                         if (uuid_policy_table
) { 
5425                                 new_mapping
->table_usecount 
= 1; 
5427                                 new_mapping
->table_usecount 
= 0; 
5430                         LIST_INSERT_HEAD(APPUUIDHASH(uuid
), new_mapping
, chain
); 
5432                         if (allocated_mapping
) { 
5433                                 *allocated_mapping 
= TRUE
; 
5436                         local_id 
= new_mapping
->id
; 
5444 necp_remove_uuid_app_id_mapping(uuid_t uuid
, bool *removed_mapping
, bool uuid_policy_table
) 
5446         struct necp_uuid_id_mapping 
*existing_mapping 
= NULL
; 
5448         LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
); 
5450         if (removed_mapping
) { 
5451                 *removed_mapping 
= FALSE
; 
5454         existing_mapping 
= necp_uuid_lookup_app_id_locked(uuid
); 
5455         if (existing_mapping 
!= NULL
) { 
5456                 if (uuid_policy_table
) { 
5457                         existing_mapping
->table_usecount
--; 
5459                 if (os_ref_release_locked(&existing_mapping
->refcount
) == 0) { 
5460                         LIST_REMOVE(existing_mapping
, chain
); 
5461                         FREE(existing_mapping
, M_NECP
); 
5462                         if (removed_mapping
) { 
5463                                 *removed_mapping 
= TRUE
; 
5472 static struct necp_uuid_id_mapping 
* 
5473 necp_uuid_get_null_service_id_mapping(void) 
5475         static struct necp_uuid_id_mapping null_mapping
; 
5476         uuid_clear(null_mapping
.uuid
); 
5477         null_mapping
.id 
= NECP_NULL_SERVICE_ID
; 
5479         return &null_mapping
; 
5482 static struct necp_uuid_id_mapping 
* 
5483 necp_uuid_lookup_service_id_locked(uuid_t uuid
) 
5485         struct necp_uuid_id_mapping 
*searchentry 
= NULL
; 
5486         struct necp_uuid_id_mapping 
*foundentry 
= NULL
; 
5488         if (uuid_is_null(uuid
)) { 
5489                 return necp_uuid_get_null_service_id_mapping(); 
5492         LIST_FOREACH(searchentry
, &necp_uuid_service_id_list
, chain
) { 
5493                 if (uuid_compare(searchentry
->uuid
, uuid
) == 0) { 
5494                         foundentry 
= searchentry
; 
5502 static struct necp_uuid_id_mapping 
* 
5503 necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id
) 
5505         struct necp_uuid_id_mapping 
*searchentry 
= NULL
; 
5506         struct necp_uuid_id_mapping 
*foundentry 
= NULL
; 
5508         if (local_id 
== NECP_NULL_SERVICE_ID
) { 
5509                 return necp_uuid_get_null_service_id_mapping(); 
5512         LIST_FOREACH(searchentry
, &necp_uuid_service_id_list
, chain
) { 
5513                 if (searchentry
->id 
== local_id
) { 
5514                         foundentry 
= searchentry
; 
5523 necp_create_uuid_service_id_mapping(uuid_t uuid
) 
5525         u_int32_t local_id 
= 0; 
5526         struct necp_uuid_id_mapping 
*existing_mapping 
= NULL
; 
5528         if (uuid_is_null(uuid
)) { 
5529                 return NECP_NULL_SERVICE_ID
; 
5532         LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
); 
5534         existing_mapping 
= necp_uuid_lookup_service_id_locked(uuid
); 
5535         if (existing_mapping 
!= NULL
) { 
5536                 local_id 
= existing_mapping
->id
; 
5537                 os_ref_retain_locked(&existing_mapping
->refcount
); 
5539                 struct necp_uuid_id_mapping 
*new_mapping 
= NULL
; 
5540                 MALLOC(new_mapping
, struct necp_uuid_id_mapping 
*, sizeof(*new_mapping
), M_NECP
, M_WAITOK
); 
5541                 if (new_mapping 
!= NULL
) { 
5542                         uuid_copy(new_mapping
->uuid
, uuid
); 
5543                         new_mapping
->id 
= necp_get_new_uuid_id(true); 
5544                         os_ref_init(&new_mapping
->refcount
, &necp_refgrp
); 
5546                         LIST_INSERT_HEAD(&necp_uuid_service_id_list
, new_mapping
, chain
); 
5548                         local_id 
= new_mapping
->id
; 
5556 necp_remove_uuid_service_id_mapping(uuid_t uuid
) 
5558         struct necp_uuid_id_mapping 
*existing_mapping 
= NULL
; 
5560         if (uuid_is_null(uuid
)) { 
5564         LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
); 
5566         existing_mapping 
= necp_uuid_lookup_service_id_locked(uuid
); 
5567         if (existing_mapping 
!= NULL
) { 
5568                 if (os_ref_release_locked(&existing_mapping
->refcount
) == 0) { 
5569                         LIST_REMOVE(existing_mapping
, chain
); 
5570                         FREE(existing_mapping
, M_NECP
); 
5579 necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id
) 
5581         struct necp_uuid_id_mapping 
*existing_mapping 
= NULL
; 
5583         if (service_id 
== 0) { 
5587         LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
); 
5589         existing_mapping 
= necp_uuid_lookup_uuid_with_service_id_locked(service_id
); 
5590         if (existing_mapping 
!= NULL
) { 
5591                 if (os_ref_release_locked(&existing_mapping
->refcount
) == 0) { 
5592                         LIST_REMOVE(existing_mapping
, chain
); 
5593                         FREE(existing_mapping
, M_NECP
); 
5602 necp_kernel_socket_policies_update_uuid_table(void) 
5604         LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
); 
5606         if (necp_uuid_app_id_mappings_dirty
) { 
5607                 if (proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_CLEAR
, NULL
, PROC_UUID_NECP_APP_POLICY
) < 0) { 
5608                         NECPLOG0(LOG_DEBUG
, "Error clearing uuids from policy table\n"); 
5612                 if (necp_num_uuid_app_id_mappings 
> 0) { 
5613                         struct necp_uuid_id_mapping_head 
*uuid_list_head 
= NULL
; 
5614                         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
--) { 
5615                                 struct necp_uuid_id_mapping 
*mapping 
= NULL
; 
5616                                 LIST_FOREACH(mapping
, uuid_list_head
, chain
) { 
5617                                         if (mapping
->table_usecount 
> 0 && 
5618                                             proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_ADD
, mapping
->uuid
, PROC_UUID_NECP_APP_POLICY
) < 0) { 
5619                                                 NECPLOG0(LOG_DEBUG
, "Error adding uuid to policy table\n"); 
5625                 necp_uuid_app_id_mappings_dirty 
= FALSE
; 
5631 #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) 
5632 static necp_kernel_policy_id
 
5633 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
) 
5635         struct necp_kernel_ip_output_policy 
*new_kernel_policy 
= NULL
; 
5636         struct necp_kernel_ip_output_policy 
*tmp_kernel_policy 
= NULL
; 
5638         new_kernel_policy 
= zalloc_flags(necp_ip_policy_zone
, Z_WAITOK 
| Z_ZERO
); 
5639         new_kernel_policy
->id 
= necp_kernel_policy_get_new_id(false); 
5640         new_kernel_policy
->suborder 
= suborder
; 
5641         new_kernel_policy
->order 
= order
; 
5642         new_kernel_policy
->session_order 
= session_order
; 
5643         new_kernel_policy
->session_pid 
= session_pid
; 
5645         // Sanitize condition mask 
5646         new_kernel_policy
->condition_mask 
= (condition_mask 
& NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS
); 
5647         if ((new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
)) { 
5648                 new_kernel_policy
->condition_mask 
&= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE
; 
5650         if ((new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_END
) && (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
)) { 
5651                 new_kernel_policy
->condition_mask 
&= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX
; 
5653         if ((new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_END
) && (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
)) { 
5654                 new_kernel_policy
->condition_mask 
&= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX
; 
5656         new_kernel_policy
->condition_negated_mask 
= condition_negated_mask 
& new_kernel_policy
->condition_mask
; 
5658         // Set condition values 
5659         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_POLICY_ID
) { 
5660                 new_kernel_policy
->cond_policy_id 
= cond_policy_id
; 
5662         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) { 
5663                 if (cond_bound_interface
) { 
5664                         ifnet_reference(cond_bound_interface
); 
5666                 new_kernel_policy
->cond_bound_interface 
= cond_bound_interface
; 
5668         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LAST_INTERFACE
) { 
5669                 new_kernel_policy
->cond_last_interface_index 
= cond_last_interface_index
; 
5671         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_PROTOCOL
) { 
5672                 new_kernel_policy
->cond_protocol 
= cond_protocol
; 
5674         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_START
) { 
5675                 memcpy(&new_kernel_policy
->cond_local_start
, cond_local_start
, cond_local_start
->sa
.sa_len
); 
5677         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_END
) { 
5678                 memcpy(&new_kernel_policy
->cond_local_end
, cond_local_end
, cond_local_end
->sa
.sa_len
); 
5680         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) { 
5681                 new_kernel_policy
->cond_local_prefix 
= cond_local_prefix
; 
5683         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_START
) { 
5684                 memcpy(&new_kernel_policy
->cond_remote_start
, cond_remote_start
, cond_remote_start
->sa
.sa_len
); 
5686         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_END
) { 
5687                 memcpy(&new_kernel_policy
->cond_remote_end
, cond_remote_end
, cond_remote_end
->sa
.sa_len
); 
5689         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) { 
5690                 new_kernel_policy
->cond_remote_prefix 
= cond_remote_prefix
; 
5692         if (new_kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) { 
5693                 new_kernel_policy
->cond_packet_filter_tags 
= cond_packet_filter_tags
; 
5696         new_kernel_policy
->result 
= result
; 
5697         memcpy(&new_kernel_policy
->result_parameter
, &result_parameter
, sizeof(result_parameter
)); 
5700                 NECPLOG(LOG_DEBUG
, "Added kernel policy: ip output, id=%d, mask=%x\n", new_kernel_policy
->id
, new_kernel_policy
->condition_mask
); 
5702         LIST_INSERT_SORTED_THRICE_ASCENDING(&necp_kernel_ip_output_policies
, new_kernel_policy
, chain
, session_order
, order
, suborder
, tmp_kernel_policy
); 
5704         return new_kernel_policy 
? new_kernel_policy
->id 
: 0; 
5707 static struct necp_kernel_ip_output_policy 
* 
5708 necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id
) 
5710         struct necp_kernel_ip_output_policy 
*kernel_policy 
= NULL
; 
5711         struct necp_kernel_ip_output_policy 
*tmp_kernel_policy 
= NULL
; 
5713         if (policy_id 
== 0) { 
5717         LIST_FOREACH_SAFE(kernel_policy
, &necp_kernel_ip_output_policies
, chain
, tmp_kernel_policy
) { 
5718                 if (kernel_policy
->id 
== policy_id
) { 
5719                         return kernel_policy
; 
5727 necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id
) 
5729         struct necp_kernel_ip_output_policy 
*policy 
= NULL
; 
5731         LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
); 
5733         policy 
= necp_kernel_ip_output_policy_find(policy_id
); 
5735                 LIST_REMOVE(policy
, chain
); 
5737                 if (policy
->cond_bound_interface
) { 
5738                         ifnet_release(policy
->cond_bound_interface
); 
5739                         policy
->cond_bound_interface 
= NULL
; 
5742                 zfree(necp_ip_policy_zone
, policy
); 
5750 necp_kernel_ip_output_policies_dump_all(void) 
5753                 struct necp_kernel_ip_output_policy 
*policy 
= NULL
; 
5756                 char result_string
[MAX_RESULT_STRING_LEN
]; 
5757                 char proc_name_string
[MAXCOMLEN 
+ 1]; 
5758                 memset(result_string
, 0, MAX_RESULT_STRING_LEN
); 
5759                 memset(proc_name_string
, 0, MAXCOMLEN 
+ 1); 
5761                 NECPLOG0(LOG_DEBUG
, "NECP IP Output Policies:\n"); 
5762                 NECPLOG0(LOG_DEBUG
, "-----------\n"); 
5763                 for (id_i 
= 0; id_i 
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; id_i
++) { 
5764                         NECPLOG(LOG_DEBUG
, " ID Bucket: %d\n", id_i
); 
5765                         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
++) { 
5766                                 policy 
= (necp_kernel_ip_output_policies_map
[id_i
])[policy_i
]; 
5767                                 proc_name(policy
->session_pid
, proc_name_string
, MAXCOMLEN
); 
5768                                 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
)); 
5770                         NECPLOG0(LOG_DEBUG
, "-----------\n"); 
5776 necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy 
*upper_policy
, struct necp_kernel_ip_output_policy 
*lower_policy
) 
5778         if (upper_policy
->result 
== NECP_KERNEL_POLICY_RESULT_SKIP
) { 
5779                 if (upper_policy
->session_order 
!= lower_policy
->session_order
) { 
5780                         // A skip cannot override a policy of a different session 
5783                         if (upper_policy
->result_parameter
.skip_policy_order 
== 0 || 
5784                             lower_policy
->order 
>= upper_policy
->result_parameter
.skip_policy_order
) { 
5785                                 // This policy is beyond the skip 
5788                                 // This policy is inside the skip 
5794         // All other IP Output policy results (drop, tunnel, hard pass) currently overlap 
5799 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
) 
5801         bool can_skip 
= FALSE
; 
5802         u_int32_t highest_skip_session_order 
= 0; 
5803         u_int32_t highest_skip_order 
= 0; 
5805         for (i 
= 0; i 
< valid_indices
; i
++) { 
5806                 struct necp_kernel_ip_output_policy 
*compared_policy 
= policy_array
[i
]; 
5808                 // For policies in a skip window, we can't mark conflicting policies as unnecessary 
5810                         if (highest_skip_session_order 
!= compared_policy
->session_order 
|| 
5811                             (highest_skip_order 
!= 0 && compared_policy
->order 
>= highest_skip_order
)) { 
5812                                 // If we've moved on to the next session, or passed the skip window 
5813                                 highest_skip_session_order 
= 0; 
5814                                 highest_skip_order 
= 0; 
5817                                 // If this policy is also a skip, in can increase the skip window 
5818                                 if (compared_policy
->result 
== NECP_KERNEL_POLICY_RESULT_SKIP
) { 
5819                                         if (compared_policy
->result_parameter
.skip_policy_order 
> highest_skip_order
) { 
5820                                                 highest_skip_order 
= compared_policy
->result_parameter
.skip_policy_order
; 
5827                 if (compared_policy
->result 
== NECP_KERNEL_POLICY_RESULT_SKIP
) { 
5828                         // This policy is a skip. Set the skip window accordingly 
5830                         highest_skip_session_order 
= compared_policy
->session_order
; 
5831                         highest_skip_order 
= compared_policy
->result_parameter
.skip_policy_order
; 
5834                 // The result of the compared policy must be able to block out this policy result 
5835                 if (!necp_kernel_ip_output_policy_results_overlap(compared_policy
, policy
)) { 
5839                 // If new policy matches All Interfaces, compared policy must also 
5840                 if ((policy
->condition_mask 
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && !(compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) { 
5844                 // If new policy matches Local Networks, compared policy must also 
5845                 if ((policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) && !(compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
)) { 
5849                 // Default makes lower policies unecessary always 
5850                 if (compared_policy
->condition_mask 
== 0) { 
5854                 // Compared must be more general than policy, and include only conditions within policy 
5855                 if ((policy
->condition_mask 
& compared_policy
->condition_mask
) != compared_policy
->condition_mask
) { 
5859                 // Negative conditions must match for the overlapping conditions 
5860                 if ((policy
->condition_negated_mask 
& compared_policy
->condition_mask
) != (compared_policy
->condition_negated_mask 
& compared_policy
->condition_mask
)) { 
5864                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_POLICY_ID 
&& 
5865                     compared_policy
->cond_policy_id 
!= policy
->cond_policy_id
) { 
5869                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_BOUND_INTERFACE 
&& 
5870                     compared_policy
->cond_bound_interface 
!= policy
->cond_bound_interface
) { 
5874                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_PROTOCOL 
&& 
5875                     compared_policy
->cond_protocol 
!= policy
->cond_protocol
) { 
5879                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_START
) { 
5880                         if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_END
) { 
5881                                 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
)) { 
5884                         } else if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) { 
5885                                 if (compared_policy
->cond_local_prefix 
> policy
->cond_local_prefix 
|| 
5886                                     !necp_is_addr_in_subnet((struct sockaddr 
*)&policy
->cond_local_start
, (struct sockaddr 
*)&compared_policy
->cond_local_start
, compared_policy
->cond_local_prefix
)) { 
5892                 if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_START
) { 
5893                         if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_END
) { 
5894                                 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
)) { 
5897                         } else if (compared_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) { 
5898                                 if (compared_policy
->cond_remote_prefix 
> policy
->cond_remote_prefix 
|| 
5899                                     !necp_is_addr_in_subnet((struct sockaddr 
*)&policy
->cond_remote_start
, (struct sockaddr 
*)&compared_policy
->cond_remote_start
, compared_policy
->cond_remote_prefix
)) { 
5912 necp_kernel_ip_output_policies_reprocess(void) 
5915         int bucket_allocation_counts
[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
]; 
5916         int bucket_current_free_index
[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
]; 
5917         struct necp_kernel_ip_output_policy 
*kernel_policy 
= NULL
; 
5919         LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
); 
5922         necp_kernel_ip_output_policies_condition_mask 
= 0; 
5923         necp_kernel_ip_output_policies_count 
= 0; 
5924         necp_kernel_ip_output_policies_non_id_count 
= 0; 
5926         for (i 
= 0; i 
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) { 
5927                 if (necp_kernel_ip_output_policies_map
[i
] != NULL
) { 
5928                         FREE(necp_kernel_ip_output_policies_map
[i
], M_NECP
); 
5929                         necp_kernel_ip_output_policies_map
[i
] = NULL
; 
5933                 bucket_allocation_counts
[i
] = 0; 
5936         LIST_FOREACH(kernel_policy
, &necp_kernel_ip_output_policies
, chain
) { 
5938                 necp_kernel_ip_output_policies_condition_mask 
|= kernel_policy
->condition_mask
; 
5939                 necp_kernel_ip_output_policies_count
++; 
5941                 /* Update bucket counts: 
5942                  * Non-id and SKIP policies will be added to all buckets 
5943                  * Add local networks policy to all buckets for incoming IP 
5945                 if (!(kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_POLICY_ID
) || 
5946                     (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) || 
5947                     kernel_policy
->result 
== NECP_KERNEL_POLICY_RESULT_SKIP
) { 
5948                         for (i 
= 0; i 
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) { 
5949                                 bucket_allocation_counts
[i
]++; 
5952                 if (!(kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_POLICY_ID
)) { 
5953                         necp_kernel_ip_output_policies_non_id_count
++; 
5955                         bucket_allocation_counts
[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy
->cond_policy_id
)]++; 
5959         for (i 
= 0; i 
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) { 
5960                 if (bucket_allocation_counts
[i
] > 0) { 
5961                         // Allocate a NULL-terminated array of policy pointers for each bucket 
5962                         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
); 
5963                         if (necp_kernel_ip_output_policies_map
[i
] == NULL
) { 
5967                         // Initialize the first entry to NULL 
5968                         (necp_kernel_ip_output_policies_map
[i
])[0] = NULL
; 
5970                 bucket_current_free_index
[i
] = 0; 
5973         LIST_FOREACH(kernel_policy
, &necp_kernel_ip_output_policies
, chain
) { 
5974                 // Insert pointers into map 
5975                 if (!(kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_POLICY_ID
) || 
5976                     (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) || 
5977                     kernel_policy
->result 
== NECP_KERNEL_POLICY_RESULT_SKIP
) { 
5978                         for (i 
= 0; i 
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) { 
5979                                 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
])) { 
5980                                         (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = kernel_policy
; 
5981                                         bucket_current_free_index
[i
]++; 
5982                                         (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = NULL
; 
5986                         i 
= NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy
->cond_policy_id
); 
5987                         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
])) { 
5988                                 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = kernel_policy
; 
5989                                 bucket_current_free_index
[i
]++; 
5990                                 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = NULL
; 
5994         necp_kernel_ip_output_policies_dump_all(); 
5998         // Free memory, reset mask to 0 
5999         necp_kernel_ip_output_policies_condition_mask 
= 0; 
6000         necp_kernel_ip_output_policies_count 
= 0; 
6001         necp_kernel_ip_output_policies_non_id_count 
= 0; 
6002         for (i 
= 0; i 
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) { 
6003                 if (necp_kernel_ip_output_policies_map
[i
] != NULL
) { 
6004                         FREE(necp_kernel_ip_output_policies_map
[i
], M_NECP
); 
6005                         necp_kernel_ip_output_policies_map
[i
] = NULL
; 
6011 // Outbound Policy Matching 
6012 // --------------------- 
6018 static struct substring
 
6019 necp_trim_dots_and_stars(char *string
, size_t length
) 
6021         struct substring sub
; 
6022         sub
.string 
= string
; 
6023         sub
.length 
= string 
? length 
: 0; 
6025         while (sub
.length 
&& (sub
.string
[0] == '.' || sub
.string
[0] == '*')) { 
6030         while (sub
.length 
&& (sub
.string
[sub
.length 
- 1] == '.' || sub
.string
[sub
.length 
- 1] == '*')) { 
6038 necp_create_trimmed_domain(char *string
, size_t length
) 
6040         char *trimmed_domain 
= NULL
; 
6041         struct substring sub 
= necp_trim_dots_and_stars(string
, length
); 
6043         MALLOC(trimmed_domain
, char *, sub
.length 
+ 1, M_NECP
, M_WAITOK
); 
6044         if (trimmed_domain 
== NULL
) { 
6048         memcpy(trimmed_domain
, sub
.string
, sub
.length
); 
6049         trimmed_domain
[sub
.length
] = 0; 
6051         return trimmed_domain
; 
6055 necp_count_dots(char *string
, size_t length
) 
6060         for (i 
= 0; i 
< length
; i
++) { 
6061                 if (string
[i
] == '.') { 
6070 necp_check_suffix(struct substring parent
, struct substring suffix
, bool require_dot_before_suffix
) 
6072         if (parent
.length 
<= suffix
.length
) { 
6076         size_t length_difference 
= (parent
.length 
- suffix
.length
); 
6078         if (require_dot_before_suffix
) { 
6079                 if (((char *)(parent
.string 
+ length_difference 
- 1))[0] != '.') { 
6084         // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters) 
6085         return strncasecmp(parent
.string 
+ length_difference
, suffix
.string
, suffix
.length
) == 0; 
6089 necp_hostname_matches_domain(struct substring hostname_substring
, u_int8_t hostname_dot_count
, char *domain
, u_int8_t domain_dot_count
) 
6091         if (hostname_substring
.string 
== NULL 
|| domain 
== NULL
) { 
6092                 return hostname_substring
.string 
== domain
; 
6095         struct substring domain_substring
; 
6096         domain_substring
.string 
= domain
; 
6097         domain_substring
.length 
= strlen(domain
); 
6099         if (hostname_dot_count 
== domain_dot_count
) { 
6100                 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters) 
6101                 if (hostname_substring
.length 
== domain_substring
.length 
&& 
6102                     strncasecmp(hostname_substring
.string
, domain_substring
.string
, hostname_substring
.length
) == 0) { 
6105         } else if (domain_dot_count 
< hostname_dot_count
) { 
6106                 if (necp_check_suffix(hostname_substring
, domain_substring
, TRUE
)) { 
6115 net_domain_contains_hostname(char *hostname_string
, char *domain_string
) 
6117         if (hostname_string 
== NULL 
|| 
6118             domain_string 
== NULL
) { 
6122         struct substring hostname_substring
; 
6123         hostname_substring
.string 
= hostname_string
; 
6124         hostname_substring
.length 
= strlen(hostname_string
); 
6126         return necp_hostname_matches_domain(hostname_substring
, 
6127                    necp_count_dots(hostname_string
, hostname_substring
.length
), 
6129                    necp_count_dots(domain_string
, strlen(domain_string
))); 
6132 #define NECP_MAX_STRING_LEN 1024 
6135 necp_copy_string(char *string
, size_t length
) 
6137         char *copied_string 
= NULL
; 
6139         if (length 
> NECP_MAX_STRING_LEN
) { 
6143         MALLOC(copied_string
, char *, length 
+ 1, M_NECP
, M_WAITOK
); 
6144         if (copied_string 
== NULL
) { 
6148         memcpy(copied_string
, string
, length
); 
6149         copied_string
[length
] = 0; 
6151         return copied_string
; 
6155 necp_get_primary_direct_interface_index(void) 
6157         u_int32_t interface_index 
= IFSCOPE_NONE
; 
6159         ifnet_head_lock_shared(); 
6160         struct ifnet 
*ordered_interface 
= NULL
; 
6161         TAILQ_FOREACH(ordered_interface
, &ifnet_ordered_head
, if_ordered_link
) { 
6162                 const u_int8_t functional_type 
= if_functional_type(ordered_interface
, TRUE
); 
6163                 if (functional_type 
!= IFRTYPE_FUNCTIONAL_UNKNOWN 
&& 
6164                     functional_type 
!= IFRTYPE_FUNCTIONAL_LOOPBACK
) { 
6165                         // All known, non-loopback functional types represent direct physical interfaces (Wi-Fi, Cellular, Wired) 
6166                         interface_index 
= ordered_interface
->if_index
; 
6172         return interface_index
; 
6176 necp_get_parent_cred_result(proc_t proc
, struct necp_socket_info 
*info
) 
6178         task_t task 
= proc_task(proc 
? proc 
: current_proc()); 
6179         coalition_t coal 
= task_get_coalition(task
, COALITION_TYPE_JETSAM
); 
6181         if (coal 
== COALITION_NULL 
|| coalition_is_leader(task
, coal
)) { 
6182                 // No parent, nothing to do 
6186         task_t lead_task 
= coalition_get_leader(coal
); 
6187         if (lead_task 
!= NULL
) { 
6188                 proc_t lead_proc 
= get_bsdtask_info(lead_task
); 
6189                 if (lead_proc 
!= NULL
) { 
6190                         kauth_cred_t lead_cred 
= kauth_cred_proc_ref(lead_proc
); 
6191                         if (lead_cred 
!= NULL
) { 
6192                                 errno_t cred_result 
= priv_check_cred(lead_cred
, PRIV_NET_PRIVILEGED_NECP_MATCH
, 0); 
6193                                 kauth_cred_unref(&lead_cred
); 
6194                                 info
->cred_result 
= cred_result
; 
6197                 task_deallocate(lead_task
); 
6201 // Some processes, due to particular entitlements, require using an NECP client to 
6202 // access networking. Returns true if the result should be a Drop. 
6204 necp_check_missing_client_drop(proc_t proc
, struct necp_socket_info 
*info
) 
6206         task_t task 
= proc_task(proc 
? proc 
: current_proc()); 
6208         if (!info
->has_client 
&& 
6210             IOTaskHasEntitlement(task
, "com.apple.developer.on-demand-install-capable")) { 
6211                 // Drop connections that don't use NECP clients and have the 
6212                 // com.apple.developer.on-demand-install-capable entitlement. 
6213                 // This effectively restricts those processes to only using 
6214                 // an NECP-aware path for networking. 
6222 necp_check_restricted_multicast_drop(proc_t proc
, struct necp_socket_info 
*info
, bool check_minor_version
) 
6224         if (!necp_restrict_multicast 
|| proc 
== NULL
) { 
6228         // Check for multicast/broadcast here 
6229         if (info
->remote_addr
.sa
.sa_family 
== AF_INET
) { 
6230                 if (!IN_MULTICAST(ntohl(info
->remote_addr
.sin
.sin_addr
.s_addr
)) && 
6231                     info
->remote_addr
.sin
.sin_addr
.s_addr 
!= INADDR_BROADCAST
) { 
6234         } else if (info
->remote_addr
.sa
.sa_family 
== AF_INET6
) { 
6235                 if (!IN6_IS_ADDR_MULTICAST(&info
->remote_addr
.sin6
.sin6_addr
)) { 
6243         if (necp_is_platform_binary(proc
)) { 
6247         const uint32_t platform 
= proc_platform(proc
); 
6248         const uint32_t sdk 
= proc_sdk(proc
); 
6250         // Enforce for iOS, linked on or after version 14 
6251         // If the caller set `check_minor_version`, only enforce starting at 14.5 
6252         if (platform 
!= PLATFORM_IOS 
|| 
6255             (check_minor_version 
&& (sdk 
>> 16) == 14 && ((sdk 
>> 8) & 0xff) < 5)) { 
6259         // Allow entitled processes to use multicast 
6260         task_t task 
= proc_task(proc
); 
6262             IOTaskHasEntitlement(task
, "com.apple.developer.networking.multicast")) { 
6266         const uint32_t min_sdk 
= proc_min_sdk(proc
); 
6267         NECPLOG(LOG_INFO
, "Dropping unentitled multicast (SDK 0x%x, min 0x%x)", sdk
, min_sdk
); 
6272 #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) 
6274 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
, int32_t pid_version
, 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 real_proc
, proc_t proc
, proc_t responsible_proc
, u_int32_t drop_order
, u_int32_t client_flags
, struct necp_socket_info 
*info
, bool is_loopback
, bool is_delegated
) 
6276         memset(info
, 0, sizeof(struct necp_socket_info
)); 
6279         info
->pid_version 
= pid_version
; 
6281         info
->protocol 
= protocol
; 
6282         info
->bound_interface_index 
= bound_interface_index
; 
6283         info
->traffic_class 
= traffic_class
; 
6284         info
->has_client 
= has_client
; 
6285         info
->drop_order 
= drop_order
; 
6286         info
->client_flags 
= client_flags
; 
6287         info
->is_loopback 
= is_loopback
; 
6288         info
->is_delegated 
= is_delegated
; 
6290         if (necp_kernel_application_policies_condition_mask 
& NECP_KERNEL_CONDITION_APP_ID 
&& !uuid_is_null(application_uuid
)) { 
6291                 struct necp_uuid_id_mapping 
*existing_mapping 
= necp_uuid_lookup_app_id_locked(application_uuid
); 
6292                 if (existing_mapping
) { 
6293                         info
->application_id 
= existing_mapping
->id
; 
6297         if (necp_kernel_application_policies_condition_mask 
& NECP_KERNEL_CONDITION_REAL_APP_ID 
&& !uuid_is_null(real_application_uuid
)) { 
6298                 if (uuid_compare(application_uuid
, real_application_uuid
) == 0) { 
6299                         info
->real_application_id 
= info
->application_id
; 
6301                         struct necp_uuid_id_mapping 
*existing_mapping 
= necp_uuid_lookup_app_id_locked(real_application_uuid
); 
6302                         if (existing_mapping
) { 
6303                                 info
->real_application_id 
= existing_mapping
->id
; 
6308         if (necp_kernel_application_policies_condition_mask 
& NECP_KERNEL_CONDITION_APP_ID 
&& !uuid_is_null(responsible_application_uuid
)) { 
6309                 struct necp_uuid_id_mapping 
*existing_mapping 
= necp_uuid_lookup_app_id_locked(responsible_application_uuid
); 
6310                 if (existing_mapping 
!= NULL
) { 
6311                         info
->real_application_id 
= info
->application_id
; 
6312                         info
->application_id 
= existing_mapping
->id
; 
6313                         info
->used_responsible_pid 
= true; 
6317         if (info
->used_responsible_pid
) { 
6318                 proc 
= responsible_proc
; 
6321         if (necp_kernel_application_policies_condition_mask 
& NECP_KERNEL_CONDITION_ENTITLEMENT 
&& proc 
!= NULL
) { 
6322                 info
->cred_result 
= priv_check_cred(proc_ucred(proc
), PRIV_NET_PRIVILEGED_NECP_MATCH
, 0); 
6323                 if (info
->cred_result 
!= 0) { 
6324                         // Process does not have entitlement, check the parent process 
6325                         necp_get_parent_cred_result(proc
, info
); 
6329         if (necp_kernel_application_policies_condition_mask 
& NECP_KERNEL_CONDITION_PLATFORM_BINARY 
&& proc 
!= NULL
) { 
6330                 info
->is_platform_binary 
= necp_is_platform_binary(proc
) ? true : false; 
6333         if (necp_kernel_application_policies_condition_mask 
& NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY 
&& real_proc 
!= NULL
) { 
6334                 info
->real_is_platform_binary 
= (necp_is_platform_binary(real_proc
) ? true : false); 
6337         if (necp_kernel_application_policies_condition_mask 
& NECP_KERNEL_CONDITION_ACCOUNT_ID 
&& account 
!= NULL
) { 
6338                 struct necp_string_id_mapping 
*existing_mapping 
= necp_lookup_string_to_id_locked(&necp_account_id_list
, account
); 
6339                 if (existing_mapping
) { 
6340                         info
->account_id 
= existing_mapping
->id
; 
6344         if (necp_kernel_application_policies_condition_mask 
& NECP_KERNEL_CONDITION_DOMAIN
) { 
6345                 info
->domain 
= domain
; 
6348         if (necp_restrict_multicast 
|| 
6349             (necp_kernel_application_policies_condition_mask 
& NECP_KERNEL_ADDRESS_TYPE_CONDITIONS
)) { 
6350                 if (local_addr 
&& local_addr
->sa
.sa_len 
> 0) { 
6351                         memcpy(&info
->local_addr
, local_addr
, local_addr
->sa
.sa_len
); 
6352                         if (local_port 
!= 0) { 
6353                                 info
->local_addr
.sin6
.sin6_port 
= local_port
; 
6356                         if (remote_addr 
&& remote_addr
->sa
.sa_len 
> 0) { 
6357                                 info
->local_addr
.sa
.sa_family 
= remote_addr
->sa
.sa_family
; 
6358                                 info
->local_addr
.sa
.sa_len 
= remote_addr
->sa
.sa_len
; 
6360                                 info
->local_addr
.sin6
.sin6_family 
= AF_INET6
; 
6361                                 info
->local_addr
.sin6
.sin6_len 
= sizeof(struct sockaddr_in6
); 
6363                         if (local_port 
!= 0) { 
6364                                 info
->local_addr
.sin6
.sin6_port 
= local_port
; 
6367                 if (remote_addr 
&& remote_addr
->sa
.sa_len 
> 0) { 
6368                         memcpy(&info
->remote_addr
, remote_addr
, remote_addr
->sa
.sa_len
); 
6369                         if (remote_port 
!= 0) { 
6370                                 info
->remote_addr
.sin6
.sin6_port 
= remote_port
; 
6372                 } else if (remote_port 
!= 0) { 
6373                         info
->remote_addr
.sin6
.sin6_len 
= sizeof(struct sockaddr_in6
); 
6374                         info
->remote_addr
.sin6
.sin6_family 
= AF_INET6
; 
6375                         info
->remote_addr
.sin6
.sin6_port 
= remote_port
; 
6381 necp_send_application_interface_denied_event(pid_t pid
, uuid_t proc_uuid
, u_int32_t if_functional_type
) 
6383         struct kev_netpolicy_ifdenied ev_ifdenied
; 
6385         bzero(&ev_ifdenied
, sizeof(ev_ifdenied
)); 
6387         ev_ifdenied
.ev_data
.epid 
= pid
; 
6388         uuid_copy(ev_ifdenied
.ev_data
.euuid
, proc_uuid
); 
6389         ev_ifdenied
.ev_if_functional_type 
= if_functional_type
; 
6391         netpolicy_post_msg(KEV_NETPOLICY_IFDENIED
, &ev_ifdenied
.ev_data
, sizeof(ev_ifdenied
)); 
6395 necp_send_network_denied_event(pid_t pid
, uuid_t proc_uuid
, u_int32_t network_type
) 
6397         struct kev_netpolicy_netdenied ev_netdenied 
= {}; 
6399         bzero(&ev_netdenied
, sizeof(ev_netdenied
)); 
6401         ev_netdenied
.ev_data
.epid 
= pid
; 
6402         uuid_copy(ev_netdenied
.ev_data
.euuid
, proc_uuid
); 
6403         ev_netdenied
.ev_network_type 
= network_type
; 
6405         netpolicy_post_msg(KEV_NETPOLICY_NETDENIED
, &ev_netdenied
.ev_data
, sizeof(ev_netdenied
)); 
6408 extern char *proc_name_address(void *p
); 
6410 #define NECP_VERIFY_DELEGATION_ENTITLEMENT(_p, _d) \ 
6411         if (!has_checked_delegation_entitlement) { \ 
6412                 has_delegation_entitlement = (priv_check_cred(proc_ucred(_p), PRIV_NET_PRIVILEGED_SOCKET_DELEGATE, 0) == 0); \ 
6413                 has_checked_delegation_entitlement = TRUE; \ 
6415         if (!has_delegation_entitlement) { \ 
6416                 NECPLOG(LOG_ERR, "%s(%d) does not hold the necessary entitlement to delegate network traffic for other processes by %s", \ 
6417                                                   proc_name_address(_p), proc_pid(_p), _d); \ 
6422 necp_application_find_policy_match_internal(proc_t proc
, 
6423     u_int8_t 
*parameters
, 
6424     u_int32_t parameters_size
, 
6425     struct necp_aggregate_result 
*returned_result
, 
6428     u_int required_interface_index
, 
6429     const union necp_sockaddr_union 
*override_local_addr
, 
6430     const union necp_sockaddr_union 
*override_remote_addr
, 
6431     struct necp_client_endpoint 
*returned_v4_gateway
, 
6432     struct necp_client_endpoint 
*returned_v6_gateway
, 
6433     struct rtentry 
**returned_route
, bool ignore_address
, 
6435     uuid_t 
*returned_override_euuid
) 
6440         struct necp_kernel_socket_policy 
*matched_policy 
= NULL
; 
6441         struct necp_socket_info info
; 
6442         necp_kernel_policy_filter filter_control_unit 
= 0; 
6443         necp_kernel_policy_result service_action 
= 0; 
6444         necp_kernel_policy_service service 
= { 0, 0 }; 
6446         u_int16_t protocol 
= 0; 
6447         u_int32_t bound_interface_index 
= required_interface_index
; 
6448         u_int32_t traffic_class 
= 0; 
6449         u_int32_t client_flags 
= 0; 
6450         union necp_sockaddr_union local_addr
; 
6451         union necp_sockaddr_union remote_addr
; 
6452         bool no_remote_addr 
= FALSE
; 
6453         u_int8_t remote_family 
= 0; 
6454         bool no_local_addr 
= FALSE
; 
6455         u_int16_t local_port 
= 0; 
6456         u_int16_t remote_port 
= 0; 
6457         necp_drop_all_bypass_check_result_t drop_all_bypass 
= NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
; 
6458         bool is_delegated 
= false; 
6460         if (override_local_addr
) { 
6461                 memcpy(&local_addr
, override_local_addr
, sizeof(local_addr
)); 
6463                 memset(&local_addr
, 0, sizeof(local_addr
)); 
6465         if (override_remote_addr
) { 
6466                 memcpy(&remote_addr
, override_remote_addr
, sizeof(remote_addr
)); 
6468                 memset(&remote_addr
, 0, sizeof(remote_addr
)); 
6471         // Initialize UID, PID, and UUIDs to the current process 
6472         uid_t uid 
= kauth_cred_getuid(proc_ucred(proc
)); 
6473         pid_t pid 
= proc_pid(proc
); 
6474         int32_t pid_version 
= proc_pidversion(proc
); 
6475         uuid_t application_uuid
; 
6476         uuid_clear(application_uuid
); 
6477         uuid_t real_application_uuid
; 
6478         uuid_clear(real_application_uuid
); 
6479         proc_getexecutableuuid(proc
, real_application_uuid
, sizeof(real_application_uuid
)); 
6480         uuid_copy(application_uuid
, real_application_uuid
); 
6481         uuid_t responsible_application_uuid
; 
6482         uuid_clear(responsible_application_uuid
); 
6484         char *domain 
= NULL
; 
6485         char *account 
= NULL
; 
6487 #define NECP_MAX_REQUIRED_AGENTS 16 
6488         u_int32_t num_required_agent_types 
= 0; 
6489         struct necp_client_parameter_netagent_type required_agent_types
[NECP_MAX_REQUIRED_AGENTS
]; 
6490         memset(&required_agent_types
, 0, sizeof(required_agent_types
)); 
6492         u_int32_t netagent_ids
[NECP_MAX_NETAGENTS
]; 
6493         u_int32_t netagent_use_flags
[NECP_MAX_NETAGENTS
]; 
6494         memset(&netagent_ids
, 0, sizeof(netagent_ids
)); 
6495         memset(&netagent_use_flags
, 0, sizeof(netagent_use_flags
)); 
6496         int netagent_cursor
; 
6498         bool has_checked_delegation_entitlement 
= FALSE
; 
6499         bool has_delegation_entitlement 
= FALSE
; 
6501         proc_t responsible_proc 
= PROC_NULL
; 
6502         proc_t effective_proc 
= proc
; 
6503         bool release_eproc 
= false; 
6504         necp_socket_bypass_type_t bypass_type 
= NECP_BYPASS_TYPE_NONE
; 
6506         u_int32_t flow_divert_aggregate_unit 
= 0; 
6508         if (returned_result 
== NULL
) { 
6512         if (returned_v4_gateway 
!= NULL
) { 
6513                 memset(returned_v4_gateway
, 0, sizeof(struct necp_client_endpoint
)); 
6516         if (returned_v6_gateway 
!= NULL
) { 
6517                 memset(returned_v6_gateway
, 0, sizeof(struct necp_client_endpoint
)); 
6520         if (returned_override_euuid 
!= NULL
) { 
6521                 uuid_clear(*returned_override_euuid
); 
6524         memset(returned_result
, 0, sizeof(struct necp_aggregate_result
)); 
6526         u_int32_t drop_order 
= necp_process_drop_order(proc_ucred(proc
)); 
6528         necp_kernel_policy_result drop_dest_policy_result 
= NECP_KERNEL_POLICY_RESULT_NONE
; 
6530         lck_rw_lock_shared(&necp_kernel_policy_lock
); 
6531         if (necp_kernel_application_policies_count 
== 0) { 
6532                 if (necp_drop_all_order 
> 0 || drop_order 
> 0) { 
6533                         returned_result
->routing_result 
= NECP_KERNEL_POLICY_RESULT_DROP
; 
6534                         lck_rw_done(&necp_kernel_policy_lock
); 
6538         lck_rw_done(&necp_kernel_policy_lock
); 
6540         while ((offset 
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)) <= parameters_size
) { 
6541                 u_int8_t type 
= necp_buffer_get_tlv_type(parameters
, offset
); 
6542                 u_int32_t length 
= necp_buffer_get_tlv_length(parameters
, offset
); 
6544                 if (length 
> (parameters_size 
- (offset 
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)))) { 
6545                         // If the length is larger than what can fit in the remaining parameters size, bail 
6546                         NECPLOG(LOG_ERR
, "Invalid TLV length (%u)", length
); 
6551                         u_int8_t 
*value 
= necp_buffer_get_tlv_value(parameters
, offset
, NULL
); 
6552                         if (value 
!= NULL
) { 
6554                                 case NECP_CLIENT_PARAMETER_APPLICATION
: { 
6555                                         if (length 
>= sizeof(uuid_t
)) { 
6556                                                 if (uuid_compare(application_uuid
, value
) == 0) { 
6561                                                 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc
, "euuid"); 
6563                                                 is_delegated 
= true; 
6564                                                 uuid_copy(application_uuid
, value
); 
6568                                 case NECP_CLIENT_PARAMETER_REAL_APPLICATION
: { 
6569                                         if (length 
>= sizeof(uuid_t
)) { 
6570                                                 if (uuid_compare(real_application_uuid
, value
) == 0) { 
6575                                                 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc
, "uuid"); 
6577                                                 is_delegated 
= true; 
6578                                                 uuid_copy(real_application_uuid
, value
); 
6582                                 case NECP_CLIENT_PARAMETER_PID
: { 
6583                                         if (length 
>= sizeof(pid_t
)) { 
6584                                                 if (memcmp(&pid
, value
, sizeof(pid_t
)) == 0) { 
6589                                                 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc
, "pid"); 
6591                                                 is_delegated 
= true; 
6592                                                 memcpy(&pid
, value
, sizeof(pid_t
)); 
6596                                 case NECP_CLIENT_PARAMETER_UID
: { 
6597                                         if (length 
>= sizeof(uid_t
)) { 
6598                                                 if (memcmp(&uid
, value
, sizeof(uid_t
)) == 0) { 
6603                                                 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc
, "uid"); 
6605                                                 is_delegated 
= true; 
6606                                                 memcpy(&uid
, value
, sizeof(uid_t
)); 
6610                                 case NECP_CLIENT_PARAMETER_DOMAIN
: { 
6611                                         domain 
= (char *)value
; 
6612                                         domain
[length 
- 1] = 0; 
6615                                 case NECP_CLIENT_PARAMETER_ACCOUNT
: { 
6616                                         account 
= (char *)value
; 
6617                                         account
[length 
- 1] = 0; 
6620                                 case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS
: { 
6621                                         if (length 
>= sizeof(u_int32_t
)) { 
6622                                                 memcpy(&traffic_class
, value
, sizeof(u_int32_t
)); 
6626                                 case NECP_CLIENT_PARAMETER_IP_PROTOCOL
: { 
6627                                         if (length 
>= sizeof(u_int16_t
)) { 
6628                                                 memcpy(&protocol
, value
, sizeof(u_int16_t
)); 
6629                                         } else if (length 
>= sizeof(u_int8_t
)) { 
6630                                                 memcpy(&protocol
, value
, sizeof(u_int8_t
)); 
6634                                 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE
: { 
6635                                         if (length 
<= IFXNAMSIZ 
&& length 
> 0) { 
6636                                                 ifnet_t bound_interface 
= NULL
; 
6637                                                 char interface_name
[IFXNAMSIZ
]; 
6638                                                 memcpy(interface_name
, value
, length
); 
6639                                                 interface_name
[length 
- 1] = 0;         // Make sure the string is NULL terminated 
6640                                                 if (ifnet_find_by_name(interface_name
, &bound_interface
) == 0) { 
6641                                                         bound_interface_index 
= bound_interface
->if_index
; 
6642                                                         ifnet_release(bound_interface
); 
6647                                 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS
: { 
6648                                         if (ignore_address 
|| override_local_addr
) { 
6652                                         if (length 
>= sizeof(struct necp_policy_condition_addr
)) { 
6653                                                 struct necp_policy_condition_addr 
*address_struct 
= (struct necp_policy_condition_addr 
*)(void *)value
; 
6654                                                 if (necp_address_is_valid(&address_struct
->address
.sa
)) { 
6655                                                         memcpy(&local_addr
, &address_struct
->address
, sizeof(address_struct
->address
)); 
6660                                 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS
: { 
6661                                         if (ignore_address 
|| override_remote_addr
) { 
6665                                         if (length 
>= sizeof(struct necp_policy_condition_addr
)) { 
6666                                                 struct necp_policy_condition_addr 
*address_struct 
= (struct necp_policy_condition_addr 
*)(void *)value
; 
6667                                                 if (necp_address_is_valid(&address_struct
->address
.sa
)) { 
6668                                                         memcpy(&remote_addr
, &address_struct
->address
, sizeof(address_struct
->address
)); 
6673                                 case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT
: { 
6674                                         if (ignore_address 
|| override_local_addr
) { 
6678                                         if (length 
>= sizeof(struct necp_client_endpoint
)) { 
6679                                                 struct necp_client_endpoint 
*endpoint 
= (struct necp_client_endpoint 
*)(void *)value
; 
6680                                                 if (endpoint
->u
.endpoint
.endpoint_family 
== AF_UNSPEC 
&& 
6681                                                     endpoint
->u
.endpoint
.endpoint_port 
!= 0) { 
6683                                                         local_port 
= endpoint
->u
.endpoint
.endpoint_port
; 
6688                                 case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT
: { 
6689                                         if (ignore_address 
|| override_remote_addr
) { 
6693                                         if (length 
>= sizeof(struct necp_client_endpoint
)) { 
6694                                                 struct necp_client_endpoint 
*endpoint 
= (struct necp_client_endpoint 
*)(void *)value
; 
6695                                                 if (endpoint
->u
.endpoint
.endpoint_family 
== AF_UNSPEC 
&& 
6696                                                     endpoint
->u
.endpoint
.endpoint_port 
!= 0) { 
6698                                                         remote_port 
= endpoint
->u
.endpoint
.endpoint_port
; 
6703                                 case NECP_CLIENT_PARAMETER_FLAGS
: { 
6704                                         if (length 
>= sizeof(client_flags
)) { 
6705                                                 memcpy(&client_flags
, value
, sizeof(client_flags
)); 
6709                                 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE
: 
6710                                 case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE
: { 
6711                                         if (num_required_agent_types 
>= NECP_MAX_REQUIRED_AGENTS
) { 
6714                                         if (length 
>= sizeof(struct necp_client_parameter_netagent_type
)) { 
6715                                                 memcpy(&required_agent_types
[num_required_agent_types
], value
, sizeof(struct necp_client_parameter_netagent_type
)); 
6716                                                 num_required_agent_types
++; 
6727                 offset 
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
; 
6730         // Check for loopback exception 
6731         if (necp_pass_loopback 
> 0 && necp_is_loopback(&local_addr
.sa
, &remote_addr
.sa
, NULL
, NULL
, bound_interface_index
)) { 
6732                 bypass_type 
= NECP_BYPASS_TYPE_LOOPBACK
; 
6735         if (bypass_type 
== NECP_BYPASS_TYPE_LOOPBACK 
&& necp_pass_loopback 
== NECP_LOOPBACK_PASS_ALL
) { 
6736                 returned_result
->policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
6737                 returned_result
->routing_result 
= NECP_KERNEL_POLICY_RESULT_PASS
; 
6738                 returned_result
->routed_interface_index 
= lo_ifp
->if_index
; 
6739                 *flags 
|= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL 
| NECP_CLIENT_RESULT_FLAG_IS_DIRECT
); 
6743         if (proc_pid(effective_proc
) != pid
) { 
6744                 proc_t found_proc 
= proc_find(pid
); 
6745                 if (found_proc 
!= PROC_NULL
) { 
6746                         effective_proc 
= found_proc
; 
6747                         pid_version 
= proc_pidversion(effective_proc
); 
6748                         release_eproc 
= true; 
6751 #if defined(XNU_TARGET_OS_OSX) 
6752         if (effective_proc
->p_responsible_pid 
> 0 && effective_proc
->p_responsible_pid 
!= pid
) { 
6753                 responsible_proc 
= proc_find(effective_proc
->p_responsible_pid
); 
6754                 if (responsible_proc 
!= PROC_NULL
) { 
6755                         proc_getexecutableuuid(responsible_proc
, responsible_application_uuid
, sizeof(responsible_application_uuid
)); 
6758 #endif /* defined(XNU_TARGET_OS_OSX) */ 
6761         lck_rw_lock_shared(&necp_kernel_policy_lock
); 
6763         u_int32_t route_rule_id_array
[MAX_AGGREGATE_ROUTE_RULES
]; 
6764         size_t route_rule_id_array_count 
= 0; 
6765         necp_application_fillout_info_locked(application_uuid
, real_application_uuid
, responsible_application_uuid
, account
, domain
, pid
, pid_version
, uid
, protocol
, bound_interface_index
, traffic_class
, &local_addr
, &remote_addr
, local_port
, remote_port
, has_client
, proc
, effective_proc
, responsible_proc
, drop_order
, client_flags
, &info
, (bypass_type 
== NECP_BYPASS_TYPE_LOOPBACK
), is_delegated
); 
6766         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
); 
6768         // Check for loopback exception again after the policy match 
6769         if (bypass_type 
== NECP_BYPASS_TYPE_LOOPBACK 
&& 
6770             necp_pass_loopback 
== NECP_LOOPBACK_PASS_WITH_FILTER 
&& 
6771             (matched_policy 
== NULL 
|| matched_policy
->result 
!= NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
)) { 
6772                 if (filter_control_unit 
== NECP_FILTER_UNIT_NO_FILTER
) { 
6773                         returned_result
->filter_control_unit 
= 0; 
6775                         returned_result
->filter_control_unit 
= filter_control_unit
; 
6778                 if (flow_divert_aggregate_unit 
> 0) { 
6779                         returned_result
->flow_divert_aggregate_unit 
= flow_divert_aggregate_unit
; 
6782                 returned_result
->policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
6783                 returned_result
->routing_result 
= NECP_KERNEL_POLICY_RESULT_PASS
; 
6784                 returned_result
->routed_interface_index 
= lo_ifp
->if_index
; 
6785                 *flags 
|= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL 
| NECP_CLIENT_RESULT_FLAG_IS_DIRECT
); 
6790         if (matched_policy
) { 
6791                 returned_result
->policy_id 
= matched_policy
->id
; 
6792                 returned_result
->routing_result 
= matched_policy
->result
; 
6793                 memcpy(&returned_result
->routing_result_parameter
, &matched_policy
->result_parameter
, sizeof(returned_result
->routing_result_parameter
)); 
6794                 if (returned_override_euuid 
!= NULL 
&& info
.used_responsible_pid 
&& !(matched_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REAL_APP_ID
)) { 
6795                         uuid_copy(*returned_override_euuid
, responsible_application_uuid
); 
6798                 bool drop_all 
= false; 
6799                 if (necp_drop_all_order 
> 0 || info
.drop_order 
> 0 || drop_dest_policy_result 
== NECP_KERNEL_POLICY_RESULT_DROP
) { 
6800                         // Mark socket as a drop if drop_all is set 
6802                         if (drop_all_bypass 
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
) { 
6803                                 drop_all_bypass 
= necp_check_drop_all_bypass_result(proc
); 
6806                 if (drop_all 
&& drop_all_bypass 
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
) { 
6807                         returned_result
->policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
6808                         returned_result
->routing_result 
= NECP_KERNEL_POLICY_RESULT_DROP
; 
6810                         returned_result
->policy_id 
= 0; 
6811                         returned_result
->routing_result 
= NECP_KERNEL_POLICY_RESULT_NONE
; 
6814         if (necp_check_missing_client_drop(proc
, &info
) || 
6815             necp_check_restricted_multicast_drop(proc
, &info
, false)) { 
6817                 returned_result
->policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
6818                 returned_result
->routing_result 
= NECP_KERNEL_POLICY_RESULT_DROP
; 
6820         if (filter_control_unit 
== NECP_FILTER_UNIT_NO_FILTER
) { 
6821                 returned_result
->filter_control_unit 
= 0; 
6823                 returned_result
->filter_control_unit 
= filter_control_unit
; 
6826         if (flow_divert_aggregate_unit 
> 0) { 
6827                 returned_result
->flow_divert_aggregate_unit 
= flow_divert_aggregate_unit
; 
6830         returned_result
->service_action 
= service_action
; 
6832         // Handle trigger service 
6833         if (service
.identifier 
!= 0) { 
6834                 struct necp_uuid_id_mapping 
*mapping 
= necp_uuid_lookup_uuid_with_service_id_locked(service
.identifier
); 
6835                 if (mapping 
!= NULL
) { 
6836                         struct necp_service_registration 
*service_registration 
= NULL
; 
6837                         uuid_copy(returned_result
->service_uuid
, mapping
->uuid
); 
6838                         returned_result
->service_data 
= service
.data
; 
6839                         if (service
.identifier 
== NECP_NULL_SERVICE_ID
) { 
6840                                 // NULL service is always 'registered' 
6841                                 returned_result
->service_flags 
|= NECP_SERVICE_FLAGS_REGISTERED
; 
6843                                 LIST_FOREACH(service_registration
, &necp_registered_service_list
, kernel_chain
) { 
6844                                         if (service
.identifier 
== service_registration
->service_id
) { 
6845                                                 returned_result
->service_flags 
|= NECP_SERVICE_FLAGS_REGISTERED
; 
6854         for (netagent_cursor 
= 0; netagent_cursor 
< NECP_MAX_NETAGENTS
; netagent_cursor
++) { 
6855                 struct necp_uuid_id_mapping 
*mapping 
= NULL
; 
6856                 u_int32_t netagent_id 
= netagent_ids
[netagent_cursor
]; 
6857                 if (netagent_id 
== 0) { 
6860                 mapping 
= necp_uuid_lookup_uuid_with_service_id_locked(netagent_id
); 
6861                 if (mapping 
!= NULL
) { 
6862                         uuid_copy(returned_result
->netagents
[netagent_cursor
], mapping
->uuid
); 
6863                         returned_result
->netagent_use_flags
[netagent_cursor
] = netagent_use_flags
[netagent_cursor
]; 
6867         // Do routing evaluation 
6868         u_int output_bound_interface 
= bound_interface_index
; 
6869         if (returned_result
->routing_result 
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
) { 
6870                 output_bound_interface 
= returned_result
->routing_result_parameter
.scoped_interface_index
; 
6871         } else if (returned_result
->routing_result 
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
) { 
6872                 output_bound_interface 
= returned_result
->routing_result_parameter
.tunnel_interface_index
; 
6873         } else if (returned_result
->routing_result 
== NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT
) { 
6874                 output_bound_interface 
= necp_get_primary_direct_interface_index(); 
6875                 if (output_bound_interface 
== IFSCOPE_NONE
) { 
6876                         returned_result
->routing_result 
= NECP_KERNEL_POLICY_RESULT_DROP
; 
6878                         returned_result
->routing_result 
= NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
; 
6879                         returned_result
->routing_result_parameter
.scoped_interface_index 
= output_bound_interface
; 
6883         if (returned_result
->routing_result 
== NECP_KERNEL_POLICY_RESULT_DROP 
&& 
6884             returned_result
->routing_result_parameter
.drop_flags 
& NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK
) { 
6885                 // Trigger the event that we dropped due to a local network policy 
6886                 necp_send_network_denied_event(pid
, application_uuid
, NETPOLICY_NETWORKTYPE_LOCAL
); 
6887                 if (reason 
!= NULL
) { 
6888                         *reason 
= NECP_CLIENT_RESULT_REASON_LOCAL_NETWORK_PROHIBITED
; 
6892         if (local_addr
.sa
.sa_len 
== 0 || 
6893             (local_addr
.sa
.sa_family 
== AF_INET 
&& local_addr
.sin
.sin_addr
.s_addr 
== 0) || 
6894             (local_addr
.sa
.sa_family 
== AF_INET6 
&& IN6_IS_ADDR_UNSPECIFIED(&local_addr
.sin6
.sin6_addr
))) { 
6895                 no_local_addr 
= TRUE
; 
6898         if (remote_addr
.sa
.sa_len 
== 0 || 
6899             (remote_addr
.sa
.sa_family 
== AF_INET 
&& remote_addr
.sin
.sin_addr
.s_addr 
== 0) || 
6900             (remote_addr
.sa
.sa_family 
== AF_INET6 
&& IN6_IS_ADDR_UNSPECIFIED(&remote_addr
.sin6
.sin6_addr
))) { 
6901                 no_remote_addr 
= TRUE
; 
6902                 remote_family 
= remote_addr
.sa
.sa_family
; 
6905         returned_result
->routed_interface_index 
= 0; 
6906         struct rtentry 
*rt 
= NULL
; 
6907         if (!no_local_addr 
&& (client_flags 
& NECP_CLIENT_PARAMETER_FLAG_LISTENER
) != 0) { 
6908                 // Treat the output bound interface as the routed interface for local address 
6909                 // validation later. 
6910                 returned_result
->routed_interface_index 
= output_bound_interface
; 
6912                 if (no_remote_addr
) { 
6913                         memset(&remote_addr
, 0, sizeof(remote_addr
)); 
6914                         if (remote_family 
== AF_INET6
) { 
6915                                 // Reset address to :: 
6916                                 remote_addr
.sa
.sa_family 
= AF_INET6
; 
6917                                 remote_addr
.sa
.sa_len 
= sizeof(struct sockaddr_in6
); 
6919                                 // Reset address to 0.0.0.0 
6920                                 remote_addr
.sa
.sa_family 
= AF_INET
; 
6921                                 remote_addr
.sa
.sa_len 
= sizeof(struct sockaddr_in
); 
6925                 rt 
= rtalloc1_scoped((struct sockaddr 
*)&remote_addr
, 0, 0, 
6926                     output_bound_interface
); 
6928                 if (remote_addr
.sa
.sa_family 
== AF_INET 
&& rt 
!= NULL 
&& 
6929                     IS_INTF_CLAT46(rt
->rt_ifp
)) { 
6932                         returned_result
->routed_interface_index 
= 0; 
6935                 if (no_remote_addr 
&& remote_family 
== AF_UNSPEC 
&& 
6936                     (rt 
== NULL 
|| rt
->rt_ifp 
== NULL
)) { 
6937                         // Route lookup for default IPv4 failed, try IPv6 
6939                         // Cleanup old route if necessary 
6945                         // Reset address to :: 
6946                         memset(&remote_addr
, 0, sizeof(remote_addr
)); 
6947                         remote_addr
.sa
.sa_family 
= AF_INET6
; 
6948                         remote_addr
.sa
.sa_len 
= sizeof(struct sockaddr_in6
); 
6951                         rt 
= rtalloc1_scoped((struct sockaddr 
*)&remote_addr
, 0, 0, 
6952                             output_bound_interface
); 
6956                     rt
->rt_ifp 
!= NULL
) { 
6957                         returned_result
->routed_interface_index 
= rt
->rt_ifp
->if_index
; 
6959                          * For local addresses, we allow the interface scope to be 
6960                          * either the loopback interface or the interface hosting the 
6963                         if (bound_interface_index 
!= IFSCOPE_NONE 
&& 
6964                             rt
->rt_ifa 
!= NULL 
&& rt
->rt_ifa
->ifa_ifp 
&& 
6965                             (output_bound_interface 
== lo_ifp
->if_index 
|| 
6966                             rt
->rt_ifp
->if_index 
== lo_ifp
->if_index 
|| 
6967                             rt
->rt_ifa
->ifa_ifp
->if_index 
== bound_interface_index
)) { 
6968                                 struct sockaddr_storage dst
; 
6969                                 unsigned int ifscope 
= bound_interface_index
; 
6972                                  * Transform dst into the internal routing table form 
6974                                 (void) sa_copy((struct sockaddr 
*)&remote_addr
, 
6977                                 if ((rt
->rt_ifp
->if_index 
== lo_ifp
->if_index
) || 
6978                                     rt_ifa_is_dst((struct sockaddr 
*)&dst
, rt
->rt_ifa
)) { 
6979                                         returned_result
->routed_interface_index 
= 
6980                                             bound_interface_index
; 
6986         if (returned_result
->routed_interface_index 
!= 0 && 
6987             returned_result
->routed_interface_index 
!= lo_ifp
->if_index 
&&     // Loopback can accept any local address 
6989                 // Transform local_addr into the ifaddr form 
6990                 // IPv6 Scope IDs are always embedded in the ifaddr list 
6991                 struct sockaddr_storage local_address_sanitized
; 
6992                 u_int ifscope 
= IFSCOPE_NONE
; 
6993                 (void)sa_copy(&local_addr
.sa
, &local_address_sanitized
, &ifscope
); 
6994                 SIN(&local_address_sanitized
)->sin_port 
= 0; 
6995                 if (local_address_sanitized
.ss_family 
== AF_INET6
) { 
6996                         SIN6(&local_address_sanitized
)->sin6_scope_id 
= 0; 
6999                 // Validate local address on routed interface 
7000                 struct ifaddr 
*ifa 
= ifa_ifwithaddr_scoped((struct sockaddr 
*)&local_address_sanitized
, returned_result
->routed_interface_index
); 
7002                         // Interface address not found, reject route 
7003                         returned_result
->routed_interface_index 
= 0; 
7009                         ifaddr_release(ifa
); 
7014         if (flags 
!= NULL
) { 
7015                 if ((client_flags 
& NECP_CLIENT_PARAMETER_FLAG_LISTENER
) == 0) { 
7016                         // Check for local/direct 
7017                         bool is_local 
= FALSE
; 
7018                         if (rt 
!= NULL 
&& (rt
->rt_flags 
& RTF_LOCAL
)) { 
7020                         } else if (returned_result
->routed_interface_index 
!= 0 && 
7022                                 // Clean up the address before comparison with interface addresses 
7024                                 // Transform remote_addr into the ifaddr form 
7025                                 // IPv6 Scope IDs are always embedded in the ifaddr list 
7026                                 struct sockaddr_storage remote_address_sanitized
; 
7027                                 u_int ifscope 
= IFSCOPE_NONE
; 
7028                                 (void)sa_copy(&remote_addr
.sa
, &remote_address_sanitized
, &ifscope
); 
7029                                 SIN(&remote_address_sanitized
)->sin_port 
= 0; 
7030                                 if (remote_address_sanitized
.ss_family 
== AF_INET6
) { 
7031                                         SIN6(&remote_address_sanitized
)->sin6_scope_id 
= 0; 
7034                                 // Check if remote address is an interface address 
7035                                 struct ifaddr 
*ifa 
= ifa_ifwithaddr((struct sockaddr 
*)&remote_address_sanitized
); 
7036                                 if (ifa 
!= NULL 
&& ifa
->ifa_ifp 
!= NULL
) { 
7037                                         u_int if_index_for_remote_addr 
= ifa
->ifa_ifp
->if_index
; 
7038                                         if (if_index_for_remote_addr 
== returned_result
->routed_interface_index 
|| 
7039                                             if_index_for_remote_addr 
== lo_ifp
->if_index
) { 
7044                                         ifaddr_release(ifa
); 
7050                                 *flags 
|= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL 
| NECP_CLIENT_RESULT_FLAG_IS_DIRECT
); 
7053                                     !(rt
->rt_flags 
& RTF_GATEWAY
) && 
7054                                     (rt
->rt_ifa 
&& rt
->rt_ifa
->ifa_ifp 
&& !(rt
->rt_ifa
->ifa_ifp
->if_flags 
& IFF_POINTOPOINT
))) { 
7055                                         // Route is directly accessible 
7056                                         *flags 
|= NECP_CLIENT_RESULT_FLAG_IS_DIRECT
; 
7061                             rt
->rt_ifp 
!= NULL
) { 
7062                                 // Check probe status 
7063                                 if (rt
->rt_ifp
->if_eflags 
& IFEF_PROBE_CONNECTIVITY
) { 
7064                                         *flags 
|= NECP_CLIENT_RESULT_FLAG_PROBE_CONNECTIVITY
; 
7067                                 if (rt
->rt_ifp
->if_type 
== IFT_CELLULAR
) { 
7068                                         struct if_cellular_status_v1 
*ifsr
; 
7070                                         ifnet_lock_shared(rt
->rt_ifp
); 
7071                                         lck_rw_lock_exclusive(&rt
->rt_ifp
->if_link_status_lock
); 
7073                                         if (rt
->rt_ifp
->if_link_status 
!= NULL
) { 
7074                                                 ifsr 
= &rt
->rt_ifp
->if_link_status
->ifsr_u
.ifsr_cell
.if_cell_u
.if_status_v1
; 
7076                                                 if (ifsr
->valid_bitmask 
& IF_CELL_UL_MSS_RECOMMENDED_VALID
) { 
7077                                                         if (ifsr
->mss_recommended 
== IF_CELL_UL_MSS_RECOMMENDED_NONE
) { 
7078                                                                 returned_result
->mss_recommended 
= NECP_CLIENT_RESULT_RECOMMENDED_MSS_NONE
; 
7079                                                         } else if (ifsr
->mss_recommended 
== IF_CELL_UL_MSS_RECOMMENDED_MEDIUM
) { 
7080                                                                 returned_result
->mss_recommended 
= NECP_CLIENT_RESULT_RECOMMENDED_MSS_MEDIUM
; 
7081                                                         } else if (ifsr
->mss_recommended 
== IF_CELL_UL_MSS_RECOMMENDED_LOW
) { 
7082                                                                 returned_result
->mss_recommended 
= NECP_CLIENT_RESULT_RECOMMENDED_MSS_LOW
; 
7086                                         lck_rw_done(&rt
->rt_ifp
->if_link_status_lock
); 
7087                                         ifnet_lock_done(rt
->rt_ifp
); 
7090                                 // Check link quality 
7091                                 if ((client_flags 
& NECP_CLIENT_PARAMETER_FLAG_DISCRETIONARY
) && 
7092                                     (rt
->rt_ifp
->if_interface_state
.valid_bitmask 
& IF_INTERFACE_STATE_LQM_STATE_VALID
) && 
7093                                     rt
->rt_ifp
->if_interface_state
.lqm_state 
== IFNET_LQM_THRESH_ABORT
) { 
7094                                         *flags 
|= NECP_CLIENT_RESULT_FLAG_LINK_QUALITY_ABORT
; 
7097                                 // Check QoS marking (fastlane) 
7098                                 for (size_t route_rule_index 
= 0; route_rule_index 
< route_rule_id_array_count
; route_rule_index
++) { 
7099                                         if (necp_update_qos_marking(rt
->rt_ifp
, route_rule_id_array
[route_rule_index
])) { 
7100                                                 *flags 
|= NECP_CLIENT_RESULT_FLAG_ALLOW_QOS_MARKING
; 
7101                                                 // If the route can use QoS markings, stop iterating route rules 
7106                                 if (IFNET_IS_LOW_POWER(rt
->rt_ifp
)) { 
7107                                         *flags 
|= NECP_CLIENT_RESULT_FLAG_INTERFACE_LOW_POWER
; 
7110                                 if (traffic_class 
== SO_TC_BK_SYS
) { 
7111                                         // Block BK_SYS traffic if interface is throttled 
7112                                         u_int32_t throttle_level 
= 0; 
7113                                         if (ifnet_get_throttle(rt
->rt_ifp
, &throttle_level
) == 0) { 
7114                                                 if (throttle_level 
== IFNET_THROTTLE_OPPORTUNISTIC
) { 
7115                                                         returned_result
->routing_result 
= NECP_KERNEL_POLICY_RESULT_DROP
; 
7116                                                         memset(&returned_result
->routing_result_parameter
, 0, sizeof(returned_result
->routing_result_parameter
)); 
7123                 if (returned_result
->routed_interface_index 
!= 0) { 
7124                         union necp_sockaddr_union default_address
; 
7125                         struct rtentry 
*v4Route 
= NULL
; 
7126                         struct rtentry 
*v6Route 
= NULL
; 
7128                         memset(&default_address
, 0, sizeof(default_address
)); 
7130                         // Reset address to 0.0.0.0 
7131                         default_address
.sa
.sa_family 
= AF_INET
; 
7132                         default_address
.sa
.sa_len 
= sizeof(struct sockaddr_in
); 
7133                         v4Route 
= rtalloc1_scoped((struct sockaddr 
*)&default_address
, 0, 0, 
7134                             returned_result
->routed_interface_index
); 
7136                         // Reset address to :: 
7137                         default_address
.sa
.sa_family 
= AF_INET6
; 
7138                         default_address
.sa
.sa_len 
= sizeof(struct sockaddr_in6
); 
7139                         v6Route 
= rtalloc1_scoped((struct sockaddr 
*)&default_address
, 0, 0, 
7140                             returned_result
->routed_interface_index
); 
7142                         if (v4Route 
!= NULL
) { 
7143                                 if (v4Route
->rt_ifp 
!= NULL 
&& !IS_INTF_CLAT46(v4Route
->rt_ifp
)) { 
7144                                         *flags 
|= NECP_CLIENT_RESULT_FLAG_HAS_IPV4
; 
7146                                 if (returned_v4_gateway 
!= NULL 
&& 
7147                                     v4Route
->rt_gateway 
!= NULL 
&& 
7148                                     v4Route
->rt_gateway
->sa_len 
== sizeof(returned_v4_gateway
->u
.sin
)) { 
7149                                         memcpy(&returned_v4_gateway
->u
.sin
, v4Route
->rt_gateway
, sizeof(returned_v4_gateway
->u
.sin
)); 
7150                                         memset(&returned_v4_gateway
->u
.sin
.sin_zero
, 0, sizeof(returned_v4_gateway
->u
.sin
.sin_zero
)); 
7156                         if (v6Route 
!= NULL
) { 
7157                                 if (v6Route
->rt_ifp 
!= NULL
) { 
7158                                         *flags 
|= NECP_CLIENT_RESULT_FLAG_HAS_IPV6
; 
7160                                         if (ifnet_get_nat64prefix(v6Route
->rt_ifp
, returned_result
->nat64_prefixes
) == 0) { 
7161                                                 *flags 
|= NECP_CLIENT_RESULT_FLAG_HAS_NAT64
; 
7164                                 if (returned_v6_gateway 
!= NULL 
&& 
7165                                     v6Route
->rt_gateway 
!= NULL 
&& 
7166                                     v6Route
->rt_gateway
->sa_len 
== sizeof(returned_v6_gateway
->u
.sin6
)) { 
7167                                         memcpy(&returned_v6_gateway
->u
.sin6
, v6Route
->rt_gateway
, sizeof(returned_v6_gateway
->u
.sin6
)); 
7175         for (size_t route_rule_index 
= 0; route_rule_index 
< route_rule_id_array_count
; route_rule_index
++) { 
7176                 u_int32_t interface_type_denied 
= IFRTYPE_FUNCTIONAL_UNKNOWN
; 
7177                 bool route_is_allowed 
= necp_route_is_allowed(rt
, NULL
, route_rule_id_array
[route_rule_index
], &interface_type_denied
); 
7178                 if (!route_is_allowed
) { 
7179                         // If the route is blocked, treat the lookup as a drop 
7180                         returned_result
->routing_result 
= NECP_KERNEL_POLICY_RESULT_DROP
; 
7181                         memset(&returned_result
->routing_result_parameter
, 0, sizeof(returned_result
->routing_result_parameter
)); 
7183                         if (interface_type_denied 
!= IFRTYPE_FUNCTIONAL_UNKNOWN
) { 
7184                                 if (reason 
!= NULL
) { 
7185                                         if (interface_type_denied 
== IFRTYPE_FUNCTIONAL_CELLULAR
) { 
7186                                                 *reason 
= NECP_CLIENT_RESULT_REASON_CELLULAR_DENIED
; 
7187                                         } else if (interface_type_denied 
== IFRTYPE_FUNCTIONAL_WIFI_INFRA
) { 
7188                                                 *reason 
= NECP_CLIENT_RESULT_REASON_WIFI_DENIED
; 
7191                                 necp_send_application_interface_denied_event(pid
, application_uuid
, interface_type_denied
); 
7193                         // If the route gets denied, stop matching rules 
7197                 // Check if there is a route rule that adds an agent 
7198                 u_int32_t netagent_id 
= necp_route_get_netagent(rt
, route_rule_id_array
[route_rule_index
]); 
7199                 if (netagent_id 
!= 0) { 
7200                         struct necp_uuid_id_mapping 
*mapping 
= necp_uuid_lookup_uuid_with_service_id_locked(netagent_id
); 
7201                         if (mapping 
!= NULL
) { 
7202                                 for (netagent_cursor 
= 0; netagent_cursor 
< NECP_MAX_NETAGENTS
; netagent_cursor
++) { 
7203                                         if (uuid_is_null(returned_result
->netagents
[netagent_cursor
])) { 
7205                                                 uuid_copy(returned_result
->netagents
[netagent_cursor
], mapping
->uuid
); 
7206                                                 returned_result
->netagent_use_flags
[netagent_cursor
] = 0; 
7214         if (rt 
!= NULL 
&& rt
->rt_ifp 
!= NULL
) { 
7215                 const bool expensive_prohibited 
= ((client_flags 
& NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE
) && 
7216                     IFNET_IS_EXPENSIVE(rt
->rt_ifp
)); 
7217                 const bool constrained_prohibited 
= ((client_flags 
& NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED
) && 
7218                     IFNET_IS_CONSTRAINED(rt
->rt_ifp
)); 
7219                 if (reason 
!= NULL
) { 
7220                         if (expensive_prohibited
) { 
7221                                 *reason 
= NECP_CLIENT_RESULT_REASON_EXPENSIVE_PROHIBITED
; 
7222                         } else if (constrained_prohibited
) { 
7223                                 *reason 
= NECP_CLIENT_RESULT_REASON_CONSTRAINED_PROHIBITED
; 
7226                 if (expensive_prohibited 
|| constrained_prohibited
) { 
7227                         // If the client flags prohibited a property of the interface, treat it as a drop 
7228                         returned_result
->routing_result 
= NECP_KERNEL_POLICY_RESULT_DROP
; 
7229                         memset(&returned_result
->routing_result_parameter
, 0, sizeof(returned_result
->routing_result_parameter
)); 
7234                 if (returned_route 
!= NULL
) { 
7235                         *returned_route 
= rt
; 
7244         lck_rw_done(&necp_kernel_policy_lock
); 
7246         if (release_eproc 
&& effective_proc 
!= PROC_NULL
) { 
7247                 proc_rele(effective_proc
); 
7249 #if defined(XNU_TARGET_OS_OSX) 
7250         if (responsible_proc 
!= PROC_NULL
) { 
7251                 proc_rele(responsible_proc
); 
7259 necp_is_route_local(union necp_sockaddr_union 
*remote_addr
) 
7261         bool no_remote_addr 
= FALSE
; 
7262         u_int8_t remote_family 
= 0; 
7263         struct rtentry 
*rt 
= NULL
; 
7264         bool is_local 
= FALSE
; 
7266         if (remote_addr 
== NULL
) { 
7270         if (remote_addr
->sa
.sa_len 
== 0 || 
7271             (remote_addr
->sa
.sa_family 
== AF_INET 
&& remote_addr
->sin
.sin_addr
.s_addr 
== 0) || 
7272             (remote_addr
->sa
.sa_family 
== AF_INET6 
&& IN6_IS_ADDR_UNSPECIFIED(&remote_addr
->sin6
.sin6_addr
))) { 
7273                 no_remote_addr 
= TRUE
; 
7274                 remote_family 
= remote_addr
->sa
.sa_family
; 
7277         if (no_remote_addr
) { 
7278                 memset(remote_addr
, 0, sizeof(union necp_sockaddr_union
)); 
7279                 if (remote_family 
== AF_INET6
) { 
7280                         // Reset address to :: 
7281                         remote_addr
->sa
.sa_family 
= AF_INET6
; 
7282                         remote_addr
->sa
.sa_len 
= sizeof(struct sockaddr_in6
); 
7284                         // Reset address to 0.0.0.0 
7285                         remote_addr
->sa
.sa_family 
= AF_INET
; 
7286                         remote_addr
->sa
.sa_len 
= sizeof(struct sockaddr_in
); 
7290         // Lookup route regardless of the scoped interface to check if 
7291         // remote address is in a local network. 
7292         rt 
= rtalloc1_scoped((struct sockaddr 
*)remote_addr
, 0, 0, 0); 
7297         if (remote_addr
->sa
.sa_family 
== AF_INET 
&& IS_INTF_CLAT46(rt
->rt_ifp
)) { 
7300         is_local 
= IS_NECP_DEST_IN_LOCAL_NETWORKS(rt
); 
7310 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
, int32_t pid_version
, 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
, bool is_loopback
, bool real_is_platform_binary
, bool is_delegated
) 
7312         if (!(kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) { 
7313                 if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) { 
7314                         u_int32_t cond_bound_interface_index 
= kernel_policy
->cond_bound_interface 
? kernel_policy
->cond_bound_interface
->if_index 
: 0; 
7315                         if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) { 
7316                                 if (bound_interface_index 
== cond_bound_interface_index
) { 
7317                                         // No match, matches forbidden interface 
7321                                 if (bound_interface_index 
!= cond_bound_interface_index
) { 
7322                                         // No match, does not match required interface 
7327                         if (bound_interface_index 
!= 0) { 
7328                                 // No match, requires a non-bound packet 
7334         if (kernel_policy
->condition_mask 
== 0) { 
7338         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_APP_ID
) { 
7339                 if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_APP_ID
) { 
7340                         if (app_id 
== kernel_policy
->cond_app_id
) { 
7341                                 // No match, matches forbidden application 
7345                         if (app_id 
!= kernel_policy
->cond_app_id
) { 
7346                                 // No match, does not match required application 
7351                 // Check signing identifier only after APP ID matched 
7352                 if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER 
|| 
7353                     kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
) { 
7354                         u_int8_t matched 
= necp_boolean_state_false
; 
7355                         const char *signing_id 
= cs_identity_get(proc 
? proc 
: current_proc()); 
7357                         if (signing_id 
!= NULL
) { 
7358                                 size_t signing_id_size 
= strlen(signing_id
) + 1; 
7359                                 if (memcmp(signing_id
, kernel_policy
->cond_signing_identifier
, signing_id_size
) == 0) { 
7360                                         matched 
= necp_boolean_state_true
; 
7364                         if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
) { 
7365                                 if (matched 
== necp_boolean_state_true
) { 
7369                                 if (matched 
!= necp_boolean_state_true
) { 
7376         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REAL_APP_ID
) { 
7377                 if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_REAL_APP_ID
) { 
7378                         if (real_app_id 
== kernel_policy
->cond_real_app_id
) { 
7379                                 // No match, matches forbidden application 
7383                         if (real_app_id 
!= kernel_policy
->cond_real_app_id
) { 
7384                                 // No match, does not match required application 
7390         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_HAS_CLIENT
) { 
7396         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_ENTITLEMENT
) { 
7397                 if (cred_result 
!= 0) { 
7398                         // Process is missing entitlement 
7403         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_PLATFORM_BINARY
) { 
7404                 if (is_platform_binary 
== 0) { 
7405                         // Process is not platform binary 
7410         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_SDK_VERSION
) { 
7412                         if (kernel_policy
->cond_sdk_version
.platform 
!= 0) { 
7413                                 if (kernel_policy
->cond_sdk_version
.platform 
!= proc_platform(proc
)) { 
7414                                         // Process does not match platform 
7419                         if (kernel_policy
->cond_sdk_version
.min_version 
!= 0) { 
7420                                 if (kernel_policy
->cond_sdk_version
.min_version 
> proc_min_sdk(proc
)) { 
7421                                         // Process min version is older than required min version 
7426                         if (kernel_policy
->cond_sdk_version
.version 
!= 0) { 
7427                                 if (kernel_policy
->cond_sdk_version
.version 
> proc_sdk(proc
)) { 
7428                                         // Process SDK version is older than required version 
7435         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) { 
7436                 if (kernel_policy
->cond_custom_entitlement_matched 
== necp_boolean_state_false
) { 
7437                         // Process is missing entitlement based on previous check 
7439                 } else if (kernel_policy
->cond_custom_entitlement_matched 
== necp_boolean_state_unknown
) { 
7440                         if (kernel_policy
->cond_custom_entitlement 
!= NULL
) { 
7442                                         // No process found, cannot check entitlement 
7445                                 task_t task 
= proc_task(proc
); 
7447                                     !IOTaskHasEntitlement(task
, kernel_policy
->cond_custom_entitlement
)) { 
7448                                         // Process is missing custom entitlement 
7449                                         kernel_policy
->cond_custom_entitlement_matched 
= necp_boolean_state_false
; 
7452                                         kernel_policy
->cond_custom_entitlement_matched 
= necp_boolean_state_true
; 
7458         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_DOMAIN
) { 
7459                 bool domain_matches 
= necp_hostname_matches_domain(domain
, domain_dot_count
, kernel_policy
->cond_domain
, kernel_policy
->cond_domain_dot_count
); 
7460                 if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_DOMAIN
) { 
7461                         if (domain_matches
) { 
7462                                 // No match, matches forbidden domain 
7466                         if (!domain_matches
) { 
7467                                 // No match, does not match required domain 
7473         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) { 
7474                 if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) { 
7475                         if (account_id 
== kernel_policy
->cond_account_id
) { 
7476                                 // No match, matches forbidden account 
7480                         if (account_id 
!= kernel_policy
->cond_account_id
) { 
7481                                 // No match, does not match required account 
7487         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_PID
) { 
7488                 if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_PID
) { 
7489                         if (pid 
== kernel_policy
->cond_pid
) { 
7490                                 // No match, matches forbidden pid 
7493                         if (kernel_policy
->cond_pid_version 
!= 0 && pid_version 
== kernel_policy
->cond_pid_version
) { 
7497                         if (pid 
!= kernel_policy
->cond_pid
) { 
7498                                 // No match, does not match required pid 
7501                         if (kernel_policy
->cond_pid_version 
!= 0 && pid_version 
!= kernel_policy
->cond_pid_version
) { 
7507         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_UID
) { 
7508                 if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_UID
) { 
7509                         if (uid 
== kernel_policy
->cond_uid
) { 
7510                                 // No match, matches forbidden uid 
7514                         if (uid 
!= kernel_policy
->cond_uid
) { 
7515                                 // No match, does not match required uid 
7521         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) { 
7522                 if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) { 
7523                         if (traffic_class 
>= kernel_policy
->cond_traffic_class
.start_tc 
&& 
7524                             traffic_class 
<= kernel_policy
->cond_traffic_class
.end_tc
) { 
7525                                 // No match, matches forbidden traffic class 
7529                         if (traffic_class 
< kernel_policy
->cond_traffic_class
.start_tc 
|| 
7530                             traffic_class 
> kernel_policy
->cond_traffic_class
.end_tc
) { 
7531                                 // No match, does not match required traffic class 
7537         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_PROTOCOL
) { 
7538                 if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_PROTOCOL
) { 
7539                         if (protocol 
== kernel_policy
->cond_protocol
) { 
7540                                 // No match, matches forbidden protocol 
7544                         if (protocol 
!= kernel_policy
->cond_protocol
) { 
7545                                 // No match, does not match required protocol 
7551         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_AGENT_TYPE
) { 
7552                 bool matches_agent_type 
= FALSE
; 
7553                 for (u_int32_t i 
= 0; i 
< num_required_agent_types
; i
++) { 
7554                         struct necp_client_parameter_netagent_type 
*required_agent_type 
= &required_agent_types
[i
]; 
7555                         if ((strlen(kernel_policy
->cond_agent_type
.agent_domain
) == 0 || 
7556                             strncmp(required_agent_type
->netagent_domain
, kernel_policy
->cond_agent_type
.agent_domain
, NETAGENT_DOMAINSIZE
) == 0) && 
7557                             (strlen(kernel_policy
->cond_agent_type
.agent_type
) == 0 || 
7558                             strncmp(required_agent_type
->netagent_type
, kernel_policy
->cond_agent_type
.agent_type
, NETAGENT_TYPESIZE
) == 0)) { 
7559                                 // Found a required agent that matches 
7560                                 matches_agent_type 
= TRUE
; 
7564                 if (!matches_agent_type
) { 
7569         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) { 
7570                 bool is_local 
= FALSE
; 
7573                         is_local 
= IS_NECP_DEST_IN_LOCAL_NETWORKS(rt
); 
7575                         is_local 
= necp_is_route_local(remote
); 
7579                         // Either no route to validate or no match for local networks 
7584         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_START
) { 
7585                 if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_END
) { 
7586                         bool inRange 
= necp_is_addr_in_range((struct sockaddr 
*)local
, (struct sockaddr 
*)&kernel_policy
->cond_local_start
, (struct sockaddr 
*)&kernel_policy
->cond_local_end
); 
7587                         if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_LOCAL_END
) { 
7596                 } else if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) { 
7597                         bool inSubnet 
= necp_is_addr_in_subnet((struct sockaddr 
*)local
, (struct sockaddr 
*)&kernel_policy
->cond_local_start
, kernel_policy
->cond_local_prefix
); 
7598                         if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) { 
7610         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_START
) { 
7611                 if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_END
) { 
7612                         bool inRange 
= necp_is_addr_in_range((struct sockaddr 
*)remote
, (struct sockaddr 
*)&kernel_policy
->cond_remote_start
, (struct sockaddr 
*)&kernel_policy
->cond_remote_end
); 
7613                         if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_REMOTE_END
) { 
7622                 } else if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) { 
7623                         bool inSubnet 
= necp_is_addr_in_subnet((struct sockaddr 
*)remote
, (struct sockaddr 
*)&kernel_policy
->cond_remote_start
, kernel_policy
->cond_remote_prefix
); 
7624                         if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) { 
7636         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_CLIENT_FLAGS
) { 
7637                 if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_CLIENT_FLAGS
) { 
7638                         if ((client_flags 
& kernel_policy
->cond_client_flags
) == kernel_policy
->cond_client_flags
) { 
7639                                 // Flags do match, and condition is negative, fail. 
7643                         if ((client_flags 
& kernel_policy
->cond_client_flags
) != kernel_policy
->cond_client_flags
) { 
7644                                 // Flags do not match, fail. 
7650         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_EMPTY
) { 
7651                 bool isEmpty 
= necp_addr_is_empty((struct sockaddr 
*)local
); 
7652                 if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_LOCAL_EMPTY
) { 
7663         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_EMPTY
) { 
7664                 bool isEmpty 
= necp_addr_is_empty((struct sockaddr 
*)remote
); 
7665                 if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_REMOTE_EMPTY
) { 
7676         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) { 
7677                 bool tags_matched 
= false; 
7678                 if (kernel_policy
->cond_packet_filter_tags 
& NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP
) { 
7679                         if (pf_tag 
== PF_TAG_ID_STACK_DROP
) { 
7680                                 tags_matched 
= true; 
7684                 if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) { 
7689                         if (!tags_matched
) { 
7695         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_IS_LOOPBACK
) { 
7696                 if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_IS_LOOPBACK
) { 
7707         if (is_delegated 
&& (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY
)) { 
7708                 if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY
) { 
7709                         if (real_is_platform_binary
) { 
7713                         if (!real_is_platform_binary
) { 
7722 static inline u_int32_t
 
7723 necp_socket_calc_flowhash_locked(struct necp_socket_info 
*info
) 
7725         return net_flowhash(info
, sizeof(*info
), necp_kernel_socket_policies_gencount
); 
7729 necp_socket_fillout_info_locked(struct inpcb 
*inp
, struct sockaddr 
*override_local_addr
, struct sockaddr 
*override_remote_addr
, u_int32_t override_bound_interface
, bool override_is_inbound
, u_int32_t drop_order
, proc_t 
*socket_proc
, struct necp_socket_info 
*info
, bool is_loopback
) 
7731         struct socket 
*so 
= NULL
; 
7732         proc_t sock_proc 
= NULL
; 
7733         proc_t curr_proc 
= current_proc(); 
7735         memset(info
, 0, sizeof(struct necp_socket_info
)); 
7737         so 
= inp
->inp_socket
; 
7739         info
->drop_order 
= drop_order
; 
7740         info
->is_loopback 
= is_loopback
; 
7741         info
->is_delegated 
= ((so
->so_flags 
& SOF_DELEGATED
) ? true : false); 
7743         if (necp_kernel_socket_policies_condition_mask 
& NECP_KERNEL_CONDITION_UID
) { 
7744                 info
->uid 
= kauth_cred_getuid(so
->so_cred
); 
7747         if (necp_kernel_socket_policies_condition_mask 
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) { 
7748                 info
->traffic_class 
= so
->so_traffic_class
; 
7751         if (necp_kernel_socket_policies_condition_mask 
& NECP_KERNEL_CONDITION_HAS_CLIENT
) { 
7752                 info
->has_client 
= !uuid_is_null(inp
->necp_client_uuid
); 
7755         if (necp_kernel_socket_policies_condition_mask 
& NECP_KERNEL_CONDITION_CLIENT_FLAGS
) { 
7756                 info
->client_flags 
= 0; 
7757                 if (INP_NO_CONSTRAINED(inp
)) { 
7758                         info
->client_flags 
|= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED
; 
7760                 if (INP_NO_EXPENSIVE(inp
)) { 
7761                         info
->client_flags 
|= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE
; 
7763                 if (inp
->inp_socket
->so_flags1 
& SOF1_CELLFALLBACK
) { 
7764                         info
->client_flags 
|= NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC
; 
7766                 if (inp
->inp_socket
->so_flags1 
& SOF1_INBOUND 
|| override_is_inbound
) { 
7767                         info
->client_flags 
|= NECP_CLIENT_PARAMETER_FLAG_INBOUND
; 
7769                 if (inp
->inp_socket
->so_options 
& SO_ACCEPTCONN 
|| 
7770                     inp
->inp_flags2 
& INP2_EXTERNAL_PORT
) { 
7771                         info
->client_flags 
|= NECP_CLIENT_PARAMETER_FLAG_LISTENER
; 
7775         if (necp_kernel_socket_policies_condition_mask 
& NECP_KERNEL_CONDITION_PROTOCOL
) { 
7776                 if (inp
->inp_ip_p
) { 
7777                         info
->protocol 
= inp
->inp_ip_p
; 
7779                         info
->protocol 
= SOCK_PROTO(so
); 
7783         if (inp
->inp_flags2 
& INP2_WANT_APP_POLICY 
&& necp_kernel_socket_policies_condition_mask 
& NECP_KERNEL_CONDITION_APP_ID
) { 
7784                 u_int32_t responsible_application_id 
= 0; 
7786                 struct necp_uuid_id_mapping 
*existing_mapping 
= necp_uuid_lookup_app_id_locked(((so
->so_flags 
& SOF_DELEGATED
) ? so
->e_uuid 
: so
->last_uuid
)); 
7787                 if (existing_mapping
) { 
7788                         info
->application_id 
= existing_mapping
->id
; 
7791 #if defined(XNU_TARGET_OS_OSX) 
7792                 if (so
->so_rpid 
> 0) { 
7793                         existing_mapping 
= necp_uuid_lookup_app_id_locked(so
->so_ruuid
); 
7794                         if (existing_mapping 
!= NULL
) { 
7795                                 responsible_application_id 
= existing_mapping
->id
; 
7800                 if (responsible_application_id 
> 0) { 
7801                         info
->real_application_id 
= info
->application_id
; 
7802                         info
->application_id 
= responsible_application_id
; 
7803                         info
->used_responsible_pid 
= true; 
7804                 } else if (!(so
->so_flags 
& SOF_DELEGATED
)) { 
7805                         info
->real_application_id 
= info
->application_id
; 
7806                 } else if (necp_kernel_socket_policies_condition_mask 
& NECP_KERNEL_CONDITION_REAL_APP_ID
) { 
7807                         struct necp_uuid_id_mapping 
*real_existing_mapping 
= necp_uuid_lookup_app_id_locked(so
->last_uuid
); 
7808                         if (real_existing_mapping
) { 
7809                                 info
->real_application_id 
= real_existing_mapping
->id
; 
7813                 if (necp_kernel_socket_policies_condition_mask 
& NECP_KERNEL_CONDITION_ENTITLEMENT
) { 
7814                         info
->cred_result 
= priv_check_cred(so
->so_cred
, PRIV_NET_PRIVILEGED_NECP_MATCH
, 0); 
7815                         if (info
->cred_result 
!= 0) { 
7816                                 // Process does not have entitlement, check the parent process 
7817                                 necp_get_parent_cred_result(NULL
, info
); 
7823 #if defined(XNU_TARGET_OS_OSX) 
7824             info
->used_responsible_pid 
? so
->so_rpid 
: 
7826             ((so
->so_flags 
& SOF_DELEGATED
) ? so
->e_pid 
: so
->last_pid
); 
7827         if (socket_pid 
&& (socket_pid 
!= proc_pid(curr_proc
))) { 
7828                 sock_proc 
= proc_find(socket_pid
); 
7830                         *socket_proc 
= sock_proc
; 
7834         if (necp_kernel_socket_policies_condition_mask 
& NECP_KERNEL_CONDITION_PID
) { 
7835                 info
->pid 
= socket_pid
; 
7836                 info
->pid_version 
= proc_pidversion(sock_proc 
!= NULL 
? sock_proc 
: curr_proc
); 
7839         if (necp_kernel_socket_policies_condition_mask 
& NECP_KERNEL_CONDITION_PLATFORM_BINARY
) { 
7840                 info
->is_platform_binary 
= necp_is_platform_binary(sock_proc 
? sock_proc 
: curr_proc
) ? true : false; 
7843         if (necp_kernel_socket_policies_condition_mask 
& NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY
) { 
7844                 proc_t real_proc 
= curr_proc
; 
7845                 bool release_real_proc 
= false; 
7846                 if (so
->last_pid 
!= proc_pid(real_proc
)) { 
7847                         if (so
->last_pid 
== socket_pid 
&& sock_proc 
!= NULL
) { 
7848                                 real_proc 
= sock_proc
; 
7850                                 proc_t last_proc 
= proc_find(so
->last_pid
); 
7851                                 if (last_proc 
!= NULL
) { 
7852                                         real_proc 
= last_proc
; 
7853                                         release_real_proc 
= true; 
7857                 if (real_proc 
!= NULL
) { 
7858                         info
->real_is_platform_binary 
= (necp_is_platform_binary(real_proc
) ? true : false); 
7859                         if (release_real_proc
) { 
7860                                 proc_rele(real_proc
); 
7865         if (necp_kernel_socket_policies_condition_mask 
& NECP_KERNEL_CONDITION_ACCOUNT_ID 
&& inp
->inp_necp_attributes
.inp_account 
!= NULL
) { 
7866                 struct necp_string_id_mapping 
*existing_mapping 
= necp_lookup_string_to_id_locked(&necp_account_id_list
, inp
->inp_necp_attributes
.inp_account
); 
7867                 if (existing_mapping
) { 
7868                         info
->account_id 
= existing_mapping
->id
; 
7872         if (necp_kernel_socket_policies_condition_mask 
& NECP_KERNEL_CONDITION_DOMAIN
) { 
7873                 info
->domain 
= inp
->inp_necp_attributes
.inp_domain
; 
7876         if (override_bound_interface
) { 
7877                 info
->bound_interface_index 
= override_bound_interface
; 
7879                 if ((inp
->inp_flags 
& INP_BOUND_IF
) && inp
->inp_boundifp
) { 
7880                         info
->bound_interface_index 
= inp
->inp_boundifp
->if_index
; 
7884         if (necp_restrict_multicast 
|| 
7885             (necp_kernel_socket_policies_condition_mask 
& NECP_KERNEL_ADDRESS_TYPE_CONDITIONS
)) { 
7886                 if (override_local_addr 
!= NULL
) { 
7887                         if (override_local_addr
->sa_family 
== AF_INET6 
&& override_local_addr
->sa_len 
<= sizeof(struct sockaddr_in6
)) { 
7888                                 memcpy(&info
->local_addr
, override_local_addr
, override_local_addr
->sa_len
); 
7889                                 if (IN6_IS_ADDR_V4MAPPED(&(info
->local_addr
.sin6
.sin6_addr
))) { 
7890                                         struct sockaddr_in sin
; 
7891                                         in6_sin6_2_sin(&sin
, &(info
->local_addr
.sin6
)); 
7892                                         memset(&info
->local_addr
, 0, sizeof(union necp_sockaddr_union
)); 
7893                                         memcpy(&info
->local_addr
, &sin
, sin
.sin_len
); 
7895                         } else if (override_local_addr
->sa_family 
== AF_INET 
&& override_local_addr
->sa_len 
<= sizeof(struct sockaddr_in
)) { 
7896                                 memcpy(&info
->local_addr
, override_local_addr
, override_local_addr
->sa_len
); 
7899                         if (inp
->inp_vflag 
& INP_IPV4
) { 
7900                                 ((struct sockaddr_in 
*)&info
->local_addr
)->sin_family 
= AF_INET
; 
7901                                 ((struct sockaddr_in 
*)&info
->local_addr
)->sin_len 
= sizeof(struct sockaddr_in
); 
7902                                 ((struct sockaddr_in 
*)&info
->local_addr
)->sin_port 
= inp
->inp_lport
; 
7903                                 memcpy(&((struct sockaddr_in 
*)&info
->local_addr
)->sin_addr
, &inp
->inp_laddr
, sizeof(struct in_addr
)); 
7904                         } else if (inp
->inp_vflag 
& INP_IPV6
) { 
7905                                 ((struct sockaddr_in6 
*)&info
->local_addr
)->sin6_family 
= AF_INET6
; 
7906                                 ((struct sockaddr_in6 
*)&info
->local_addr
)->sin6_len 
= sizeof(struct sockaddr_in6
); 
7907                                 ((struct sockaddr_in6 
*)&info
->local_addr
)->sin6_port 
= inp
->inp_lport
; 
7908                                 memcpy(&((struct sockaddr_in6 
*)&info
->local_addr
)->sin6_addr
, &inp
->in6p_laddr
, sizeof(struct in6_addr
)); 
7912                 if (override_remote_addr 
!= NULL
) { 
7913                         if (override_remote_addr
->sa_family 
== AF_INET6 
&& override_remote_addr
->sa_len 
<= sizeof(struct sockaddr_in6
)) { 
7914                                 memcpy(&info
->remote_addr
, override_remote_addr
, override_remote_addr
->sa_len
); 
7915                                 if (IN6_IS_ADDR_V4MAPPED(&(info
->remote_addr
.sin6
.sin6_addr
))) { 
7916                                         struct sockaddr_in sin
; 
7917                                         in6_sin6_2_sin(&sin
, &(info
->remote_addr
.sin6
)); 
7918                                         memset(&info
->remote_addr
, 0, sizeof(union necp_sockaddr_union
)); 
7919                                         memcpy(&info
->remote_addr
, &sin
, sin
.sin_len
); 
7921                         } else if (override_remote_addr
->sa_family 
== AF_INET 
&& override_remote_addr
->sa_len 
<= sizeof(struct sockaddr_in
)) { 
7922                                 memcpy(&info
->remote_addr
, override_remote_addr
, override_remote_addr
->sa_len
); 
7925                         if (inp
->inp_vflag 
& INP_IPV4
) { 
7926                                 ((struct sockaddr_in 
*)&info
->remote_addr
)->sin_family 
= AF_INET
; 
7927                                 ((struct sockaddr_in 
*)&info
->remote_addr
)->sin_len 
= sizeof(struct sockaddr_in
); 
7928                                 ((struct sockaddr_in 
*)&info
->remote_addr
)->sin_port 
= inp
->inp_fport
; 
7929                                 memcpy(&((struct sockaddr_in 
*)&info
->remote_addr
)->sin_addr
, &inp
->inp_faddr
, sizeof(struct in_addr
)); 
7930                         } else if (inp
->inp_vflag 
& INP_IPV6
) { 
7931                                 ((struct sockaddr_in6 
*)&info
->remote_addr
)->sin6_family 
= AF_INET6
; 
7932                                 ((struct sockaddr_in6 
*)&info
->remote_addr
)->sin6_len 
= sizeof(struct sockaddr_in6
); 
7933                                 ((struct sockaddr_in6 
*)&info
->remote_addr
)->sin6_port 
= inp
->inp_fport
; 
7934                                 memcpy(&((struct sockaddr_in6 
*)&info
->remote_addr
)->sin6_addr
, &inp
->in6p_faddr
, sizeof(struct in6_addr
)); 
7940 static inline struct necp_kernel_socket_policy 
* 
7941 necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy 
**policy_search_array
, struct necp_socket_info 
*info
, 
7942     necp_kernel_policy_filter 
*return_filter
, 
7943     u_int32_t 
*return_route_rule_id_array
, size_t *return_route_rule_id_array_count
, size_t route_rule_id_array_count
, 
7944     necp_kernel_policy_result 
*return_service_action
, necp_kernel_policy_service 
*return_service
, 
7945     u_int32_t 
*return_netagent_array
, u_int32_t 
*return_netagent_use_flags_array
, size_t netagent_array_count
, 
7946     struct necp_client_parameter_netagent_type 
*required_agent_types
, 
7947     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
, 
7948     necp_kernel_policy_result 
*return_drop_dest_policy_result
, necp_drop_all_bypass_check_result_t 
*return_drop_all_bypass
, 
7949     u_int32_t 
*return_flow_divert_aggregate_unit
) 
7951         struct necp_kernel_socket_policy 
*matched_policy 
= NULL
; 
7952         u_int32_t skip_order 
= 0; 
7953         u_int32_t skip_session_order 
= 0; 
7954         size_t route_rule_id_count 
= 0; 
7956         size_t netagent_cursor 
= 0; 
7957         necp_drop_all_bypass_check_result_t drop_all_bypass 
= NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
; 
7958         if (return_drop_all_bypass 
!= NULL
) { 
7959                 *return_drop_all_bypass 
= drop_all_bypass
; 
7962         // Pre-process domain for quick matching 
7963         struct substring domain_substring 
= necp_trim_dots_and_stars(info
->domain
, info
->domain 
? strlen(info
->domain
) : 0); 
7964         u_int8_t domain_dot_count 
= necp_count_dots(domain_substring
.string
, domain_substring
.length
); 
7966         if (return_filter 
!= NULL
) { 
7970         if (return_route_rule_id_array_count 
!= NULL
) { 
7971                 *return_route_rule_id_array_count 
= 0; 
7974         if (return_service_action 
!= NULL
) { 
7975                 *return_service_action 
= 0; 
7978         if (return_service 
!= NULL
) { 
7979                 return_service
->identifier 
= 0; 
7980                 return_service
->data 
= 0; 
7983         // Do not subject layer-2 filter to NECP policies, return a PASS policy 
7984         if (necp_pass_interpose 
> 0 && info
->client_flags 
& NECP_CLIENT_PARAMETER_FLAG_INTERPOSE
) { 
7985                 return &pass_policy
; 
7988         *return_drop_dest_policy_result 
= NECP_KERNEL_POLICY_RESULT_NONE
; 
7990         if (policy_search_array 
!= NULL
) { 
7991                 for (i 
= 0; policy_search_array
[i
] != NULL
; i
++) { 
7992                         if (necp_drop_all_order 
!= 0 && policy_search_array
[i
]->session_order 
>= necp_drop_all_order
) { 
7993                                 // We've hit a drop all rule 
7994                                 if (drop_all_bypass 
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
) { 
7995                                         drop_all_bypass 
= necp_check_drop_all_bypass_result(proc
); 
7996                                         if (return_drop_all_bypass 
!= NULL
) { 
7997                                                 *return_drop_all_bypass 
= drop_all_bypass
; 
8000                                 if (drop_all_bypass 
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
) { 
8004                         if (necp_drop_dest_policy
.entry_count 
!= 0 && 
8005                             necp_address_matches_drop_dest_policy(&info
->remote_addr
, policy_search_array
[i
]->session_order
)) { 
8006                                 // We've hit a drop by destination address rule 
8007                                 *return_drop_dest_policy_result 
= NECP_KERNEL_POLICY_RESULT_DROP
; 
8010                         if (info
->drop_order 
!= 0 && policy_search_array
[i
]->session_order 
>= info
->drop_order
) { 
8011                                 // We've hit a drop order for this socket 
8014                         if (skip_session_order 
&& policy_search_array
[i
]->session_order 
>= skip_session_order
) { 
8017                                 skip_session_order 
= 0; 
8020                                 if (policy_search_array
[i
]->order 
< skip_order
) { 
8026                                         skip_session_order 
= 0; 
8028                         } else if (skip_session_order
) { 
8033                         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
->pid_version
, 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
, info
->is_loopback
, info
->real_is_platform_binary
, info
->is_delegated
)) { 
8034                                 if (policy_search_array
[i
]->result 
== NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER
) { 
8035                                         if (return_filter 
&& *return_filter 
!= NECP_FILTER_UNIT_NO_FILTER
) { 
8036                                                 necp_kernel_policy_filter control_unit 
= policy_search_array
[i
]->result_parameter
.filter_control_unit
; 
8037                                                 if (control_unit 
== NECP_FILTER_UNIT_NO_FILTER
) { 
8038                                                         *return_filter 
= control_unit
; 
8040                                                         *return_filter 
|= control_unit
; 
8042                                                 if (necp_debug 
> 1) { 
8043                                                         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
); 
8047                                 } else if (policy_search_array
[i
]->result 
== NECP_KERNEL_POLICY_RESULT_ROUTE_RULES
) { 
8048                                         if (return_route_rule_id_array 
&& route_rule_id_count 
< route_rule_id_array_count
) { 
8049                                                 return_route_rule_id_array
[route_rule_id_count
++] = policy_search_array
[i
]->result_parameter
.route_rule_id
; 
8050                                                 if (necp_debug 
> 1) { 
8051                                                         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
); 
8055                                 } else if (necp_kernel_socket_result_is_trigger_service_type(policy_search_array
[i
])) { 
8056                                         if (return_service_action 
&& *return_service_action 
== 0) { 
8057                                                 *return_service_action 
= policy_search_array
[i
]->result
; 
8058                                                 if (necp_debug 
> 1) { 
8059                                                         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
); 
8062                                         if (return_service 
&& return_service
->identifier 
== 0) { 
8063                                                 return_service
->identifier 
= policy_search_array
[i
]->result_parameter
.service
.identifier
; 
8064                                                 return_service
->data 
= policy_search_array
[i
]->result_parameter
.service
.data
; 
8065                                                 if (necp_debug 
> 1) { 
8066                                                         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
); 
8070                                 } else if (policy_search_array
[i
]->result 
== NECP_KERNEL_POLICY_RESULT_USE_NETAGENT 
|| 
8071                                     policy_search_array
[i
]->result 
== NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED
) { 
8072                                         if (return_netagent_array 
!= NULL 
&& 
8073                                             netagent_cursor 
< netagent_array_count
) { 
8074                                                 return_netagent_array
[netagent_cursor
] = policy_search_array
[i
]->result_parameter
.netagent_id
; 
8075                                                 if (return_netagent_use_flags_array 
!= NULL 
&& 
8076                                                     policy_search_array
[i
]->result 
== NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED
) { 
8077                                                         return_netagent_use_flags_array
[netagent_cursor
] |= NECP_AGENT_USE_FLAG_SCOPE
; 
8080                                                 if (necp_debug 
> 1) { 
8081                                                         NECPLOG(LOG_DEBUG
, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) %s Netagent %d", 
8082                                                             info
->application_id
, info
->real_application_id
, info
->bound_interface_index
, info
->protocol
, 
8083                                                             policy_search_array
[i
]->result 
== NECP_KERNEL_POLICY_RESULT_USE_NETAGENT 
? "Use" : "Scope", 
8084                                                             policy_search_array
[i
]->result_parameter
.netagent_id
); 
8088                                 } else if (policy_search_array
[i
]->result 
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
) { 
8089                                         u_int32_t control_unit 
= policy_search_array
[i
]->result_parameter
.flow_divert_control_unit
; 
8090                                         if (control_unit 
& FLOW_DIVERT_IS_TRANSPARENT
) { 
8091                                                 /* For transparent proxies, accumulate the control unit and continue to the next policy */ 
8092                                                 if (return_flow_divert_aggregate_unit 
!= NULL
) { 
8093                                                         *return_flow_divert_aggregate_unit 
|= (control_unit 
& ~FLOW_DIVERT_IS_TRANSPARENT
); 
8094                                                         if (necp_debug 
> 1) { 
8095                                                                 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
); 
8102                                 // Matched policy is a skip. Do skip and continue. 
8103                                 if (policy_search_array
[i
]->result 
== NECP_KERNEL_POLICY_RESULT_SKIP
) { 
8104                                         skip_order 
= policy_search_array
[i
]->result_parameter
.skip_policy_order
; 
8105                                         skip_session_order 
= policy_search_array
[i
]->session_order 
+ 1; 
8106                                         if (skip_policy_id 
&& *skip_policy_id 
== NECP_KERNEL_POLICY_ID_NONE
) { 
8107                                                 *skip_policy_id 
= policy_search_array
[i
]->id
; 
8112                                 // Matched an allow unentitled, which clears any drop order 
8113                                 if (policy_search_array
[i
]->result 
== NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED
) { 
8114                                         info
->drop_order 
= 0; 
8118                                 // Passed all tests, found a match 
8119                                 matched_policy 
= policy_search_array
[i
]; 
8125         if (return_route_rule_id_array_count 
!= NULL
) { 
8126                 *return_route_rule_id_array_count 
= route_rule_id_count
; 
8128         return matched_policy
; 
8132 necp_socket_uses_interface(struct inpcb 
*inp
, u_int32_t interface_index
) 
8134         bool found_match 
= FALSE
; 
8136         ifaddr_t 
*addresses 
= NULL
; 
8137         union necp_sockaddr_union address_storage
; 
8139         int family 
= AF_INET
; 
8140         ifnet_t interface 
= ifindex2ifnet
[interface_index
]; 
8142         if (inp 
== NULL 
|| interface 
== NULL
) { 
8146         if (inp
->inp_vflag 
& INP_IPV4
) { 
8148         } else if (inp
->inp_vflag 
& INP_IPV6
) { 
8152         result 
= ifnet_get_address_list_family(interface
, &addresses
, family
); 
8154                 NECPLOG(LOG_ERR
, "Failed to get address list for %s%d", ifnet_name(interface
), ifnet_unit(interface
)); 
8158         for (i 
= 0; addresses
[i
] != NULL
; i
++) { 
8159                 if (ifaddr_address(addresses
[i
], &address_storage
.sa
, sizeof(address_storage
)) == 0) { 
8160                         if (family 
== AF_INET
) { 
8161                                 if (memcmp(&address_storage
.sin
.sin_addr
, &inp
->inp_laddr
, sizeof(inp
->inp_laddr
)) == 0) { 
8165                         } else if (family 
== AF_INET6
) { 
8166                                 if (memcmp(&address_storage
.sin6
.sin6_addr
, &inp
->in6p_laddr
, sizeof(inp
->in6p_laddr
)) == 0) { 
8175         ifnet_free_address_list(addresses
); 
8181 necp_socket_is_connected(struct inpcb 
*inp
) 
8183         return inp
->inp_socket
->so_state 
& (SS_ISCONNECTING 
| SS_ISCONNECTED 
| SS_ISDISCONNECTING
); 
8186 static inline necp_socket_bypass_type_t
 
8187 necp_socket_bypass(struct sockaddr 
*override_local_addr
, struct sockaddr 
*override_remote_addr
, struct inpcb 
*inp
) 
8189         if (necp_pass_loopback 
> 0 && necp_is_loopback(override_local_addr
, override_remote_addr
, inp
, NULL
, IFSCOPE_NONE
)) { 
8190                 return NECP_BYPASS_TYPE_LOOPBACK
; 
8191         } else if (necp_is_intcoproc(inp
, NULL
)) { 
8192                 return NECP_BYPASS_TYPE_INTCOPROC
; 
8195         return NECP_BYPASS_TYPE_NONE
; 
8199 necp_socket_ip_tunnel_tso(struct inpcb 
*inp
) 
8201         u_int tunnel_interface_index 
= inp
->inp_policyresult
.results
.result_parameter
.tunnel_interface_index
; 
8202         ifnet_t tunnel_interface 
= NULL
; 
8204         ifnet_head_lock_shared(); 
8205         tunnel_interface 
= ifindex2ifnet
[tunnel_interface_index
]; 
8208         if (tunnel_interface 
!= NULL
) { 
8209                 tcp_set_tso(intotcpcb(inp
), tunnel_interface
); 
8213 necp_kernel_policy_id
 
8214 necp_socket_find_policy_match(struct inpcb 
*inp
, struct sockaddr 
*override_local_addr
, struct sockaddr 
*override_remote_addr
, u_int32_t override_bound_interface
) 
8216         struct socket 
*so 
= NULL
; 
8217         necp_kernel_policy_filter filter_control_unit 
= 0; 
8218         struct necp_kernel_socket_policy 
*matched_policy 
= NULL
; 
8219         necp_kernel_policy_id matched_policy_id 
= NECP_KERNEL_POLICY_ID_NONE
; 
8220         necp_kernel_policy_result service_action 
= 0; 
8221         necp_kernel_policy_service service 
= { 0, 0 }; 
8222         u_int32_t drop_dest_policy_result 
= NECP_KERNEL_POLICY_RESULT_NONE
; 
8223         necp_drop_all_bypass_check_result_t drop_all_bypass 
= NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
; 
8224         proc_t socket_proc 
= NULL
; 
8225         necp_socket_bypass_type_t bypass_type 
= NECP_BYPASS_TYPE_NONE
; 
8227         u_int32_t netagent_ids
[NECP_MAX_NETAGENTS
]; 
8228         memset(&netagent_ids
, 0, sizeof(netagent_ids
)); 
8229         int netagent_cursor
; 
8231         struct necp_socket_info info
; 
8233         u_int32_t flow_divert_aggregate_unit 
= 0; 
8236                 return NECP_KERNEL_POLICY_ID_NONE
; 
8239         // Ignore invalid addresses 
8240         if (override_local_addr 
!= NULL 
&& 
8241             !necp_address_is_valid(override_local_addr
)) { 
8242                 override_local_addr 
= NULL
; 
8244         if (override_remote_addr 
!= NULL 
&& 
8245             !necp_address_is_valid(override_remote_addr
)) { 
8246                 override_remote_addr 
= NULL
; 
8249         so 
= inp
->inp_socket
; 
8251         u_int32_t drop_order 
= necp_process_drop_order(so
->so_cred
); 
8253         // Don't lock. Possible race condition, but we don't want the performance hit. 
8254         if (necp_kernel_socket_policies_count 
== 0 || 
8255             (!(inp
->inp_flags2 
& INP2_WANT_APP_POLICY
) && necp_kernel_socket_policies_non_app_count 
== 0)) { 
8256                 if (necp_drop_all_order 
> 0 || drop_order 
> 0) { 
8257                         inp
->inp_policyresult
.policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
8258                         inp
->inp_policyresult
.skip_policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
8259                         inp
->inp_policyresult
.policy_gencount 
= 0; 
8260                         inp
->inp_policyresult
.app_id 
= 0; 
8261                         inp
->inp_policyresult
.flowhash 
= 0; 
8262                         inp
->inp_policyresult
.results
.filter_control_unit 
= 0; 
8263                         inp
->inp_policyresult
.results
.flow_divert_aggregate_unit 
= 0; 
8264                         inp
->inp_policyresult
.results
.route_rule_id 
= 0; 
8265                         if (necp_socket_bypass(override_local_addr
, override_remote_addr
, inp
) != NECP_BYPASS_TYPE_NONE
) { 
8266                                 inp
->inp_policyresult
.results
.result 
= NECP_KERNEL_POLICY_RESULT_PASS
; 
8268                                 inp
->inp_policyresult
.results
.result 
= NECP_KERNEL_POLICY_RESULT_DROP
; 
8271                 return NECP_KERNEL_POLICY_ID_NONE
; 
8274         // Check for loopback exception 
8275         bypass_type 
= necp_socket_bypass(override_local_addr
, override_remote_addr
, inp
); 
8276         if (bypass_type 
== NECP_BYPASS_TYPE_INTCOPROC 
|| (bypass_type 
== NECP_BYPASS_TYPE_LOOPBACK 
&& necp_pass_loopback 
== NECP_LOOPBACK_PASS_ALL
)) { 
8277                 if (inp
->inp_policyresult
.results
.result 
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
) { 
8278                         // If the previous policy result was "socket scoped", un-scope the socket. 
8279                         inp
->inp_flags 
&= ~INP_BOUND_IF
; 
8280                         inp
->inp_boundifp 
= NULL
; 
8282                 // Mark socket as a pass 
8283                 inp
->inp_policyresult
.policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
8284                 inp
->inp_policyresult
.skip_policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
8285                 inp
->inp_policyresult
.policy_gencount 
= 0; 
8286                 inp
->inp_policyresult
.app_id 
= 0; 
8287                 inp
->inp_policyresult
.flowhash 
= 0; 
8288                 inp
->inp_policyresult
.results
.filter_control_unit 
= 0; 
8289                 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit 
= 0; 
8290                 inp
->inp_policyresult
.results
.route_rule_id 
= 0; 
8291                 inp
->inp_policyresult
.results
.result 
= NECP_KERNEL_POLICY_RESULT_PASS
; 
8292                 return NECP_KERNEL_POLICY_ID_NONE
; 
8296         lck_rw_lock_shared(&necp_kernel_policy_lock
); 
8297         necp_socket_fillout_info_locked(inp
, override_local_addr
, override_remote_addr
, override_bound_interface
, false, drop_order
, &socket_proc
, &info
, (bypass_type 
== NECP_BYPASS_TYPE_LOOPBACK
)); 
8300         u_int32_t flowhash 
= necp_socket_calc_flowhash_locked(&info
); 
8301         if (inp
->inp_policyresult
.policy_id 
!= NECP_KERNEL_POLICY_ID_NONE 
&& 
8302             inp
->inp_policyresult
.policy_gencount 
== necp_kernel_socket_policies_gencount 
&& 
8303             inp
->inp_policyresult
.flowhash 
== flowhash
) { 
8304                 // If already matched this socket on this generation of table, skip 
8307                 lck_rw_done(&necp_kernel_policy_lock
); 
8310                         proc_rele(socket_proc
); 
8313                 return inp
->inp_policyresult
.policy_id
; 
8316         inp
->inp_policyresult
.app_id 
= info
.application_id
; 
8318         // Match socket to policy 
8319         necp_kernel_policy_id skip_policy_id 
= NECP_KERNEL_POLICY_ID_NONE
; 
8320         u_int32_t route_rule_id_array
[MAX_AGGREGATE_ROUTE_RULES
]; 
8321         size_t route_rule_id_array_count 
= 0; 
8322         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
); 
8324         // Check for loopback exception again after the policy match 
8325         if (bypass_type 
== NECP_BYPASS_TYPE_LOOPBACK 
&& 
8326             necp_pass_loopback 
== NECP_LOOPBACK_PASS_WITH_FILTER 
&& 
8327             (matched_policy 
== NULL 
|| matched_policy
->result 
!= NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
)) { 
8328                 if (inp
->inp_policyresult
.results
.result 
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
) { 
8329                         // If the previous policy result was "socket scoped", un-scope the socket. 
8330                         inp
->inp_flags 
&= ~INP_BOUND_IF
; 
8331                         inp
->inp_boundifp 
= NULL
; 
8333                 // Mark socket as a pass 
8334                 inp
->inp_policyresult
.policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
8335                 inp
->inp_policyresult
.skip_policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
8336                 inp
->inp_policyresult
.policy_gencount 
= 0; 
8337                 inp
->inp_policyresult
.app_id 
= 0; 
8338                 inp
->inp_policyresult
.flowhash 
= 0; 
8339                 inp
->inp_policyresult
.results
.filter_control_unit 
= filter_control_unit
; 
8340                 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit 
= flow_divert_aggregate_unit
; 
8341                 inp
->inp_policyresult
.results
.route_rule_id 
= 0; 
8342                 inp
->inp_policyresult
.results
.result 
= NECP_KERNEL_POLICY_RESULT_PASS
; 
8345                 lck_rw_done(&necp_kernel_policy_lock
); 
8348                         proc_rele(socket_proc
); 
8351                 return NECP_KERNEL_POLICY_ID_NONE
; 
8354         // If the socket matched a scoped service policy, mark as Drop if not registered. 
8355         // This covers the cases in which a service is required (on demand) but hasn't started yet. 
8356         if ((service_action 
== NECP_KERNEL_POLICY_RESULT_TRIGGER_SCOPED 
|| 
8357             service_action 
== NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED
) && 
8358             service
.identifier 
!= 0 && 
8359             service
.identifier 
!= NECP_NULL_SERVICE_ID
) { 
8360                 bool service_is_registered 
= FALSE
; 
8361                 struct necp_service_registration 
*service_registration 
= NULL
; 
8362                 LIST_FOREACH(service_registration
, &necp_registered_service_list
, kernel_chain
) { 
8363                         if (service
.identifier 
== service_registration
->service_id
) { 
8364                                 service_is_registered 
= TRUE
; 
8368                 if (!service_is_registered
) { 
8369                         // Mark socket as a drop if service is not registered 
8370                         inp
->inp_policyresult
.policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
8371                         inp
->inp_policyresult
.skip_policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
8372                         inp
->inp_policyresult
.policy_gencount 
= necp_kernel_socket_policies_gencount
; 
8373                         inp
->inp_policyresult
.flowhash 
= flowhash
; 
8374                         inp
->inp_policyresult
.results
.filter_control_unit 
= 0; 
8375                         inp
->inp_policyresult
.results
.flow_divert_aggregate_unit 
= 0; 
8376                         inp
->inp_policyresult
.results
.route_rule_id 
= 0; 
8377                         inp
->inp_policyresult
.results
.result 
= NECP_KERNEL_POLICY_RESULT_DROP
; 
8379                         if (necp_debug 
> 1) { 
8380                                 NECPLOG(LOG_DEBUG
, "Socket Policy: (BoundInterface %d Proto %d) Dropping packet because service is not registered", info
.bound_interface_index
, info
.protocol
); 
8384                         lck_rw_done(&necp_kernel_policy_lock
); 
8387                                 proc_rele(socket_proc
); 
8390                         return NECP_KERNEL_POLICY_ID_NONE
; 
8394         for (netagent_cursor 
= 0; netagent_cursor 
< NECP_MAX_NETAGENTS
; netagent_cursor
++) { 
8395                 struct necp_uuid_id_mapping 
*mapping 
= NULL
; 
8396                 u_int32_t netagent_id 
= netagent_ids
[netagent_cursor
]; 
8397                 if (netagent_id 
== 0) { 
8400                 mapping 
= necp_uuid_lookup_uuid_with_service_id_locked(netagent_id
); 
8401                 if (mapping 
!= NULL
) { 
8402                         u_int32_t agent_flags 
= 0; 
8403                         agent_flags 
= netagent_get_flags(mapping
->uuid
); 
8404                         if (agent_flags 
& NETAGENT_FLAG_REGISTERED
) { 
8405                                 if (agent_flags 
& NETAGENT_FLAG_ACTIVE
) { 
8407                                 } else if ((agent_flags 
& NETAGENT_FLAG_VOLUNTARY
) == 0) { 
8408                                         if (agent_flags 
& NETAGENT_FLAG_KERNEL_ACTIVATED
) { 
8409                                                 int trigger_error 
= 0; 
8410                                                 trigger_error 
= netagent_kernel_trigger(mapping
->uuid
); 
8411                                                 if (necp_debug 
> 1) { 
8412                                                         NECPLOG(LOG_DEBUG
, "Socket Policy: Triggering inactive agent, error %d", trigger_error
); 
8416                                         // Mark socket as a drop if required agent is not active 
8417                                         inp
->inp_policyresult
.policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
8418                                         inp
->inp_policyresult
.skip_policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
8419                                         inp
->inp_policyresult
.policy_gencount 
= necp_kernel_socket_policies_gencount
; 
8420                                         inp
->inp_policyresult
.flowhash 
= flowhash
; 
8421                                         inp
->inp_policyresult
.results
.filter_control_unit 
= 0; 
8422                                         inp
->inp_policyresult
.results
.flow_divert_aggregate_unit 
= 0; 
8423                                         inp
->inp_policyresult
.results
.route_rule_id 
= 0; 
8424                                         inp
->inp_policyresult
.results
.result 
= NECP_KERNEL_POLICY_RESULT_DROP
; 
8426                                         if (necp_debug 
> 1) { 
8427                                                 NECPLOG(LOG_DEBUG
, "Socket Policy: (BoundInterface %d Proto %d) Dropping packet because agent is not active", info
.bound_interface_index
, info
.protocol
); 
8431                                         lck_rw_done(&necp_kernel_policy_lock
); 
8434                                                 proc_rele(socket_proc
); 
8437                                         return NECP_KERNEL_POLICY_ID_NONE
; 
8443         u_int32_t route_rule_id 
= 0; 
8444         if (route_rule_id_array_count 
== 1) { 
8445                 route_rule_id 
= route_rule_id_array
[0]; 
8446         } else if (route_rule_id_array_count 
> 1) { 
8447                 route_rule_id 
= necp_create_aggregate_route_rule(route_rule_id_array
); 
8450         bool reset_tcp_tunnel_interface 
= false; 
8451         bool send_local_network_denied_event 
= false; 
8452         if (matched_policy
) { 
8453                 matched_policy_id 
= matched_policy
->id
; 
8454                 inp
->inp_policyresult
.policy_id 
= matched_policy
->id
; 
8455                 inp
->inp_policyresult
.skip_policy_id 
= skip_policy_id
; 
8456                 inp
->inp_policyresult
.policy_gencount 
= necp_kernel_socket_policies_gencount
; 
8457                 inp
->inp_policyresult
.flowhash 
= flowhash
; 
8458                 inp
->inp_policyresult
.results
.filter_control_unit 
= filter_control_unit
; 
8459                 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit 
= flow_divert_aggregate_unit
; 
8460                 inp
->inp_policyresult
.results
.route_rule_id 
= route_rule_id
; 
8461                 inp
->inp_policyresult
.results
.result 
= matched_policy
->result
; 
8462                 memcpy(&inp
->inp_policyresult
.results
.result_parameter
, &matched_policy
->result_parameter
, sizeof(matched_policy
->result_parameter
)); 
8464                 if (info
.used_responsible_pid 
&& (matched_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REAL_APP_ID
)) { 
8465                         inp
->inp_policyresult
.app_id 
= info
.real_application_id
; 
8468                 if (necp_socket_is_connected(inp
) && 
8469                     (matched_policy
->result 
== NECP_KERNEL_POLICY_RESULT_DROP 
|| 
8470                     (matched_policy
->result 
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL 
&& !necp_socket_uses_interface(inp
, matched_policy
->result_parameter
.tunnel_interface_index
)))) { 
8472                                 NECPLOG(LOG_DEBUG
, "Marking socket in state %d as defunct", so
->so_state
); 
8474                         sosetdefunct(current_proc(), so
, SHUTDOWN_SOCKET_LEVEL_NECP 
| SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL
, TRUE
); 
8475                 } else if (necp_socket_is_connected(inp
) && 
8476                     matched_policy
->result 
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL 
&& 
8477                     info
.protocol 
== IPPROTO_TCP
) { 
8478                         // Reset TCP socket interface based parameters if tunnel policy changes 
8479                         reset_tcp_tunnel_interface 
= true; 
8482                 if (necp_debug 
> 1) { 
8483                         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
); 
8486                 if (matched_policy
->result 
== NECP_KERNEL_POLICY_RESULT_DROP 
&& 
8487                     matched_policy
->result_parameter
.drop_flags 
& NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK
) { 
8488                         // Trigger the event that we dropped due to a local network policy 
8489                         send_local_network_denied_event 
= true; 
8492                 bool drop_all 
= false; 
8493                 if (necp_drop_all_order 
> 0 || info
.drop_order 
> 0 || drop_dest_policy_result 
== NECP_KERNEL_POLICY_RESULT_DROP
) { 
8494                         // Mark socket as a drop if set 
8496                         if (drop_all_bypass 
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
) { 
8497                                 drop_all_bypass 
= necp_check_drop_all_bypass_result(socket_proc 
? socket_proc 
: current_proc()); 
8500                 if (drop_all 
&& drop_all_bypass 
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
) { 
8501                         inp
->inp_policyresult
.policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
8502                         inp
->inp_policyresult
.skip_policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
8503                         inp
->inp_policyresult
.policy_gencount 
= necp_kernel_socket_policies_gencount
; 
8504                         inp
->inp_policyresult
.flowhash 
= flowhash
; 
8505                         inp
->inp_policyresult
.results
.filter_control_unit 
= 0; 
8506                         inp
->inp_policyresult
.results
.flow_divert_aggregate_unit 
= 0; 
8507                         inp
->inp_policyresult
.results
.route_rule_id 
= 0; 
8508                         inp
->inp_policyresult
.results
.result 
= NECP_KERNEL_POLICY_RESULT_DROP
; 
8510                         // Mark non-matching socket so we don't re-check it 
8511                         inp
->inp_policyresult
.policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
8512                         inp
->inp_policyresult
.skip_policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
8513                         inp
->inp_policyresult
.policy_gencount 
= necp_kernel_socket_policies_gencount
; 
8514                         inp
->inp_policyresult
.flowhash 
= flowhash
; 
8515                         inp
->inp_policyresult
.results
.filter_control_unit 
= filter_control_unit
; // We may have matched a filter, so mark it! 
8516                         inp
->inp_policyresult
.results
.flow_divert_aggregate_unit 
= flow_divert_aggregate_unit
; 
8517                         inp
->inp_policyresult
.results
.route_rule_id 
= route_rule_id
; // We may have matched a route rule, so mark it! 
8518                         inp
->inp_policyresult
.results
.result 
= NECP_KERNEL_POLICY_RESULT_NONE
; 
8522         if (necp_check_missing_client_drop(socket_proc 
? socket_proc 
: current_proc(), &info
) || 
8523             necp_check_restricted_multicast_drop(socket_proc 
? socket_proc 
: current_proc(), &info
, false)) { 
8525                 inp
->inp_policyresult
.policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
8526                 inp
->inp_policyresult
.skip_policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
8527                 inp
->inp_policyresult
.policy_gencount 
= necp_kernel_socket_policies_gencount
; 
8528                 inp
->inp_policyresult
.flowhash 
= flowhash
; 
8529                 inp
->inp_policyresult
.results
.filter_control_unit 
= 0; 
8530                 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit 
= 0; 
8531                 inp
->inp_policyresult
.results
.route_rule_id 
= 0; 
8532                 inp
->inp_policyresult
.results
.result 
= NECP_KERNEL_POLICY_RESULT_DROP
; 
8536         lck_rw_done(&necp_kernel_policy_lock
); 
8538         if (reset_tcp_tunnel_interface
) { 
8539                 // Update MSS when not holding the policy lock to avoid recursive locking 
8540                 tcp_mtudisc(inp
, 0); 
8542                 // Update TSO flag based on the tunnel interface 
8543                 necp_socket_ip_tunnel_tso(inp
); 
8546         if (send_local_network_denied_event 
&& inp
->inp_policyresult
.network_denied_notifies 
== 0) { 
8547                 inp
->inp_policyresult
.network_denied_notifies
++; 
8548                 necp_send_network_denied_event(((so
->so_flags 
& SOF_DELEGATED
) ? so
->e_pid 
: so
->last_pid
), 
8549                     ((so
->so_flags 
& SOF_DELEGATED
) ? so
->e_uuid 
: so
->last_uuid
), 
8550                     NETPOLICY_NETWORKTYPE_LOCAL
); 
8554                 proc_rele(socket_proc
); 
8557         return matched_policy_id
; 
8561 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
) 
8563         if (!(kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) { 
8564                 if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) { 
8565                         u_int32_t cond_bound_interface_index 
= kernel_policy
->cond_bound_interface 
? kernel_policy
->cond_bound_interface
->if_index 
: 0; 
8566                         if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) { 
8567                                 if (bound_interface_index 
== cond_bound_interface_index
) { 
8568                                         // No match, matches forbidden interface 
8572                                 if (bound_interface_index 
!= cond_bound_interface_index
) { 
8573                                         // No match, does not match required interface 
8578                         if (bound_interface_index 
!= 0) { 
8579                                 // No match, requires a non-bound packet 
8585         if (kernel_policy
->condition_mask 
== 0) { 
8589         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_POLICY_ID
) { 
8590                 necp_kernel_policy_id matched_policy_id 
= 
8591                     kernel_policy
->result 
== NECP_KERNEL_POLICY_RESULT_SKIP 
? socket_skip_policy_id 
: socket_policy_id
; 
8592                 if (matched_policy_id 
!= kernel_policy
->cond_policy_id
) { 
8593                         // No match, does not match required id 
8598         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LAST_INTERFACE
) { 
8599                 if (last_interface_index 
!= kernel_policy
->cond_last_interface_index
) { 
8604         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_PROTOCOL
) { 
8605                 if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_PROTOCOL
) { 
8606                         if (protocol 
== kernel_policy
->cond_protocol
) { 
8607                                 // No match, matches forbidden protocol 
8611                         if (protocol 
!= kernel_policy
->cond_protocol
) { 
8612                                 // No match, does not match required protocol 
8618         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) { 
8619                 bool is_local 
= FALSE
; 
8622                         is_local 
= IS_NECP_DEST_IN_LOCAL_NETWORKS(rt
); 
8624                         is_local 
= necp_is_route_local(remote
); 
8628                         // Either no route to validate or no match for local networks 
8633         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_START
) { 
8634                 if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_END
) { 
8635                         bool inRange 
= necp_is_addr_in_range((struct sockaddr 
*)local
, (struct sockaddr 
*)&kernel_policy
->cond_local_start
, (struct sockaddr 
*)&kernel_policy
->cond_local_end
); 
8636                         if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_LOCAL_END
) { 
8645                 } else if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) { 
8646                         bool inSubnet 
= necp_is_addr_in_subnet((struct sockaddr 
*)local
, (struct sockaddr 
*)&kernel_policy
->cond_local_start
, kernel_policy
->cond_local_prefix
); 
8647                         if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) { 
8659         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_START
) { 
8660                 if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_END
) { 
8661                         bool inRange 
= necp_is_addr_in_range((struct sockaddr 
*)remote
, (struct sockaddr 
*)&kernel_policy
->cond_remote_start
, (struct sockaddr 
*)&kernel_policy
->cond_remote_end
); 
8662                         if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_REMOTE_END
) { 
8671                 } else if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) { 
8672                         bool inSubnet 
= necp_is_addr_in_subnet((struct sockaddr 
*)remote
, (struct sockaddr 
*)&kernel_policy
->cond_remote_start
, kernel_policy
->cond_remote_prefix
); 
8673                         if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) { 
8685         if (kernel_policy
->condition_mask 
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) { 
8686                 bool tags_matched 
= false; 
8688                 if (kernel_policy
->cond_packet_filter_tags 
& NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP
) { 
8689                         if ((pf_tag 
& PF_TAG_ID_STACK_DROP
) == PF_TAG_ID_STACK_DROP
) { 
8690                                 tags_matched 
= true; 
8693                         if (kernel_policy
->condition_negated_mask 
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) { 
8698                                 if (!tags_matched
) { 
8708 static inline struct necp_kernel_ip_output_policy 
* 
8709 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
) 
8711         u_int32_t skip_order 
= 0; 
8712         u_int32_t skip_session_order 
= 0; 
8713         struct necp_kernel_ip_output_policy 
*matched_policy 
= NULL
; 
8714         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
)]; 
8715         u_int32_t route_rule_id_array
[MAX_AGGREGATE_ROUTE_RULES
]; 
8716         size_t route_rule_id_count 
= 0; 
8717         necp_drop_all_bypass_check_result_t drop_all_bypass 
= NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
; 
8718         if (return_drop_all_bypass 
!= NULL
) { 
8719                 *return_drop_all_bypass 
= drop_all_bypass
; 
8722         if (return_route_rule_id 
!= NULL
) { 
8723                 *return_route_rule_id 
= 0; 
8726         *return_drop_dest_policy_result 
= NECP_KERNEL_POLICY_RESULT_NONE
; 
8728         if (policy_search_array 
!= NULL
) { 
8729                 for (int i 
= 0; policy_search_array
[i
] != NULL
; i
++) { 
8730                         if (necp_drop_all_order 
!= 0 && policy_search_array
[i
]->session_order 
>= necp_drop_all_order
) { 
8731                                 // We've hit a drop all rule 
8732                                 if (drop_all_bypass 
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
) { 
8733                                         drop_all_bypass 
= necp_check_drop_all_bypass_result(NULL
); 
8734                                         if (return_drop_all_bypass 
!= NULL
) { 
8735                                                 *return_drop_all_bypass 
= drop_all_bypass
; 
8738                                 if (drop_all_bypass 
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
) { 
8742                         if (necp_drop_dest_policy
.entry_count 
> 0 && 
8743                             necp_address_matches_drop_dest_policy(remote_addr
, policy_search_array
[i
]->session_order
)) { 
8744                                 // We've hit a drop by destination address rule 
8745                                 *return_drop_dest_policy_result 
= NECP_KERNEL_POLICY_RESULT_DROP
; 
8748                         if (skip_session_order 
&& policy_search_array
[i
]->session_order 
>= skip_session_order
) { 
8751                                 skip_session_order 
= 0; 
8754                                 if (policy_search_array
[i
]->order 
< skip_order
) { 
8760                                         skip_session_order 
= 0; 
8762                         } else if (skip_session_order
) { 
8767                         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
)) { 
8768                                 if (policy_search_array
[i
]->result 
== NECP_KERNEL_POLICY_RESULT_ROUTE_RULES
) { 
8769                                         if (return_route_rule_id 
!= NULL 
&& route_rule_id_count 
< MAX_AGGREGATE_ROUTE_RULES
) { 
8770                                                 route_rule_id_array
[route_rule_id_count
++] = policy_search_array
[i
]->result_parameter
.route_rule_id
; 
8773                                 } else if (policy_search_array
[i
]->result 
== NECP_KERNEL_POLICY_RESULT_SKIP
) { 
8774                                         skip_order 
= policy_search_array
[i
]->result_parameter
.skip_policy_order
; 
8775                                         skip_session_order 
= policy_search_array
[i
]->session_order 
+ 1; 
8779                                 // Passed all tests, found a match 
8780                                 matched_policy 
= policy_search_array
[i
]; 
8786         if (route_rule_id_count 
== 1) { 
8787                 *return_route_rule_id 
= route_rule_id_array
[0]; 
8788         } else if (route_rule_id_count 
> 1) { 
8789                 *return_route_rule_id 
= necp_create_aggregate_route_rule(route_rule_id_array
); 
8792         return matched_policy
; 
8796 necp_output_bypass(struct mbuf 
*packet
) 
8798         if (necp_pass_loopback 
> 0 && necp_is_loopback(NULL
, NULL
, NULL
, packet
, IFSCOPE_NONE
)) { 
8801         if (necp_pass_keepalives 
> 0 && necp_get_is_keepalive_from_packet(packet
)) { 
8804         if (necp_is_intcoproc(NULL
, packet
)) { 
8810 necp_kernel_policy_id
 
8811 necp_ip_output_find_policy_match(struct mbuf 
*packet
, int flags
, struct ip_out_args 
*ipoa
, struct rtentry 
*rt
, 
8812     necp_kernel_policy_result 
*result
, necp_kernel_policy_result_parameter 
*result_parameter
) 
8814         struct ip 
*ip 
= NULL
; 
8815         int hlen 
= sizeof(struct ip
); 
8816         necp_kernel_policy_id socket_policy_id 
= NECP_KERNEL_POLICY_ID_NONE
; 
8817         necp_kernel_policy_id socket_skip_policy_id 
= NECP_KERNEL_POLICY_ID_NONE
; 
8818         necp_kernel_policy_id matched_policy_id 
= NECP_KERNEL_POLICY_ID_NONE
; 
8819         struct necp_kernel_ip_output_policy 
*matched_policy 
= NULL
; 
8820         u_int16_t protocol 
= 0; 
8821         u_int32_t bound_interface_index 
= 0; 
8822         u_int32_t last_interface_index 
= 0; 
8823         union necp_sockaddr_union local_addr
; 
8824         union necp_sockaddr_union remote_addr
; 
8825         u_int32_t drop_dest_policy_result 
= NECP_KERNEL_POLICY_RESULT_NONE
; 
8826         necp_drop_all_bypass_check_result_t drop_all_bypass 
= NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
; 
8827         u_int16_t pf_tag 
= 0; 
8833         if (result_parameter
) { 
8834                 memset(result_parameter
, 0, sizeof(*result_parameter
)); 
8837         if (packet 
== NULL
) { 
8838                 return NECP_KERNEL_POLICY_ID_NONE
; 
8841         socket_policy_id 
= necp_get_policy_id_from_packet(packet
); 
8842         socket_skip_policy_id 
= necp_get_skip_policy_id_from_packet(packet
); 
8843         pf_tag 
= necp_get_packet_filter_tags_from_packet(packet
); 
8845         // Exit early for an empty list 
8846         // Don't lock. Possible race condition, but we don't want the performance hit. 
8847         if (necp_kernel_ip_output_policies_count 
== 0 || 
8848             (socket_policy_id 
== NECP_KERNEL_POLICY_ID_NONE 
&& necp_kernel_ip_output_policies_non_id_count 
== 0 && necp_drop_dest_policy
.entry_count 
== 0)) { 
8849                 if (necp_drop_all_order 
> 0) { 
8850                         matched_policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
8852                                 if (necp_output_bypass(packet
)) { 
8853                                         *result 
= NECP_KERNEL_POLICY_RESULT_PASS
; 
8855                                         *result 
= NECP_KERNEL_POLICY_RESULT_DROP
; 
8860                 return matched_policy_id
; 
8863         // Check for loopback exception 
8864         if (necp_output_bypass(packet
)) { 
8865                 matched_policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
8867                         *result 
= NECP_KERNEL_POLICY_RESULT_PASS
; 
8869                 return matched_policy_id
; 
8872         last_interface_index 
= necp_get_last_interface_index_from_packet(packet
); 
8874         // Process packet to get relevant fields 
8875         ip 
= mtod(packet
, struct ip 
*); 
8877         hlen 
= _IP_VHL_HL(ip
->ip_vhl
) << 2; 
8879         hlen 
= ip
->ip_hl 
<< 2; 
8882         protocol 
= ip
->ip_p
; 
8884         if ((flags 
& IP_OUTARGS
) && (ipoa 
!= NULL
) && 
8885             (ipoa
->ipoa_flags 
& IPOAF_BOUND_IF
) && 
8886             ipoa
->ipoa_boundif 
!= IFSCOPE_NONE
) { 
8887                 bound_interface_index 
= ipoa
->ipoa_boundif
; 
8890         local_addr
.sin
.sin_family 
= AF_INET
; 
8891         local_addr
.sin
.sin_len 
= sizeof(struct sockaddr_in
); 
8892         memcpy(&local_addr
.sin
.sin_addr
, &ip
->ip_src
, sizeof(ip
->ip_src
)); 
8894         remote_addr
.sin
.sin_family 
= AF_INET
; 
8895         remote_addr
.sin
.sin_len 
= sizeof(struct sockaddr_in
); 
8896         memcpy(&((struct sockaddr_in 
*)&remote_addr
)->sin_addr
, &ip
->ip_dst
, sizeof(ip
->ip_dst
)); 
8901                 if ((int)(hlen 
+ sizeof(th
)) <= packet
->m_pkthdr
.len
) { 
8902                         m_copydata(packet
, hlen
, sizeof(th
), (u_int8_t 
*)&th
); 
8903                         ((struct sockaddr_in 
*)&local_addr
)->sin_port 
= th
.th_sport
; 
8904                         ((struct sockaddr_in 
*)&remote_addr
)->sin_port 
= th
.th_dport
; 
8910                 if ((int)(hlen 
+ sizeof(uh
)) <= packet
->m_pkthdr
.len
) { 
8911                         m_copydata(packet
, hlen
, sizeof(uh
), (u_int8_t 
*)&uh
); 
8912                         ((struct sockaddr_in 
*)&local_addr
)->sin_port 
= uh
.uh_sport
; 
8913                         ((struct sockaddr_in 
*)&remote_addr
)->sin_port 
= uh
.uh_dport
; 
8918                 ((struct sockaddr_in 
*)&local_addr
)->sin_port 
= 0; 
8919                 ((struct sockaddr_in 
*)&remote_addr
)->sin_port 
= 0; 
8924         // Match packet to policy 
8925         lck_rw_lock_shared(&necp_kernel_policy_lock
); 
8926         u_int32_t route_rule_id 
= 0; 
8927         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
); 
8928         if (matched_policy
) { 
8929                 matched_policy_id 
= matched_policy
->id
; 
8931                         *result 
= matched_policy
->result
; 
8934                 if (result_parameter
) { 
8935                         memcpy(result_parameter
, &matched_policy
->result_parameter
, sizeof(matched_policy
->result_parameter
)); 
8938                 if (route_rule_id 
!= 0 && 
8939                     packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id 
== 0) { 
8940                         packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id 
= route_rule_id
; 
8943                 if (necp_debug 
> 1) { 
8944                         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
); 
8947                 bool drop_all 
= false; 
8949                  * Apply drop-all only to packets which have never matched a primary policy (check 
8950                  * if the packet saved policy id is none or falls within the socket policy id range). 
8952                 if (socket_policy_id 
< NECP_KERNEL_POLICY_ID_FIRST_VALID_IP 
&& 
8953                     (necp_drop_all_order 
> 0 || drop_dest_policy_result 
== NECP_KERNEL_POLICY_RESULT_DROP
)) { 
8955                         if (drop_all_bypass 
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
) { 
8956                                 drop_all_bypass 
= necp_check_drop_all_bypass_result(NULL
); 
8959                 if (drop_all 
&& drop_all_bypass 
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
) { 
8960                         matched_policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
8962                                 *result 
= NECP_KERNEL_POLICY_RESULT_DROP
; 
8964                 } else if (route_rule_id 
!= 0 && 
8965                     packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id 
== 0) { 
8966                         // If we matched a route rule, mark it 
8967                         packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id 
= route_rule_id
; 
8971         lck_rw_done(&necp_kernel_policy_lock
); 
8973         return matched_policy_id
; 
8976 necp_kernel_policy_id
 
8977 necp_ip6_output_find_policy_match(struct mbuf 
*packet
, int flags
, struct ip6_out_args 
*ip6oa
, struct rtentry 
*rt
, 
8978     necp_kernel_policy_result 
*result
, necp_kernel_policy_result_parameter 
*result_parameter
) 
8980         struct ip6_hdr 
*ip6 
= NULL
; 
8983         necp_kernel_policy_id socket_policy_id 
= NECP_KERNEL_POLICY_ID_NONE
; 
8984         necp_kernel_policy_id socket_skip_policy_id 
= NECP_KERNEL_POLICY_ID_NONE
; 
8985         necp_kernel_policy_id matched_policy_id 
= NECP_KERNEL_POLICY_ID_NONE
; 
8986         struct necp_kernel_ip_output_policy 
*matched_policy 
= NULL
; 
8987         u_int16_t protocol 
= 0; 
8988         u_int32_t bound_interface_index 
= 0; 
8989         u_int32_t last_interface_index 
= 0; 
8990         union necp_sockaddr_union local_addr
; 
8991         union necp_sockaddr_union remote_addr
; 
8992         u_int32_t drop_dest_policy_result 
= NECP_KERNEL_POLICY_RESULT_NONE
; 
8993         necp_drop_all_bypass_check_result_t drop_all_bypass 
= NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
; 
8994         u_int16_t pf_tag 
= 0; 
9000         if (result_parameter
) { 
9001                 memset(result_parameter
, 0, sizeof(*result_parameter
)); 
9004         if (packet 
== NULL
) { 
9005                 return NECP_KERNEL_POLICY_ID_NONE
; 
9008         socket_policy_id 
= necp_get_policy_id_from_packet(packet
); 
9009         socket_skip_policy_id 
= necp_get_skip_policy_id_from_packet(packet
); 
9010         pf_tag 
= necp_get_packet_filter_tags_from_packet(packet
); 
9012         // Exit early for an empty list 
9013         // Don't lock. Possible race condition, but we don't want the performance hit. 
9014         if (necp_kernel_ip_output_policies_count 
== 0 || 
9015             (socket_policy_id 
== NECP_KERNEL_POLICY_ID_NONE 
&& necp_kernel_ip_output_policies_non_id_count 
== 0 && necp_drop_dest_policy
.entry_count 
== 0)) { 
9016                 if (necp_drop_all_order 
> 0) { 
9017                         matched_policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
9019                                 if (necp_output_bypass(packet
)) { 
9020                                         *result 
= NECP_KERNEL_POLICY_RESULT_PASS
; 
9022                                         *result 
= NECP_KERNEL_POLICY_RESULT_DROP
; 
9027                 return matched_policy_id
; 
9030         // Check for loopback exception 
9031         if (necp_output_bypass(packet
)) { 
9032                 matched_policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
9034                         *result 
= NECP_KERNEL_POLICY_RESULT_PASS
; 
9036                 return matched_policy_id
; 
9039         last_interface_index 
= necp_get_last_interface_index_from_packet(packet
); 
9041         // Process packet to get relevant fields 
9042         ip6 
= mtod(packet
, struct ip6_hdr 
*); 
9044         if ((flags 
& IPV6_OUTARGS
) && (ip6oa 
!= NULL
) && 
9045             (ip6oa
->ip6oa_flags 
& IP6OAF_BOUND_IF
) && 
9046             ip6oa
->ip6oa_boundif 
!= IFSCOPE_NONE
) { 
9047                 bound_interface_index 
= ip6oa
->ip6oa_boundif
; 
9050         ((struct sockaddr_in6 
*)&local_addr
)->sin6_family 
= AF_INET6
; 
9051         ((struct sockaddr_in6 
*)&local_addr
)->sin6_len 
= sizeof(struct sockaddr_in6
); 
9052         memcpy(&((struct sockaddr_in6 
*)&local_addr
)->sin6_addr
, &ip6
->ip6_src
, sizeof(ip6
->ip6_src
)); 
9054         ((struct sockaddr_in6 
*)&remote_addr
)->sin6_family 
= AF_INET6
; 
9055         ((struct sockaddr_in6 
*)&remote_addr
)->sin6_len 
= sizeof(struct sockaddr_in6
); 
9056         memcpy(&((struct sockaddr_in6 
*)&remote_addr
)->sin6_addr
, &ip6
->ip6_dst
, sizeof(ip6
->ip6_dst
)); 
9058         offset 
= ip6_lasthdr(packet
, 0, IPPROTO_IPV6
, &next
); 
9059         if (offset 
>= 0 && packet
->m_pkthdr
.len 
>= offset
) { 
9064                         if ((int)(offset 
+ sizeof(th
)) <= packet
->m_pkthdr
.len
) { 
9065                                 m_copydata(packet
, offset
, sizeof(th
), (u_int8_t 
*)&th
); 
9066                                 ((struct sockaddr_in6 
*)&local_addr
)->sin6_port 
= th
.th_sport
; 
9067                                 ((struct sockaddr_in6 
*)&remote_addr
)->sin6_port 
= th
.th_dport
; 
9073                         if ((int)(offset 
+ sizeof(uh
)) <= packet
->m_pkthdr
.len
) { 
9074                                 m_copydata(packet
, offset
, sizeof(uh
), (u_int8_t 
*)&uh
); 
9075                                 ((struct sockaddr_in6 
*)&local_addr
)->sin6_port 
= uh
.uh_sport
; 
9076                                 ((struct sockaddr_in6 
*)&remote_addr
)->sin6_port 
= uh
.uh_dport
; 
9081                         ((struct sockaddr_in6 
*)&local_addr
)->sin6_port 
= 0; 
9082                         ((struct sockaddr_in6 
*)&remote_addr
)->sin6_port 
= 0; 
9088         // Match packet to policy 
9089         lck_rw_lock_shared(&necp_kernel_policy_lock
); 
9090         u_int32_t route_rule_id 
= 0; 
9091         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
); 
9092         if (matched_policy
) { 
9093                 matched_policy_id 
= matched_policy
->id
; 
9095                         *result 
= matched_policy
->result
; 
9098                 if (result_parameter
) { 
9099                         memcpy(result_parameter
, &matched_policy
->result_parameter
, sizeof(matched_policy
->result_parameter
)); 
9102                 if (route_rule_id 
!= 0 && 
9103                     packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id 
== 0) { 
9104                         packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id 
= route_rule_id
; 
9107                 if (necp_debug 
> 1) { 
9108                         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
); 
9111                 bool drop_all 
= false; 
9113                  * Apply drop-all only to packets which have never matched a primary policy (check 
9114                  * if the packet saved policy id is none or falls within the socket policy id range). 
9116                 if (socket_policy_id 
< NECP_KERNEL_POLICY_ID_FIRST_VALID_IP 
&& 
9117                     (necp_drop_all_order 
> 0 || drop_dest_policy_result 
== NECP_KERNEL_POLICY_RESULT_DROP
)) { 
9119                         if (drop_all_bypass 
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
) { 
9120                                 drop_all_bypass 
= necp_check_drop_all_bypass_result(NULL
); 
9123                 if (drop_all 
&& drop_all_bypass 
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
) { 
9124                         matched_policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
9126                                 *result 
= NECP_KERNEL_POLICY_RESULT_DROP
; 
9128                 } else if (route_rule_id 
!= 0 && 
9129                     packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id 
== 0) { 
9130                         // If we matched a route rule, mark it 
9131                         packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id 
= route_rule_id
; 
9135         lck_rw_done(&necp_kernel_policy_lock
); 
9137         return matched_policy_id
; 
9142 necp_is_addr_in_range(struct sockaddr 
*addr
, struct sockaddr 
*range_start
, struct sockaddr 
*range_end
) 
9146         if (addr 
== NULL 
|| range_start 
== NULL 
|| range_end 
== NULL
) { 
9150         /* Must be greater than or equal to start */ 
9151         cmp 
= necp_addr_compare(addr
, range_start
, 1); 
9152         if (cmp 
!= 0 && cmp 
!= 1) { 
9156         /* Must be less than or equal to end */ 
9157         cmp 
= necp_addr_compare(addr
, range_end
, 1); 
9158         if (cmp 
!= 0 && cmp 
!= -1) { 
9166 necp_is_range_in_range(struct sockaddr 
*inner_range_start
, struct sockaddr 
*inner_range_end
, struct sockaddr 
*range_start
, struct sockaddr 
*range_end
) 
9170         if (inner_range_start 
== NULL 
|| inner_range_end 
== NULL 
|| range_start 
== NULL 
|| range_end 
== NULL
) { 
9174         /* Must be greater than or equal to start */ 
9175         cmp 
= necp_addr_compare(inner_range_start
, range_start
, 1); 
9176         if (cmp 
!= 0 && cmp 
!= 1) { 
9180         /* Must be less than or equal to end */ 
9181         cmp 
= necp_addr_compare(inner_range_end
, range_end
, 1); 
9182         if (cmp 
!= 0 && cmp 
!= -1) { 
9190 necp_is_addr_in_subnet(struct sockaddr 
*addr
, struct sockaddr 
*subnet_addr
, u_int8_t subnet_prefix
) 
9192         if (addr 
== NULL 
|| subnet_addr 
== NULL
) { 
9196         if (addr
->sa_family 
!= subnet_addr
->sa_family 
|| addr
->sa_len 
!= subnet_addr
->sa_len
) { 
9200         switch (addr
->sa_family
) { 
9202                 if (satosin(subnet_addr
)->sin_port 
!= 0 && 
9203                     satosin(addr
)->sin_port 
!= satosin(subnet_addr
)->sin_port
) { 
9206                 return necp_buffer_compare_with_bit_prefix((u_int8_t 
*)&satosin(addr
)->sin_addr
, (u_int8_t 
*)&satosin(subnet_addr
)->sin_addr
, subnet_prefix
); 
9209                 if (satosin6(subnet_addr
)->sin6_port 
!= 0 && 
9210                     satosin6(addr
)->sin6_port 
!= satosin6(subnet_addr
)->sin6_port
) { 
9213                 if (satosin6(addr
)->sin6_scope_id 
&& 
9214                     satosin6(subnet_addr
)->sin6_scope_id 
&& 
9215                     satosin6(addr
)->sin6_scope_id 
!= satosin6(subnet_addr
)->sin6_scope_id
) { 
9218                 return necp_buffer_compare_with_bit_prefix((u_int8_t 
*)&satosin6(addr
)->sin6_addr
, (u_int8_t 
*)&satosin6(subnet_addr
)->sin6_addr
, subnet_prefix
); 
9233  * 2: Not comparable or error 
9236 necp_addr_compare(struct sockaddr 
*sa1
, struct sockaddr 
*sa2
, int check_port
) 
9239         int port_result 
= 0; 
9241         if (sa1
->sa_family 
!= sa2
->sa_family 
|| sa1
->sa_len 
!= sa2
->sa_len
) { 
9245         if (sa1
->sa_len 
== 0) { 
9249         switch (sa1
->sa_family
) { 
9251                 if (sa1
->sa_len 
!= sizeof(struct sockaddr_in
)) { 
9255                 result 
= memcmp(&satosin(sa1
)->sin_addr
.s_addr
, &satosin(sa2
)->sin_addr
.s_addr
, sizeof(satosin(sa1
)->sin_addr
.s_addr
)); 
9258                         if (satosin(sa1
)->sin_port 
< satosin(sa2
)->sin_port
) { 
9260                         } else if (satosin(sa1
)->sin_port 
> satosin(sa2
)->sin_port
) { 
9265                                 result 
= port_result
; 
9266                         } else if ((result 
> 0 && port_result 
< 0) || (result 
< 0 && port_result 
> 0)) { 
9274                 if (sa1
->sa_len 
!= sizeof(struct sockaddr_in6
)) { 
9278                 if (satosin6(sa1
)->sin6_scope_id 
!= satosin6(sa2
)->sin6_scope_id
) { 
9282                 result 
= memcmp(&satosin6(sa1
)->sin6_addr
.s6_addr
[0], &satosin6(sa2
)->sin6_addr
.s6_addr
[0], sizeof(struct in6_addr
)); 
9285                         if (satosin6(sa1
)->sin6_port 
< satosin6(sa2
)->sin6_port
) { 
9287                         } else if (satosin6(sa1
)->sin6_port 
> satosin6(sa2
)->sin6_port
) { 
9292                                 result 
= port_result
; 
9293                         } else if ((result 
> 0 && port_result 
< 0) || (result 
< 0 && port_result 
> 0)) { 
9301                 result 
= memcmp(sa1
, sa2
, sa1
->sa_len
); 
9308         } else if (result 
> 0) { 
9316 necp_buffer_compare_with_bit_prefix(u_int8_t 
*p1
, u_int8_t 
*p2
, u_int32_t bits
) 
9320         /* Handle null pointers */ 
9321         if (p1 
== NULL 
|| p2 
== NULL
) { 
9326                 if (*p1
++ != *p2
++) { 
9333                 mask 
= ~((1 << (8 - bits
)) - 1); 
9334                 if ((*p1 
& mask
) != (*p2 
& mask
)) { 
9342 necp_addr_is_empty(struct sockaddr 
*addr
) 
9348         if (addr
->sa_len 
== 0) { 
9352         switch (addr
->sa_family
) { 
9354                 static struct sockaddr_in ipv4_empty_address 
= { 
9355                         .sin_len 
= sizeof(struct sockaddr_in
), 
9356                         .sin_family 
= AF_INET
, 
9358                         .sin_addr 
= { .s_addr 
= 0 }, // 0.0.0.0 
9361                 if (necp_addr_compare(addr
, (struct sockaddr 
*)&ipv4_empty_address
, 0) == 0) { 
9368                 static struct sockaddr_in6 ipv6_empty_address 
= { 
9369                         .sin6_len 
= sizeof(struct sockaddr_in6
), 
9370                         .sin6_family 
= AF_INET6
, 
9373                         .sin6_addr 
= IN6ADDR_ANY_INIT
, // :: 
9376                 if (necp_addr_compare(addr
, (struct sockaddr 
*)&ipv6_empty_address
, 0) == 0) { 
9390 necp_update_qos_marking(struct ifnet 
*ifp
, u_int32_t route_rule_id
) 
9392         bool qos_marking 
= FALSE
; 
9393         int exception_index 
= 0; 
9394         struct necp_route_rule 
*route_rule 
= NULL
; 
9396         route_rule 
= necp_lookup_route_rule_locked(&necp_route_rules
, route_rule_id
); 
9397         if (route_rule 
== NULL
) { 
9398                 qos_marking 
= FALSE
; 
9402         qos_marking 
= (route_rule
->default_action 
== NECP_ROUTE_RULE_QOS_MARKING
) ? TRUE 
: FALSE
; 
9408         for (exception_index 
= 0; exception_index 
< MAX_ROUTE_RULE_INTERFACES
; exception_index
++) { 
9409                 if (route_rule
->exception_if_indices
[exception_index
] == 0) { 
9412                 if (route_rule
->exception_if_actions
[exception_index
] != NECP_ROUTE_RULE_QOS_MARKING
) { 
9415                 if (route_rule
->exception_if_indices
[exception_index
] == ifp
->if_index
) { 
9417                         if (necp_debug 
> 2) { 
9418                                 NECPLOG(LOG_DEBUG
, "QoS Marking : Interface match %d for Rule %d Allowed %d", 
9419                                     route_rule
->exception_if_indices
[exception_index
], route_rule_id
, qos_marking
); 
9425         if ((route_rule
->cellular_action 
== NECP_ROUTE_RULE_QOS_MARKING 
&& IFNET_IS_CELLULAR(ifp
)) || 
9426             (route_rule
->wifi_action 
== NECP_ROUTE_RULE_QOS_MARKING 
&& IFNET_IS_WIFI(ifp
)) || 
9427             (route_rule
->wired_action 
== NECP_ROUTE_RULE_QOS_MARKING 
&& IFNET_IS_WIRED(ifp
)) || 
9428             (route_rule
->expensive_action 
== NECP_ROUTE_RULE_QOS_MARKING 
&& IFNET_IS_EXPENSIVE(ifp
)) || 
9429             (route_rule
->constrained_action 
== NECP_ROUTE_RULE_QOS_MARKING 
&& IFNET_IS_CONSTRAINED(ifp
))) { 
9431                 if (necp_debug 
> 2) { 
9432                         NECPLOG(LOG_DEBUG
, "QoS Marking: C:%d WF:%d W:%d E:%d Cn:%d for Rule %d Allowed %d", 
9433                             route_rule
->cellular_action
, route_rule
->wifi_action
, route_rule
->wired_action
, 
9434                             route_rule
->expensive_action
, route_rule
->constrained_action
, route_rule_id
, qos_marking
); 
9439         if (necp_debug 
> 1) { 
9440                 NECPLOG(LOG_DEBUG
, "QoS Marking: Rule %d ifp %s Allowed %d", 
9441                     route_rule_id
, ifp 
? ifp
->if_xname 
: "", qos_marking
); 
9447 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
) 
9449         bool new_qos_marking 
= old_qos_marking
; 
9450         struct ifnet 
*ifp 
= interface
; 
9452         if (net_qos_policy_restricted 
== 0) { 
9453                 return new_qos_marking
; 
9457          * This is racy but we do not need the performance hit of taking necp_kernel_policy_lock 
9459         if (*qos_marking_gencount 
== necp_kernel_socket_policies_gencount
) { 
9460                 return new_qos_marking
; 
9463         lck_rw_lock_shared(&necp_kernel_policy_lock
); 
9465         if (ifp 
== NULL 
&& route 
!= NULL
) { 
9466                 ifp 
= route
->rt_ifp
; 
9469          * By default, until we have a interface, do not mark and reevaluate the Qos marking policy 
9471         if (ifp 
== NULL 
|| route_rule_id 
== 0) { 
9472                 new_qos_marking 
= FALSE
; 
9476         if (ROUTE_RULE_IS_AGGREGATE(route_rule_id
)) { 
9477                 struct necp_aggregate_route_rule 
*aggregate_route_rule 
= necp_lookup_aggregate_route_rule_locked(route_rule_id
); 
9478                 if (aggregate_route_rule 
!= NULL
) { 
9480                         for (index 
= 0; index 
< MAX_AGGREGATE_ROUTE_RULES
; index
++) { 
9481                                 u_int32_t sub_route_rule_id 
= aggregate_route_rule
->rule_ids
[index
]; 
9482                                 if (sub_route_rule_id 
== 0) { 
9485                                 new_qos_marking 
= necp_update_qos_marking(ifp
, sub_route_rule_id
); 
9486                                 if (new_qos_marking 
== TRUE
) { 
9492                 new_qos_marking 
= necp_update_qos_marking(ifp
, route_rule_id
); 
9495          * Now that we have an interface we remember the gencount 
9497         *qos_marking_gencount 
= necp_kernel_socket_policies_gencount
; 
9500         lck_rw_done(&necp_kernel_policy_lock
); 
9501         return new_qos_marking
; 
9505 necp_socket_update_qos_marking(struct inpcb 
*inp
, struct rtentry 
*route
, u_int32_t route_rule_id
) 
9507         bool qos_marking 
= inp
->inp_socket
->so_flags1 
& SOF1_QOSMARKING_ALLOWED 
? TRUE 
: FALSE
; 
9509         if (net_qos_policy_restricted 
== 0) { 
9512         if (inp
->inp_socket 
== NULL
) { 
9515         if ((inp
->inp_socket
->so_flags1 
& SOF1_QOSMARKING_POLICY_OVERRIDE
)) { 
9519         qos_marking 
= necp_lookup_current_qos_marking(&(inp
->inp_policyresult
.results
.qos_marking_gencount
), route
, NULL
, route_rule_id
, qos_marking
); 
9521         if (qos_marking 
== TRUE
) { 
9522                 inp
->inp_socket
->so_flags1 
|= SOF1_QOSMARKING_ALLOWED
; 
9524                 inp
->inp_socket
->so_flags1 
&= ~SOF1_QOSMARKING_ALLOWED
; 
9529 necp_route_is_lqm_abort(struct ifnet 
*ifp
, struct ifnet 
*delegated_ifp
) 
9532             (ifp
->if_interface_state
.valid_bitmask 
& IF_INTERFACE_STATE_LQM_STATE_VALID
) && 
9533             ifp
->if_interface_state
.lqm_state 
== IFNET_LQM_THRESH_ABORT
) { 
9536         if (delegated_ifp 
!= NULL 
&& 
9537             (delegated_ifp
->if_interface_state
.valid_bitmask 
& IF_INTERFACE_STATE_LQM_STATE_VALID
) && 
9538             delegated_ifp
->if_interface_state
.lqm_state 
== IFNET_LQM_THRESH_ABORT
) { 
9545 necp_route_is_allowed_inner(struct rtentry 
*route
, struct ifnet 
*ifp
, u_int32_t route_rule_id
, u_int32_t 
*interface_type_denied
) 
9547         bool default_is_allowed 
= TRUE
; 
9548         u_int8_t type_aggregate_action 
= NECP_ROUTE_RULE_NONE
; 
9549         int exception_index 
= 0; 
9550         struct ifnet 
*delegated_ifp 
= NULL
; 
9551         struct necp_route_rule 
*route_rule 
= NULL
; 
9553         route_rule 
= necp_lookup_route_rule_locked(&necp_route_rules
, route_rule_id
); 
9554         if (route_rule 
== NULL
) { 
9558         default_is_allowed 
= (route_rule
->default_action 
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? FALSE 
: TRUE
; 
9560                 ifp 
= route
->rt_ifp
; 
9563                 if (necp_debug 
> 1 && !default_is_allowed
) { 
9564                         NECPLOG(LOG_DEBUG
, "Route Allowed: No interface for route, using default for Rule %d Allowed %d", route_rule_id
, default_is_allowed
); 
9566                 return default_is_allowed
; 
9569         delegated_ifp 
= ifp
->if_delegated
.ifp
; 
9570         for (exception_index 
= 0; exception_index 
< MAX_ROUTE_RULE_INTERFACES
; exception_index
++) { 
9571                 if (route_rule
->exception_if_indices
[exception_index
] == 0) { 
9574                 if (route_rule
->exception_if_indices
[exception_index
] == ifp
->if_index 
|| 
9575                     (delegated_ifp 
!= NULL 
&& route_rule
->exception_if_indices
[exception_index
] == delegated_ifp
->if_index
)) { 
9576                         if (route_rule
->exception_if_actions
[exception_index
] == NECP_ROUTE_RULE_DENY_LQM_ABORT
) { 
9577                                 const bool lqm_abort 
= necp_route_is_lqm_abort(ifp
, delegated_ifp
); 
9578                                 if (necp_debug 
> 1 && lqm_abort
) { 
9579                                         NECPLOG(LOG_DEBUG
, "Route Allowed: Interface match %d for Rule %d Deny LQM Abort", 
9580                                             route_rule
->exception_if_indices
[exception_index
], route_rule_id
); 
9583                         } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->exception_if_actions
[exception_index
])) { 
9584                                 if (necp_debug 
> 1) { 
9585                                         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
)); 
9587                                 return (route_rule
->exception_if_actions
[exception_index
] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? FALSE 
: TRUE
; 
9592         if (IFNET_IS_CELLULAR(ifp
)) { 
9593                 if (route_rule
->cellular_action 
== NECP_ROUTE_RULE_DENY_LQM_ABORT
) { 
9594                         if (necp_route_is_lqm_abort(ifp
, delegated_ifp
)) { 
9595                                 if (interface_type_denied 
!= NULL
) { 
9596                                         *interface_type_denied 
= IFRTYPE_FUNCTIONAL_CELLULAR
; 
9598                                 // Mark aggregate action as deny 
9599                                 type_aggregate_action 
= NECP_ROUTE_RULE_DENY_INTERFACE
; 
9601                 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->cellular_action
)) { 
9602                         if (interface_type_denied 
!= NULL
) { 
9603                                 *interface_type_denied 
= IFRTYPE_FUNCTIONAL_CELLULAR
; 
9605                         if (type_aggregate_action 
== NECP_ROUTE_RULE_NONE 
|| 
9606                             (type_aggregate_action 
== NECP_ROUTE_RULE_ALLOW_INTERFACE 
&& 
9607                             route_rule
->cellular_action 
== NECP_ROUTE_RULE_DENY_INTERFACE
)) { 
9608                                 // Deny wins if there is a conflict 
9609                                 type_aggregate_action 
= route_rule
->cellular_action
; 
9614         if (IFNET_IS_WIFI(ifp
)) { 
9615                 if (route_rule
->wifi_action 
== NECP_ROUTE_RULE_DENY_LQM_ABORT
) { 
9616                         if (necp_route_is_lqm_abort(ifp
, delegated_ifp
)) { 
9617                                 if (interface_type_denied 
!= NULL
) { 
9618                                         *interface_type_denied 
= IFRTYPE_FUNCTIONAL_WIFI_INFRA
; 
9620                                 // Mark aggregate action as deny 
9621                                 type_aggregate_action 
= NECP_ROUTE_RULE_DENY_INTERFACE
; 
9623                 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->wifi_action
)) { 
9624                         if (interface_type_denied 
!= NULL
) { 
9625                                 *interface_type_denied 
= IFRTYPE_FUNCTIONAL_WIFI_INFRA
; 
9627                         if (type_aggregate_action 
== NECP_ROUTE_RULE_NONE 
|| 
9628                             (type_aggregate_action 
== NECP_ROUTE_RULE_ALLOW_INTERFACE 
&& 
9629                             route_rule
->wifi_action 
== NECP_ROUTE_RULE_DENY_INTERFACE
)) { 
9630                                 // Deny wins if there is a conflict 
9631                                 type_aggregate_action 
= route_rule
->wifi_action
; 
9636         if (IFNET_IS_WIRED(ifp
)) { 
9637                 if (route_rule
->wired_action 
== NECP_ROUTE_RULE_DENY_LQM_ABORT
) { 
9638                         if (necp_route_is_lqm_abort(ifp
, delegated_ifp
)) { 
9639                                 if (interface_type_denied 
!= NULL
) { 
9640                                         *interface_type_denied 
= IFRTYPE_FUNCTIONAL_WIRED
; 
9642                                 // Mark aggregate action as deny 
9643                                 type_aggregate_action 
= NECP_ROUTE_RULE_DENY_INTERFACE
; 
9645                 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->wired_action
)) { 
9646                         if (interface_type_denied 
!= NULL
) { 
9647                                 *interface_type_denied 
= IFRTYPE_FUNCTIONAL_WIRED
; 
9649                         if (type_aggregate_action 
== NECP_ROUTE_RULE_NONE 
|| 
9650                             (type_aggregate_action 
== NECP_ROUTE_RULE_ALLOW_INTERFACE 
&& 
9651                             route_rule
->wired_action 
== NECP_ROUTE_RULE_DENY_INTERFACE
)) { 
9652                                 // Deny wins if there is a conflict 
9653                                 type_aggregate_action 
= route_rule
->wired_action
; 
9658         if (IFNET_IS_EXPENSIVE(ifp
)) { 
9659                 if (route_rule
->expensive_action 
== NECP_ROUTE_RULE_DENY_LQM_ABORT
) { 
9660                         if (necp_route_is_lqm_abort(ifp
, delegated_ifp
)) { 
9661                                 // Mark aggregate action as deny 
9662                                 type_aggregate_action 
= NECP_ROUTE_RULE_DENY_INTERFACE
; 
9664                 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->expensive_action
)) { 
9665                         if (type_aggregate_action 
== NECP_ROUTE_RULE_NONE 
|| 
9666                             (type_aggregate_action 
== NECP_ROUTE_RULE_ALLOW_INTERFACE 
&& 
9667                             route_rule
->expensive_action 
== NECP_ROUTE_RULE_DENY_INTERFACE
)) { 
9668                                 // Deny wins if there is a conflict 
9669                                 type_aggregate_action 
= route_rule
->expensive_action
; 
9674         if (IFNET_IS_CONSTRAINED(ifp
)) { 
9675                 if (route_rule
->constrained_action 
== NECP_ROUTE_RULE_DENY_LQM_ABORT
) { 
9676                         if (necp_route_is_lqm_abort(ifp
, delegated_ifp
)) { 
9677                                 // Mark aggregate action as deny 
9678                                 type_aggregate_action 
= NECP_ROUTE_RULE_DENY_INTERFACE
; 
9680                 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->constrained_action
)) { 
9681                         if (type_aggregate_action 
== NECP_ROUTE_RULE_NONE 
|| 
9682                             (type_aggregate_action 
== NECP_ROUTE_RULE_ALLOW_INTERFACE 
&& 
9683                             route_rule
->constrained_action 
== NECP_ROUTE_RULE_DENY_INTERFACE
)) { 
9684                                 // Deny wins if there is a conflict 
9685                                 type_aggregate_action 
= route_rule
->constrained_action
; 
9690         if (type_aggregate_action 
!= NECP_ROUTE_RULE_NONE
) { 
9691                 if (necp_debug 
> 1) { 
9692                         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
)); 
9694                 return (type_aggregate_action 
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? FALSE 
: TRUE
; 
9697         if (necp_debug 
> 1 && !default_is_allowed
) { 
9698                 NECPLOG(LOG_DEBUG
, "Route Allowed: Using default for Rule %d Allowed %d", route_rule_id
, default_is_allowed
); 
9700         return default_is_allowed
; 
9704 necp_route_is_allowed(struct rtentry 
*route
, struct ifnet 
*interface
, u_int32_t route_rule_id
, u_int32_t 
*interface_type_denied
) 
9706         if ((route 
== NULL 
&& interface 
== NULL
) || route_rule_id 
== 0) { 
9707                 if (necp_debug 
> 1) { 
9708                         NECPLOG(LOG_DEBUG
, "Route Allowed: no route or interface, Rule %d Allowed %d", route_rule_id
, TRUE
); 
9713         if (ROUTE_RULE_IS_AGGREGATE(route_rule_id
)) { 
9714                 struct necp_aggregate_route_rule 
*aggregate_route_rule 
= necp_lookup_aggregate_route_rule_locked(route_rule_id
); 
9715                 if (aggregate_route_rule 
!= NULL
) { 
9717                         for (index 
= 0; index 
< MAX_AGGREGATE_ROUTE_RULES
; index
++) { 
9718                                 u_int32_t sub_route_rule_id 
= aggregate_route_rule
->rule_ids
[index
]; 
9719                                 if (sub_route_rule_id 
== 0) { 
9722                                 if (!necp_route_is_allowed_inner(route
, interface
, sub_route_rule_id
, interface_type_denied
)) { 
9728                 return necp_route_is_allowed_inner(route
, interface
, route_rule_id
, interface_type_denied
); 
9735 necp_route_get_netagent(struct rtentry 
*route
, u_int32_t route_rule_id
) 
9737         if (route 
== NULL
) { 
9741         struct ifnet 
*ifp 
= route
->rt_ifp
; 
9746         struct necp_route_rule 
*route_rule 
= necp_lookup_route_rule_locked(&necp_route_rules
, route_rule_id
); 
9747         if (route_rule 
== NULL
) { 
9751         // No netagent, skip 
9752         if (route_rule
->netagent_id 
== 0) { 
9756         if (route_rule
->default_action 
== NECP_ROUTE_RULE_USE_NETAGENT
) { 
9757                 return route_rule
->netagent_id
; 
9760         for (int exception_index 
= 0; exception_index 
< MAX_ROUTE_RULE_INTERFACES
; exception_index
++) { 
9761                 if (route_rule
->exception_if_indices
[exception_index
] == 0) { 
9764                 if (route_rule
->exception_if_indices
[exception_index
] == ifp
->if_index 
&& 
9765                     route_rule
->exception_if_actions
[exception_index
] == NECP_ROUTE_RULE_USE_NETAGENT
) { 
9766                         return route_rule
->netagent_id
; 
9770         if (route_rule
->cellular_action 
== NECP_ROUTE_RULE_USE_NETAGENT 
&& 
9771             ifp
->if_type 
== IFT_CELLULAR
) { 
9772                 return route_rule
->netagent_id
; 
9775         if (route_rule
->wifi_action 
== NECP_ROUTE_RULE_USE_NETAGENT 
&& 
9776             ifp
->if_family 
== IFNET_FAMILY_ETHERNET 
&& ifp
->if_subfamily 
== IFNET_SUBFAMILY_WIFI
) { 
9777                 return route_rule
->netagent_id
; 
9780         if (route_rule
->wired_action 
== NECP_ROUTE_RULE_USE_NETAGENT 
&& 
9781             (ifp
->if_family 
== IFNET_FAMILY_ETHERNET 
|| ifp
->if_family 
== IFNET_FAMILY_FIREWIRE
)) { 
9782                 return route_rule
->netagent_id
; 
9785         if (route_rule
->expensive_action 
== NECP_ROUTE_RULE_USE_NETAGENT 
&& 
9786             ifp
->if_eflags 
& IFEF_EXPENSIVE
) { 
9787                 return route_rule
->netagent_id
; 
9790         if (route_rule
->constrained_action 
== NECP_ROUTE_RULE_USE_NETAGENT 
&& 
9791             ifp
->if_xflags 
& IFXF_CONSTRAINED
) { 
9792                 return route_rule
->netagent_id
; 
9799 necp_packet_is_allowed_over_interface(struct mbuf 
*packet
, struct ifnet 
*interface
) 
9801         bool is_allowed 
= TRUE
; 
9802         u_int32_t route_rule_id 
= necp_get_route_rule_id_from_packet(packet
); 
9803         if (route_rule_id 
!= 0 && 
9804             interface 
!= NULL
) { 
9805                 lck_rw_lock_shared(&necp_kernel_policy_lock
); 
9806                 is_allowed 
= necp_route_is_allowed(NULL
, interface
, necp_get_route_rule_id_from_packet(packet
), NULL
); 
9807                 lck_rw_done(&necp_kernel_policy_lock
); 
9813 necp_netagents_allow_traffic(u_int32_t 
*netagent_ids
, size_t netagent_id_count
) 
9815         size_t netagent_cursor
; 
9816         for (netagent_cursor 
= 0; netagent_cursor 
< netagent_id_count
; netagent_cursor
++) { 
9817                 struct necp_uuid_id_mapping 
*mapping 
= NULL
; 
9818                 u_int32_t netagent_id 
= netagent_ids
[netagent_cursor
]; 
9819                 if (netagent_id 
== 0) { 
9822                 mapping 
= necp_uuid_lookup_uuid_with_service_id_locked(netagent_id
); 
9823                 if (mapping 
!= NULL
) { 
9824                         u_int32_t agent_flags 
= 0; 
9825                         agent_flags 
= netagent_get_flags(mapping
->uuid
); 
9826                         if (agent_flags 
& NETAGENT_FLAG_REGISTERED
) { 
9827                                 if (agent_flags 
& NETAGENT_FLAG_ACTIVE
) { 
9829                                 } else if ((agent_flags 
& NETAGENT_FLAG_VOLUNTARY
) == 0) { 
9839 necp_packet_filter_tags_receive(u_int16_t pf_tag
, u_int32_t pass_flags
) 
9841         bool allowed_to_receive 
= TRUE
; 
9843         if (pf_tag 
== PF_TAG_ID_STACK_DROP 
&& 
9844             (pass_flags 
& NECP_KERNEL_POLICY_PASS_PF_TAG
) != NECP_KERNEL_POLICY_PASS_PF_TAG
) { 
9845                 allowed_to_receive 
= FALSE
; 
9848         return allowed_to_receive
; 
9852 necp_socket_is_allowed_to_send_recv_internal(struct inpcb 
*inp
, struct sockaddr 
*override_local_addr
, struct sockaddr 
*override_remote_addr
, ifnet_t input_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
) 
9854         u_int32_t verifyifindex 
= input_interface 
? input_interface
->if_index 
: 0; 
9855         bool allowed_to_receive 
= TRUE
; 
9856         struct necp_socket_info info
; 
9857         u_int32_t flowhash 
= 0; 
9858         necp_kernel_policy_result service_action 
= 0; 
9859         necp_kernel_policy_service service 
= { 0, 0 }; 
9860         u_int32_t route_rule_id 
= 0; 
9861         struct rtentry 
*route 
= NULL
; 
9862         u_int32_t interface_type_denied 
= IFRTYPE_FUNCTIONAL_UNKNOWN
; 
9863         necp_kernel_policy_result drop_dest_policy_result 
= NECP_KERNEL_POLICY_RESULT_NONE
; 
9864         necp_drop_all_bypass_check_result_t drop_all_bypass 
= NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
; 
9865         u_int32_t netagent_ids
[NECP_MAX_NETAGENTS
]; 
9866         proc_t socket_proc 
= NULL
; 
9867         necp_kernel_policy_filter filter_control_unit 
= 0; 
9868         u_int32_t pass_flags 
= 0; 
9869         u_int32_t flow_divert_aggregate_unit 
= 0; 
9870         necp_socket_bypass_type_t bypass_type 
= NECP_BYPASS_TYPE_NONE
; 
9872         memset(&netagent_ids
, 0, sizeof(netagent_ids
)); 
9874         if (return_policy_id
) { 
9875                 *return_policy_id 
= NECP_KERNEL_POLICY_ID_NONE
; 
9877         if (return_skip_policy_id
) { 
9878                 *return_skip_policy_id 
= NECP_KERNEL_POLICY_ID_NONE
; 
9880         if (return_route_rule_id
) { 
9881                 *return_route_rule_id 
= 0; 
9883         if (return_pass_flags
) { 
9884                 *return_pass_flags 
= 0; 
9891         route 
= inp
->inp_route
.ro_rt
; 
9893         struct socket 
*so 
= inp
->inp_socket
; 
9895         u_int32_t drop_order 
= necp_process_drop_order(so
->so_cred
); 
9897         // Don't lock. Possible race condition, but we don't want the performance hit. 
9898         if (necp_kernel_socket_policies_count 
== 0 || 
9899             (!(inp
->inp_flags2 
& INP2_WANT_APP_POLICY
) && necp_kernel_socket_policies_non_app_count 
== 0)) { 
9900                 if (necp_drop_all_order 
> 0 || drop_order 
> 0) { 
9901                         if (necp_socket_bypass(override_local_addr
, override_remote_addr
, inp
) != NECP_BYPASS_TYPE_NONE
) { 
9902                                 allowed_to_receive 
= TRUE
; 
9904                                 allowed_to_receive 
= FALSE
; 
9910         // If this socket is connected, or we are not taking addresses into account, try to reuse last result 
9911         if ((necp_socket_is_connected(inp
) || (override_local_addr 
== NULL 
&& override_remote_addr 
== NULL
)) && inp
->inp_policyresult
.policy_id 
!= NECP_KERNEL_POLICY_ID_NONE
) { 
9912                 bool policies_have_changed 
= FALSE
; 
9913                 bool route_allowed 
= TRUE
; 
9915                 if (inp
->inp_policyresult
.policy_gencount 
!= necp_kernel_socket_policies_gencount
) { 
9916                         policies_have_changed 
= TRUE
; 
9918                         if (inp
->inp_policyresult
.results
.route_rule_id 
!= 0) { 
9919                                 lck_rw_lock_shared(&necp_kernel_policy_lock
); 
9920                                 if (!necp_route_is_allowed(route
, input_interface
, inp
->inp_policyresult
.results
.route_rule_id
, &interface_type_denied
)) { 
9921                                         route_allowed 
= FALSE
; 
9923                                 lck_rw_done(&necp_kernel_policy_lock
); 
9927                 if (!policies_have_changed
) { 
9928                         if (!route_allowed 
|| 
9929                             inp
->inp_policyresult
.results
.result 
== NECP_KERNEL_POLICY_RESULT_DROP 
|| 
9930                             inp
->inp_policyresult
.results
.result 
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT 
|| 
9931                             (inp
->inp_policyresult
.results
.result 
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL 
&& input_interface 
&& 
9932                             inp
->inp_policyresult
.results
.result_parameter
.tunnel_interface_index 
!= verifyifindex
)) { 
9933                                 allowed_to_receive 
= FALSE
; 
9935                                 if (return_policy_id
) { 
9936                                         *return_policy_id 
= inp
->inp_policyresult
.policy_id
; 
9938                                 if (return_skip_policy_id
) { 
9939                                         *return_skip_policy_id 
= inp
->inp_policyresult
.skip_policy_id
; 
9941                                 if (return_route_rule_id
) { 
9942                                         *return_route_rule_id 
= inp
->inp_policyresult
.results
.route_rule_id
; 
9944                                 if (inp
->inp_policyresult
.results
.result 
== NECP_KERNEL_POLICY_RESULT_PASS
) { 
9945                                         pass_flags 
= inp
->inp_policyresult
.results
.result_parameter
.pass_flags
; 
9952         // Check for loopback exception 
9953         bypass_type 
= necp_socket_bypass(override_local_addr
, override_remote_addr
, inp
); 
9954         if (bypass_type 
== NECP_BYPASS_TYPE_INTCOPROC 
|| (bypass_type 
== NECP_BYPASS_TYPE_LOOPBACK 
&& necp_pass_loopback 
== NECP_LOOPBACK_PASS_ALL
)) { 
9955                 allowed_to_receive 
= TRUE
; 
9959         // Actually calculate policy result 
9960         lck_rw_lock_shared(&necp_kernel_policy_lock
); 
9961         necp_socket_fillout_info_locked(inp
, override_local_addr
, override_remote_addr
, 0, input_interface 
!= NULL 
? true : false, drop_order
, &socket_proc
, &info
, (bypass_type 
== NECP_BYPASS_TYPE_LOOPBACK
)); 
9963         flowhash 
= necp_socket_calc_flowhash_locked(&info
); 
9964         if (inp
->inp_policyresult
.policy_id 
!= NECP_KERNEL_POLICY_ID_NONE 
&& 
9965             inp
->inp_policyresult
.policy_gencount 
== necp_kernel_socket_policies_gencount 
&& 
9966             inp
->inp_policyresult
.flowhash 
== flowhash
) { 
9967                 if (inp
->inp_policyresult
.results
.result 
== NECP_KERNEL_POLICY_RESULT_DROP 
|| 
9968                     inp
->inp_policyresult
.results
.result 
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT 
|| 
9969                     (inp
->inp_policyresult
.results
.result 
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL 
&& input_interface 
&& 
9970                     inp
->inp_policyresult
.results
.result_parameter
.tunnel_interface_index 
!= verifyifindex
) || 
9971                     (inp
->inp_policyresult
.results
.route_rule_id 
!= 0 && 
9972                     !necp_route_is_allowed(route
, input_interface
, inp
->inp_policyresult
.results
.route_rule_id
, &interface_type_denied
))) { 
9973                         allowed_to_receive 
= FALSE
; 
9975                         if (return_policy_id
) { 
9976                                 *return_policy_id 
= inp
->inp_policyresult
.policy_id
; 
9978                         if (return_route_rule_id
) { 
9979                                 *return_route_rule_id 
= inp
->inp_policyresult
.results
.route_rule_id
; 
9981                         if (return_skip_policy_id
) { 
9982                                 *return_skip_policy_id 
= inp
->inp_policyresult
.skip_policy_id
; 
9984                         if (inp
->inp_policyresult
.results
.result 
== NECP_KERNEL_POLICY_RESULT_PASS
) { 
9985                                 pass_flags 
= inp
->inp_policyresult
.results
.result_parameter
.pass_flags
; 
9988                 lck_rw_done(&necp_kernel_policy_lock
); 
9992         u_int32_t route_rule_id_array
[MAX_AGGREGATE_ROUTE_RULES
]; 
9993         size_t route_rule_id_array_count 
= 0; 
9994         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
); 
9996         // Check for loopback exception again after the policy match 
9997         if (bypass_type 
== NECP_BYPASS_TYPE_LOOPBACK 
&& 
9998             necp_pass_loopback 
== NECP_LOOPBACK_PASS_WITH_FILTER 
&& 
9999             (matched_policy 
== NULL 
|| matched_policy
->result 
!= NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
)) { 
10000                 // Polices have changed since last evaluation, update inp result with new filter state 
10001                 if (inp
->inp_policyresult
.results
.filter_control_unit 
!= filter_control_unit
) { 
10002                         inp
->inp_policyresult
.results
.filter_control_unit 
= filter_control_unit
; 
10004                 if (inp
->inp_policyresult
.results
.flow_divert_aggregate_unit 
!= flow_divert_aggregate_unit
) { 
10005                         inp
->inp_policyresult
.results
.flow_divert_aggregate_unit 
= flow_divert_aggregate_unit
; 
10007                 allowed_to_receive 
= TRUE
; 
10008                 lck_rw_done(&necp_kernel_policy_lock
); 
10012         if (route_rule_id_array_count 
== 1) { 
10013                 route_rule_id 
= route_rule_id_array
[0]; 
10014         } else if (route_rule_id_array_count 
> 1) { 
10015                 route_rule_id 
= necp_create_aggregate_route_rule(route_rule_id_array
); 
10018         bool send_local_network_denied_event 
= false; 
10019         if (matched_policy 
!= NULL
) { 
10020                 if (matched_policy
->result 
== NECP_KERNEL_POLICY_RESULT_DROP 
&& 
10021                     matched_policy
->result_parameter
.drop_flags 
& NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK
) { 
10022                         // Trigger the event that we dropped due to a local network policy 
10023                         send_local_network_denied_event 
= true; 
10026                 if (matched_policy
->result 
== NECP_KERNEL_POLICY_RESULT_DROP 
|| 
10027                     matched_policy
->result 
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT 
|| 
10028                     (matched_policy
->result 
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL 
&& input_interface 
&& 
10029                     matched_policy
->result_parameter
.tunnel_interface_index 
!= verifyifindex
) || 
10030                     ((service_action 
== NECP_KERNEL_POLICY_RESULT_TRIGGER_SCOPED 
|| 
10031                     service_action 
== NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED
) && 
10032                     service
.identifier 
!= 0 && service
.identifier 
!= NECP_NULL_SERVICE_ID
) || 
10033                     (route_rule_id 
!= 0 && 
10034                     !necp_route_is_allowed(route
, input_interface
, route_rule_id
, &interface_type_denied
)) || 
10035                     !necp_netagents_allow_traffic(netagent_ids
, NECP_MAX_NETAGENTS
)) { 
10036                         allowed_to_receive 
= FALSE
; 
10038                         if (return_policy_id
) { 
10039                                 *return_policy_id 
= matched_policy
->id
; 
10041                         if (return_route_rule_id
) { 
10042                                 *return_route_rule_id 
= route_rule_id
; 
10044                         if (matched_policy
->result 
== NECP_KERNEL_POLICY_RESULT_PASS
) { 
10045                                 pass_flags 
= matched_policy
->result_parameter
.pass_flags
; 
10047                         // Polices has changed since last evaluation, update inp result with new filter state 
10048                         if (inp
->inp_policyresult
.results
.filter_control_unit 
!= filter_control_unit
) { 
10049                                 inp
->inp_policyresult
.results
.filter_control_unit 
= filter_control_unit
; 
10051                         if (inp
->inp_policyresult
.results
.flow_divert_aggregate_unit 
!= flow_divert_aggregate_unit
) { 
10052                                 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit 
= flow_divert_aggregate_unit
; 
10056                 if (necp_debug 
> 1 && matched_policy
->id 
!= inp
->inp_policyresult
.policy_id
) { 
10057                         NECPLOG(LOG_DEBUG
, "Socket Send/Recv Policy: Policy %d Allowed %d", return_policy_id 
? *return_policy_id 
: 0, allowed_to_receive
); 
10060                 bool drop_all 
= false; 
10061                 if (necp_drop_all_order 
> 0 || info
.drop_order 
> 0 || drop_dest_policy_result 
== NECP_KERNEL_POLICY_RESULT_DROP
) { 
10063                         if (drop_all_bypass 
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
) { 
10064                                 drop_all_bypass 
= necp_check_drop_all_bypass_result(socket_proc 
? socket_proc 
: current_proc()); 
10067                 if (drop_all 
&& drop_all_bypass 
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
) { 
10068                         allowed_to_receive 
= FALSE
; 
10070                         if (return_policy_id
) { 
10071                                 *return_policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
10073                         if (return_route_rule_id
) { 
10074                                 *return_route_rule_id 
= route_rule_id
; 
10077                         // Polices has changed since last evaluation, update inp result with new filter state 
10078                         if (inp
->inp_policyresult
.results
.filter_control_unit 
!= filter_control_unit
) { 
10079                                 inp
->inp_policyresult
.results
.filter_control_unit 
= filter_control_unit
; 
10081                         if (inp
->inp_policyresult
.results
.flow_divert_aggregate_unit 
!= flow_divert_aggregate_unit
) { 
10082                                 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit 
= flow_divert_aggregate_unit
; 
10087         if (necp_check_restricted_multicast_drop(socket_proc 
? socket_proc 
: current_proc(), &info
, true)) { 
10088                 allowed_to_receive 
= FALSE
; 
10091         lck_rw_done(&necp_kernel_policy_lock
); 
10093         if (send_local_network_denied_event 
&& inp
->inp_policyresult
.network_denied_notifies 
== 0) { 
10094                 inp
->inp_policyresult
.network_denied_notifies
++; 
10095                 necp_send_network_denied_event(((so
->so_flags 
& SOF_DELEGATED
) ? so
->e_pid 
: so
->last_pid
), 
10096                     ((so
->so_flags 
& SOF_DELEGATED
) ? so
->e_uuid 
: so
->last_uuid
), 
10097                     NETPOLICY_NETWORKTYPE_LOCAL
); 
10101         if (return_pass_flags 
!= NULL
) { 
10102                 *return_pass_flags 
= pass_flags
; 
10105         if (pf_tag 
!= 0 && allowed_to_receive
) { 
10106                 allowed_to_receive 
= necp_packet_filter_tags_receive(pf_tag
, pass_flags
); 
10109         if (!allowed_to_receive 
&& interface_type_denied 
!= IFRTYPE_FUNCTIONAL_UNKNOWN
) { 
10110                 soevent(inp
->inp_socket
, (SO_FILT_HINT_LOCKED 
| SO_FILT_HINT_IFDENIED
)); 
10114                 proc_rele(socket_proc
); 
10117         return allowed_to_receive
; 
10121 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 input_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
) 
10123         struct sockaddr_in local 
= {}; 
10124         struct sockaddr_in remote 
= {}; 
10125         local
.sin_family 
= remote
.sin_family 
= AF_INET
; 
10126         local
.sin_len 
= remote
.sin_len 
= sizeof(struct sockaddr_in
); 
10127         local
.sin_port 
= local_port
; 
10128         remote
.sin_port 
= remote_port
; 
10129         memcpy(&local
.sin_addr
, local_addr
, sizeof(local
.sin_addr
)); 
10130         memcpy(&remote
.sin_addr
, remote_addr
, sizeof(remote
.sin_addr
)); 
10132         return necp_socket_is_allowed_to_send_recv_internal(inp
, (struct sockaddr 
*)&local
, (struct sockaddr 
*)&remote
, input_interface
, 
10133                    pf_tag
, return_policy_id
, return_route_rule_id
, return_skip_policy_id
, return_pass_flags
); 
10137 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 input_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
) 
10139         struct sockaddr_in6 local 
= {}; 
10140         struct sockaddr_in6 remote 
= {}; 
10141         local
.sin6_family 
= remote
.sin6_family 
= AF_INET6
; 
10142         local
.sin6_len 
= remote
.sin6_len 
= sizeof(struct sockaddr_in6
); 
10143         local
.sin6_port 
= local_port
; 
10144         remote
.sin6_port 
= remote_port
; 
10145         memcpy(&local
.sin6_addr
, local_addr
, sizeof(local
.sin6_addr
)); 
10146         memcpy(&remote
.sin6_addr
, remote_addr
, sizeof(remote
.sin6_addr
)); 
10148         return necp_socket_is_allowed_to_send_recv_internal(inp
, (struct sockaddr 
*)&local
, (struct sockaddr 
*)&remote
, input_interface
, 
10149                    pf_tag
, return_policy_id
, return_route_rule_id
, return_skip_policy_id
, return_pass_flags
); 
10153 necp_socket_is_allowed_to_send_recv(struct inpcb 
*inp
, ifnet_t input_interface
, u_int16_t pf_tag
, necp_kernel_policy_id 
*return_policy_id
, 
10154     u_int32_t 
*return_route_rule_id
, necp_kernel_policy_id 
*return_skip_policy_id
, u_int32_t 
*return_pass_flags
) 
10156         return necp_socket_is_allowed_to_send_recv_internal(inp
, NULL
, NULL
, input_interface
, pf_tag
, 
10157                    return_policy_id
, return_route_rule_id
, 
10158                    return_skip_policy_id
, return_pass_flags
); 
10162 necp_mark_packet_from_socket(struct mbuf 
*packet
, struct inpcb 
*inp
, necp_kernel_policy_id policy_id
, u_int32_t route_rule_id
, 
10163     necp_kernel_policy_id skip_policy_id
, u_int32_t pass_flags
) 
10165         if (packet 
== NULL 
|| inp 
== NULL 
|| !(packet
->m_flags 
& M_PKTHDR
)) { 
10169         // Mark ID for Pass and IP Tunnel 
10170         if (policy_id 
!= NECP_KERNEL_POLICY_ID_NONE
) { 
10171                 packet
->m_pkthdr
.necp_mtag
.necp_policy_id 
= policy_id
; 
10172         } else if (inp
->inp_policyresult
.results
.result 
== NECP_KERNEL_POLICY_RESULT_PASS 
|| 
10173             inp
->inp_policyresult
.results
.result 
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
) { 
10174                 packet
->m_pkthdr
.necp_mtag
.necp_policy_id 
= inp
->inp_policyresult
.policy_id
; 
10176                 packet
->m_pkthdr
.necp_mtag
.necp_policy_id 
= NECP_KERNEL_POLICY_ID_NONE
; 
10178         packet
->m_pkthdr
.necp_mtag
.necp_last_interface_index 
= 0; 
10179         if (route_rule_id 
!= 0) { 
10180                 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id 
= route_rule_id
; 
10182                 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id 
= inp
->inp_policyresult
.results
.route_rule_id
; 
10184         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
); 
10186         if (skip_policy_id 
!= NECP_KERNEL_POLICY_ID_NONE 
&& 
10187             skip_policy_id 
!= NECP_KERNEL_POLICY_ID_NO_MATCH
) { 
10188                 // Only mark the skip policy if it is a valid policy ID 
10189                 packet
->m_pkthdr
.necp_mtag
.necp_skip_policy_id 
= skip_policy_id
; 
10190         } else if (inp
->inp_policyresult
.results
.filter_control_unit 
== NECP_FILTER_UNIT_NO_FILTER
) { 
10191                 // Overload the meaning of "NECP_KERNEL_POLICY_ID_NO_MATCH" 
10192                 // to indicate that NECP_FILTER_UNIT_NO_FILTER was set 
10193                 // See necp_get_skip_policy_id_from_packet() and 
10194                 // necp_packet_should_skip_filters(). 
10195                 packet
->m_pkthdr
.necp_mtag
.necp_skip_policy_id 
= NECP_KERNEL_POLICY_ID_NO_MATCH
; 
10197                 packet
->m_pkthdr
.necp_mtag
.necp_skip_policy_id 
= NECP_KERNEL_POLICY_ID_NONE
; 
10200         if (((pass_flags 
& NECP_KERNEL_POLICY_PASS_PF_TAG
) == NECP_KERNEL_POLICY_PASS_PF_TAG
) || 
10201             ((inp
->inp_policyresult
.results
.result_parameter
.pass_flags 
& NECP_KERNEL_POLICY_PASS_PF_TAG
) == NECP_KERNEL_POLICY_PASS_PF_TAG
)) { 
10202                 m_pftag(packet
)->pftag_tag 
= PF_TAG_ID_SYSTEM_SERVICE
; 
10209 necp_mark_packet_from_ip(struct mbuf 
*packet
, necp_kernel_policy_id policy_id
) 
10211         if (packet 
== NULL 
|| !(packet
->m_flags 
& M_PKTHDR
)) { 
10215         // Mark ID for Pass and IP Tunnel 
10216         if (policy_id 
!= NECP_KERNEL_POLICY_ID_NONE
) { 
10217                 packet
->m_pkthdr
.necp_mtag
.necp_policy_id 
= policy_id
; 
10219                 packet
->m_pkthdr
.necp_mtag
.necp_policy_id 
= NECP_KERNEL_POLICY_ID_NONE
; 
10226 necp_mark_packet_from_interface(struct mbuf 
*packet
, ifnet_t interface
) 
10228         if (packet 
== NULL 
|| !(packet
->m_flags 
& M_PKTHDR
)) { 
10232         // Mark ID for Pass and IP Tunnel 
10233         if (interface 
!= NULL
) { 
10234                 packet
->m_pkthdr
.necp_mtag
.necp_last_interface_index 
= interface
->if_index
; 
10241 necp_mark_packet_as_keepalive(struct mbuf 
*packet
, bool is_keepalive
) 
10243         if (packet 
== NULL 
|| !(packet
->m_flags 
& M_PKTHDR
)) { 
10247         if (is_keepalive
) { 
10248                 packet
->m_pkthdr
.pkt_flags 
|= PKTF_KEEPALIVE
; 
10250                 packet
->m_pkthdr
.pkt_flags 
&= ~PKTF_KEEPALIVE
; 
10256 necp_kernel_policy_id
 
10257 necp_get_policy_id_from_packet(struct mbuf 
*packet
) 
10259         if (packet 
== NULL 
|| !(packet
->m_flags 
& M_PKTHDR
)) { 
10260                 return NECP_KERNEL_POLICY_ID_NONE
; 
10263         return packet
->m_pkthdr
.necp_mtag
.necp_policy_id
; 
10266 necp_kernel_policy_id
 
10267 necp_get_skip_policy_id_from_packet(struct mbuf 
*packet
) 
10269         if (packet 
== NULL 
|| !(packet
->m_flags 
& M_PKTHDR
)) { 
10270                 return NECP_KERNEL_POLICY_ID_NONE
; 
10273         // Check for overloaded value. See necp_mark_packet_from_socket(). 
10274         if (packet
->m_pkthdr
.necp_mtag
.necp_skip_policy_id 
== NECP_KERNEL_POLICY_ID_NO_MATCH
) { 
10275                 return NECP_KERNEL_POLICY_ID_NONE
; 
10278         return packet
->m_pkthdr
.necp_mtag
.necp_skip_policy_id
; 
10282 necp_get_packet_filter_tags_from_packet(struct mbuf 
*packet
) 
10284         if (packet 
== NULL 
|| !(packet
->m_flags 
& M_PKTHDR
)) { 
10288         return m_pftag(packet
)->pftag_tag
; 
10292 necp_packet_should_skip_filters(struct mbuf 
*packet
) 
10294         if (packet 
== NULL 
|| !(packet
->m_flags 
& M_PKTHDR
)) { 
10298         // Check for overloaded value. See necp_mark_packet_from_socket(). 
10299         return packet
->m_pkthdr
.necp_mtag
.necp_skip_policy_id 
== NECP_KERNEL_POLICY_ID_NO_MATCH
; 
10303 necp_get_last_interface_index_from_packet(struct mbuf 
*packet
) 
10305         if (packet 
== NULL 
|| !(packet
->m_flags 
& M_PKTHDR
)) { 
10309         return packet
->m_pkthdr
.necp_mtag
.necp_last_interface_index
; 
10313 necp_get_route_rule_id_from_packet(struct mbuf 
*packet
) 
10315         if (packet 
== NULL 
|| !(packet
->m_flags 
& M_PKTHDR
)) { 
10319         return packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
; 
10323 necp_get_app_uuid_from_packet(struct mbuf 
*packet
, 
10326         if (packet 
== NULL 
|| !(packet
->m_flags 
& M_PKTHDR
)) { 
10330         bool found_mapping 
= FALSE
; 
10331         if (packet
->m_pkthdr
.necp_mtag
.necp_app_id 
!= 0) { 
10332                 lck_rw_lock_shared(&necp_kernel_policy_lock
); 
10333                 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
); 
10334                 struct necp_uuid_id_mapping 
*entry 
= necp_uuid_lookup_uuid_with_app_id_locked(app_id
); 
10335                 if (entry 
!= NULL
) { 
10336                         uuid_copy(app_uuid
, entry
->uuid
); 
10337                         found_mapping 
= true; 
10339                 lck_rw_done(&necp_kernel_policy_lock
); 
10341         if (!found_mapping
) { 
10342                 uuid_clear(app_uuid
); 
10348 necp_get_is_keepalive_from_packet(struct mbuf 
*packet
) 
10350         if (packet 
== NULL 
|| !(packet
->m_flags 
& M_PKTHDR
)) { 
10354         return packet
->m_pkthdr
.pkt_flags 
& PKTF_KEEPALIVE
; 
10358 necp_socket_get_content_filter_control_unit(struct socket 
*so
) 
10360         struct inpcb 
*inp 
= sotoinpcb(so
); 
10365         return inp
->inp_policyresult
.results
.filter_control_unit
; 
10369 necp_socket_should_use_flow_divert(struct inpcb 
*inp
) 
10375         return !(inp
->inp_socket
->so_flags1 
& SOF1_FLOW_DIVERT_SKIP
) && 
10376                (inp
->inp_policyresult
.results
.result 
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT 
|| 
10377                (inp
->inp_policyresult
.results
.flow_divert_aggregate_unit 
!= 0)); 
10381 necp_socket_get_flow_divert_control_unit(struct inpcb 
*inp
, uint32_t *aggregate_unit
) 
10387         if (inp
->inp_socket
->so_flags1 
& SOF1_FLOW_DIVERT_SKIP
) { 
10391         if (aggregate_unit 
!= NULL 
&& 
10392             inp
->inp_policyresult
.results
.flow_divert_aggregate_unit 
!= 0) { 
10393                 *aggregate_unit 
= inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
; 
10396         if (inp
->inp_policyresult
.results
.result 
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
) { 
10397                 return inp
->inp_policyresult
.results
.result_parameter
.flow_divert_control_unit
; 
10404 necp_socket_should_rescope(struct inpcb 
*inp
) 
10410         return inp
->inp_policyresult
.results
.result 
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED 
|| 
10411                inp
->inp_policyresult
.results
.result 
== NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT
; 
10415 necp_socket_get_rescope_if_index(struct inpcb 
*inp
) 
10421         if (inp
->inp_policyresult
.results
.result 
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
) { 
10422                 return inp
->inp_policyresult
.results
.result_parameter
.scoped_interface_index
; 
10423         } else if (inp
->inp_policyresult
.results
.result 
== NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT
) { 
10424                 return necp_get_primary_direct_interface_index(); 
10431 necp_socket_get_effective_mtu(struct inpcb 
*inp
, u_int32_t current_mtu
) 
10434                 return current_mtu
; 
10437         if (inp
->inp_policyresult
.results
.result 
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL 
&& 
10438             (inp
->inp_flags 
& INP_BOUND_IF
) && 
10439             inp
->inp_boundifp
) { 
10440                 u_int bound_interface_index 
= inp
->inp_boundifp
->if_index
; 
10441                 u_int tunnel_interface_index 
= inp
->inp_policyresult
.results
.result_parameter
.tunnel_interface_index
; 
10443                 // The result is IP Tunnel, and is rescoping from one interface to another. Recalculate MTU. 
10444                 if (bound_interface_index 
!= tunnel_interface_index
) { 
10445                         ifnet_t tunnel_interface 
= NULL
; 
10447                         ifnet_head_lock_shared(); 
10448                         tunnel_interface 
= ifindex2ifnet
[tunnel_interface_index
]; 
10451                         if (tunnel_interface 
!= NULL
) { 
10452                                 u_int32_t direct_tunnel_mtu 
= tunnel_interface
->if_mtu
; 
10453                                 u_int32_t delegate_tunnel_mtu 
= (tunnel_interface
->if_delegated
.ifp 
!= NULL
) ? tunnel_interface
->if_delegated
.ifp
->if_mtu 
: 0; 
10454                                 if (delegate_tunnel_mtu 
!= 0 && 
10455                                     strncmp(tunnel_interface
->if_name
, "ipsec", strlen("ipsec")) == 0) { 
10456                                         // For ipsec interfaces, calculate the overhead from the delegate interface 
10457                                         u_int32_t tunnel_overhead 
= (u_int32_t
)(esp_hdrsiz(NULL
) + sizeof(struct ip6_hdr
)); 
10458                                         if (delegate_tunnel_mtu 
> tunnel_overhead
) { 
10459                                                 delegate_tunnel_mtu 
-= tunnel_overhead
; 
10462                                         if (delegate_tunnel_mtu 
< direct_tunnel_mtu
) { 
10463                                                 // If the (delegate - overhead) < direct, return (delegate - overhead) 
10464                                                 return delegate_tunnel_mtu
; 
10466                                                 // Otherwise return direct 
10467                                                 return direct_tunnel_mtu
; 
10470                                         // For non-ipsec interfaces, just return the tunnel MTU 
10471                                         return direct_tunnel_mtu
; 
10477         // By default, just return the MTU passed in 
10478         return current_mtu
; 
10482 necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter 
*result_parameter
) 
10484         if (result_parameter 
== NULL
) { 
10488         return ifindex2ifnet
[result_parameter
->tunnel_interface_index
]; 
10492 necp_packet_can_rebind_to_ifnet(struct mbuf 
*packet
, struct ifnet 
*interface
, struct route 
*new_route
, int family
) 
10494         bool found_match 
= FALSE
; 
10495         errno_t result 
= 0; 
10496         ifaddr_t 
*addresses 
= NULL
; 
10497         union necp_sockaddr_union address_storage
; 
10500         if (packet 
== NULL 
|| interface 
== NULL 
|| new_route 
== NULL 
|| (family 
!= AF_INET 
&& family 
!= AF_INET6
)) { 
10504         result 
= ifnet_get_address_list_family(interface
, &addresses
, family
); 
10506                 NECPLOG(LOG_ERR
, "Failed to get address list for %s%d", ifnet_name(interface
), ifnet_unit(interface
)); 
10510         for (i 
= 0; addresses
[i
] != NULL
; i
++) { 
10511                 ROUTE_RELEASE(new_route
); 
10512                 if (ifaddr_address(addresses
[i
], &address_storage
.sa
, sizeof(address_storage
)) == 0) { 
10513                         if (family 
== AF_INET
) { 
10514                                 struct ip 
*ip 
= mtod(packet
, struct ip 
*); 
10515                                 if (memcmp(&address_storage
.sin
.sin_addr
, &ip
->ip_src
, sizeof(ip
->ip_src
)) == 0) { 
10516                                         struct sockaddr_in 
*dst4 
= (struct sockaddr_in 
*)(void *)&new_route
->ro_dst
; 
10517                                         dst4
->sin_family 
= AF_INET
; 
10518                                         dst4
->sin_len 
= sizeof(struct sockaddr_in
); 
10519                                         dst4
->sin_addr 
= ip
->ip_dst
; 
10520                                         rtalloc_scoped(new_route
, interface
->if_index
); 
10521                                         if (!ROUTE_UNUSABLE(new_route
)) { 
10522                                                 found_match 
= TRUE
; 
10526                         } else if (family 
== AF_INET6
) { 
10527                                 struct ip6_hdr 
*ip6 
= mtod(packet
, struct ip6_hdr 
*); 
10528                                 if (memcmp(&address_storage
.sin6
.sin6_addr
, &ip6
->ip6_src
, sizeof(ip6
->ip6_src
)) == 0) { 
10529                                         struct sockaddr_in6 
*dst6 
= (struct sockaddr_in6 
*)(void *)&new_route
->ro_dst
; 
10530                                         dst6
->sin6_family 
= AF_INET6
; 
10531                                         dst6
->sin6_len 
= sizeof(struct sockaddr_in6
); 
10532                                         dst6
->sin6_addr 
= ip6
->ip6_dst
; 
10533                                         rtalloc_scoped(new_route
, interface
->if_index
); 
10534                                         if (!ROUTE_UNUSABLE(new_route
)) { 
10535                                                 found_match 
= TRUE
; 
10544         ifnet_free_address_list(addresses
); 
10546         return found_match
; 
10550 necp_addr_is_loopback(struct sockaddr 
*address
) 
10552         if (address 
== NULL
) { 
10556         if (address
->sa_family 
== AF_INET
) { 
10557                 return ntohl(((struct sockaddr_in 
*)(void *)address
)->sin_addr
.s_addr
) == INADDR_LOOPBACK
; 
10558         } else if (address
->sa_family 
== AF_INET6
) { 
10559                 return IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6 
*)(void *)address
)->sin6_addr
); 
10566 necp_is_loopback(struct sockaddr 
*local_addr
, struct sockaddr 
*remote_addr
, struct inpcb 
*inp
, struct mbuf 
*packet
, u_int32_t bound_interface_index
) 
10568         // Note: This function only checks for the loopback addresses. 
10569         // In the future, we may want to expand to also allow any traffic 
10570         // going through the loopback interface, but until then, this 
10571         // check is cheaper. 
10573         if (local_addr 
!= NULL 
&& necp_addr_is_loopback(local_addr
)) { 
10577         if (remote_addr 
!= NULL 
&& necp_addr_is_loopback(remote_addr
)) { 
10582                 if ((inp
->inp_flags 
& INP_BOUND_IF
) && inp
->inp_boundifp 
&& (inp
->inp_boundifp
->if_flags 
& IFF_LOOPBACK
)) { 
10585                 if (inp
->inp_vflag 
& INP_IPV4
) { 
10586                         if (ntohl(inp
->inp_laddr
.s_addr
) == INADDR_LOOPBACK 
|| 
10587                             ntohl(inp
->inp_faddr
.s_addr
) == INADDR_LOOPBACK
) { 
10590                 } else if (inp
->inp_vflag 
& INP_IPV6
) { 
10591                         if (IN6_IS_ADDR_LOOPBACK(&inp
->in6p_laddr
) || 
10592                             IN6_IS_ADDR_LOOPBACK(&inp
->in6p_faddr
)) { 
10596         } else if (bound_interface_index 
!= IFSCOPE_NONE 
&& lo_ifp
->if_index 
== bound_interface_index
) { 
10600         if (packet 
!= NULL
) { 
10601                 struct ip 
*ip 
= mtod(packet
, struct ip 
*); 
10602                 if (ip
->ip_v 
== 4) { 
10603                         if (ntohl(ip
->ip_src
.s_addr
) == INADDR_LOOPBACK
) { 
10606                         if (ntohl(ip
->ip_dst
.s_addr
) == INADDR_LOOPBACK
) { 
10609                 } else if (ip
->ip_v 
== 6) { 
10610                         struct ip6_hdr 
*ip6 
= mtod(packet
, struct ip6_hdr 
*); 
10611                         if (IN6_IS_ADDR_LOOPBACK(&ip6
->ip6_src
)) { 
10614                         if (IN6_IS_ADDR_LOOPBACK(&ip6
->ip6_dst
)) { 
10624 necp_is_intcoproc(struct inpcb 
*inp
, struct mbuf 
*packet
) 
10627                 if (!(inp
->inp_vflag 
& INP_IPV6
)) { 
10630                 if (INP_INTCOPROC_ALLOWED(inp
)) { 
10633                 if ((inp
->inp_flags 
& INP_BOUND_IF
) && 
10634                     IFNET_IS_INTCOPROC(inp
->inp_boundifp
)) { 
10639         if (packet 
!= NULL
) { 
10640                 struct ip6_hdr 
*ip6 
= mtod(packet
, struct ip6_hdr 
*); 
10641                 if ((ip6
->ip6_vfc 
& IPV6_VERSION_MASK
) == IPV6_VERSION 
&& 
10642                     IN6_IS_ADDR_LINKLOCAL(&ip6
->ip6_dst
) && 
10643                     ip6
->ip6_dst
.s6_addr32
[2] == ntohl(0xaede48ff) && 
10644                     ip6
->ip6_dst
.s6_addr32
[3] == ntohl(0xfe334455)) { 
10653 necp_address_matches_drop_dest_policy(union necp_sockaddr_union 
*sau
, u_int32_t session_order
) 
10655         char dest_str
[MAX_IPv6_STR_LEN
]; 
10657         if (necp_drop_dest_debug 
> 0) { 
10658                 if (sau
->sa
.sa_family 
== AF_INET
) { 
10659                         (void) inet_ntop(AF_INET
, &sau
->sin
.sin_addr
, dest_str
, sizeof(dest_str
)); 
10660                 } else if (sau
->sa
.sa_family 
== AF_INET6
) { 
10661                         (void) inet_ntop(AF_INET6
, &sau
->sin6
.sin6_addr
, dest_str
, sizeof(dest_str
)); 
10666         for (u_int32_t i 
= 0; i 
< necp_drop_dest_policy
.entry_count
; i
++) { 
10667                 struct necp_drop_dest_entry 
*necp_drop_dest_entry 
= &necp_drop_dest_policy
.entries
[i
]; 
10668                 struct necp_policy_condition_addr 
*npca 
= &necp_drop_dest_entry
->cond_addr
; 
10670                 if (session_order 
>= necp_drop_dest_entry
->order 
&& necp_is_addr_in_subnet(&sau
->sa
, &npca
->address
.sa
, npca
->prefix
)) { 
10671                         if (necp_drop_dest_debug 
> 0) { 
10672                                 char subnet_str
[MAX_IPv6_STR_LEN
]; 
10673                                 struct proc 
*p 
= current_proc(); 
10674                                 pid_t pid 
= proc_pid(p
); 
10676                                 if (sau
->sa
.sa_family 
== AF_INET
) { 
10677                                         (void) inet_ntop(AF_INET
, &npca
->address
.sin
, subnet_str
, sizeof(subnet_str
)); 
10678                                         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
); 
10679                                 } else if (sau
->sa
.sa_family 
== AF_INET6
) { 
10680                                         (void) inet_ntop(AF_INET6
, &npca
->address
.sin6
, subnet_str
, sizeof(subnet_str
)); 
10681                                         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
); 
10687         if (necp_drop_dest_debug 
> 1) { 
10688                 struct proc 
*p 
= current_proc(); 
10689                 pid_t pid 
= proc_pid(p
); 
10691                 os_log(OS_LOG_DEFAULT
, "%s (process %s:%u) %s no match", __func__
, proc_best_name(p
), pid
, dest_str
); 
10697 sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS
 
10699 #pragma unused(arg1, arg2, oidp) 
10702         struct necp_drop_dest_policy tmp_drop_dest_policy
; 
10703         struct proc 
*p 
= current_proc(); 
10704         pid_t pid 
= proc_pid(p
); 
10706         if (req
->newptr 
!= USER_ADDR_NULL 
&& proc_suser(current_proc()) != 0 && 
10707             priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES
, 0) != 0) { 
10708                 NECPLOG(LOG_ERR
, "%s (process %s:%u) not permitted", __func__
, proc_best_name(p
), pid
); 
10711         if (req
->newptr 
!= USER_ADDR_NULL 
&& req
->newlen 
!= sizeof(struct necp_drop_dest_policy
)) { 
10712                 NECPLOG(LOG_ERR
, "%s (process %s:%u) bad newlen %lu", __func__
, proc_best_name(p
), pid
, req
->newlen
); 
10716         memcpy(&tmp_drop_dest_policy
, &necp_drop_dest_policy
, sizeof(struct necp_drop_dest_policy
)); 
10717         error 
= sysctl_io_opaque(req
, &tmp_drop_dest_policy
, sizeof(struct necp_drop_dest_policy
), &changed
); 
10719                 NECPLOG(LOG_ERR
, "%s (process %s:%u) sysctl_io_opaque() error %d", __func__
, proc_best_name(p
), pid
, error
); 
10722         if (changed 
== 0 || req
->newptr 
== USER_ADDR_NULL
) { 
10727         // Validate the passed parameters 
10729         if (tmp_drop_dest_policy
.entry_count 
>= MAX_NECP_DROP_DEST_LEVEL_ADDRS
) { 
10730                 NECPLOG(LOG_ERR
, "%s (process %s:%u) bad entry_count %u", __func__
, proc_best_name(p
), pid
, tmp_drop_dest_policy
.entry_count
); 
10733         for (u_int32_t i 
= 0; i 
< tmp_drop_dest_policy
.entry_count
; i
++) { 
10734                 struct necp_drop_dest_entry 
*tmp_drop_dest_entry 
= &tmp_drop_dest_policy
.entries
[i
]; 
10735                 struct necp_policy_condition_addr 
*npca 
= &tmp_drop_dest_entry
->cond_addr
; 
10737                 switch (tmp_drop_dest_entry
->level
) { 
10738                 case NECP_SESSION_PRIORITY_UNKNOWN
: 
10739                         if (tmp_drop_dest_policy
.entry_count 
!= 0) { 
10740                                 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
); 
10744                 case NECP_SESSION_PRIORITY_CONTROL
: 
10745                 case NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL
: 
10746                 case NECP_SESSION_PRIORITY_HIGH
: 
10747                 case NECP_SESSION_PRIORITY_HIGH_1
: 
10748                 case NECP_SESSION_PRIORITY_HIGH_2
: 
10749                 case NECP_SESSION_PRIORITY_HIGH_3
: 
10750                 case NECP_SESSION_PRIORITY_HIGH_4
: 
10751                 case NECP_SESSION_PRIORITY_HIGH_RESTRICTED
: 
10752                 case NECP_SESSION_PRIORITY_DEFAULT
: 
10753                 case NECP_SESSION_PRIORITY_LOW
: 
10754                         if (tmp_drop_dest_policy
.entry_count 
== 0) { 
10755                                 NECPLOG(LOG_ERR
, "%s (process %s:%u) priority %u entry_count 0", __func__
, proc_best_name(p
), pid
, tmp_drop_dest_entry
->level
); 
10760                         NECPLOG(LOG_ERR
, "%s (process %s:%u) bad level %u", __func__
, proc_best_name(p
), pid
, tmp_drop_dest_entry
->level
); 
10765                 switch (npca
->address
.sa
.sa_family
) { 
10767                         if (npca
->prefix 
> 32) { 
10768                                 NECPLOG(LOG_ERR
, "%s (process %s:%u) AF_INET bad prefix %u", __func__
, proc_best_name(p
), pid
, npca
->prefix
); 
10771                         if (npca
->address
.sin
.sin_len 
!= sizeof(struct sockaddr_in
)) { 
10772                                 NECPLOG(LOG_ERR
, "%s (process %s:%u) AF_INET bad sin_len %u", __func__
, proc_best_name(p
), pid
, npca
->address
.sin
.sin_len
); 
10775                         if (npca
->address
.sin
.sin_port 
!= 0) { 
10776                                 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
); 
10782                         if (npca
->prefix 
> 128) { 
10783                                 NECPLOG(LOG_ERR
, "%s (process %s:%u) AF_INET6 bad prefix %u", __func__
, proc_best_name(p
), pid
, npca
->prefix
); 
10786                         if (npca
->address
.sin6
.sin6_len 
!= sizeof(struct sockaddr_in6
)) { 
10787                                 NECPLOG(LOG_ERR
, "%s (process %s:%u) AF_INET6 bad sin6_len %u", __func__
, proc_best_name(p
), pid
, npca
->address
.sin6
.sin6_len
); 
10790                         if (npca
->address
.sin6
.sin6_port 
!= 0) { 
10791                                 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
); 
10794                         if (npca
->address
.sin6
.sin6_flowinfo 
!= 0) { 
10795                                 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
); 
10798                         if (npca
->address
.sin6
.sin6_scope_id 
!= 0) { 
10799                                 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
); 
10811         // Commit the changed policy 
10813         lck_rw_lock_exclusive(&necp_kernel_policy_lock
); 
10814         memset(&necp_drop_dest_policy
, 0, sizeof(struct necp_drop_dest_policy
)); 
10816         necp_drop_dest_policy
.entry_count 
= tmp_drop_dest_policy
.entry_count
; 
10817         for (u_int32_t i 
= 0; i 
< tmp_drop_dest_policy
.entry_count
; i
++) { 
10818                 struct necp_drop_dest_entry 
*tmp_drop_dest_entry 
= &tmp_drop_dest_policy
.entries
[i
]; 
10819                 struct necp_drop_dest_entry 
*necp_drop_dest_entry 
= &necp_drop_dest_policy
.entries
[i
]; 
10821                 memcpy(necp_drop_dest_entry
, tmp_drop_dest_entry
, sizeof(struct necp_drop_dest_entry
)); 
10823                 necp_drop_dest_entry
->order 
= necp_get_first_order_for_priority(necp_drop_dest_entry
->level
); 
10825         lck_rw_done(&necp_kernel_policy_lock
);