2 * Copyright (c) 2013-2016 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 <libkern/OSMalloc.h>
35 #include <sys/kernel.h>
36 #include <sys/kern_control.h>
38 #include <sys/kpi_mbuf.h>
39 #include <sys/proc_uuid_policy.h>
41 #include <sys/domain.h>
42 #include <sys/protosw.h>
43 #include <sys/socket.h>
44 #include <sys/socketvar.h>
45 #include <netinet/ip.h>
46 #include <netinet/ip6.h>
47 #include <netinet/tcp.h>
48 #include <netinet/tcp_var.h>
49 #include <netinet/udp.h>
50 #include <netinet/in_pcb.h>
51 #include <netinet/in_tclass.h>
52 #include <netinet6/esp.h>
53 #include <net/flowhash.h>
54 #include <net/if_var.h>
55 #include <sys/kauth.h>
56 #include <sys/sysctl.h>
57 #include <sys/sysproto.h>
59 #include <sys/kern_event.h>
60 #include <IOKit/IOBSD.h>
61 #include <net/network_agent.h>
65 * NECP - Network Extension Control Policy database
66 * ------------------------------------------------
67 * The goal of this module is to allow clients connecting via a
68 * kernel control socket to create high-level policy sessions, which
69 * are ingested into low-level kernel policies that control and tag
70 * traffic at the application, socket, and IP layers.
72 * ------------------------------------------------
74 * ------------------------------------------------
75 * Each session owns a list of session policies, each of which can
76 * specify any combination of conditions and a single result. Each
77 * session also has a priority level (such as High, Default, or Low)
78 * which is requested by the client. Based on the requested level,
79 * a session order value is assigned to the session, which will be used
80 * to sort kernel policies generated by the session. The session client
81 * can specify the sub-order for each policy it creates which will be
82 * used to further sort the kernel policies.
84 * Kernel Control Socket --> 1 necp_session --> list of necp_session_policy structs
86 * ------------------------------------------------
88 * ------------------------------------------------
89 * Whenever a session send the Apply command, its policies are ingested
90 * and generate kernel policies. There are two phases of kernel policy
93 * 1. The session policy is parsed to create kernel policies at the socket
94 * and IP layers, when applicable. For example, a policy that requires
95 * all traffic from App1 to Pass will generate a socket kernel policy to
96 * match App1 and mark packets with ID1, and also an IP policy to match
97 * ID1 and let the packet pass. This is handled in necp_apply_policy. The
98 * resulting kernel policies are added to the global socket and IP layer
100 * necp_session_policy --> necp_kernel_socket_policy and necp_kernel_ip_output_policy
103 * necp_kernel_socket_policies necp_kernel_ip_output_policies
105 * 2. Once the global lists of kernel policies have been filled out, each
106 * list is traversed to create optimized sub-lists ("Maps") which are used during
107 * data-path evaluation. IP policies are sent into necp_kernel_ip_output_policies_map,
108 * which hashes incoming packets based on marked socket-layer policies, and removes
109 * duplicate or overlapping policies. Socket policies are sent into two maps,
110 * necp_kernel_socket_policies_map and necp_kernel_socket_policies_app_layer_map.
111 * The app layer map is used for policy checks coming in from user space, and is one
112 * list with duplicate and overlapping policies removed. The socket map hashes based
113 * on app UUID, and removes duplicate and overlapping policies.
114 * necp_kernel_socket_policy --> necp_kernel_socket_policies_app_layer_map
115 * |-> necp_kernel_socket_policies_map
117 * necp_kernel_ip_output_policies --> necp_kernel_ip_output_policies_map
119 * ------------------------------------------------
121 * ------------------------------------------------
122 * The Drop All Level is a sysctl that controls the level at which policies are allowed
123 * to override a global drop rule. If the value is 0, no drop rule is applied. If the value
124 * is 1, all traffic is dropped. If the value is greater than 1, all kernel policies created
125 * by a session with a priority level better than (numerically less than) the
126 * Drop All Level will allow matching traffic to not be dropped. The Drop All Level is
127 * dynamically interpreted into necp_drop_all_order, which specifies the equivalent assigned
128 * session orders to be dropped.
131 u_int32_t necp_drop_all_order
= 0;
132 u_int32_t necp_drop_all_level
= 0;
134 u_int32_t necp_pass_loopback
= 1; // 0=Off, 1=On
135 u_int32_t necp_pass_keepalives
= 1; // 0=Off, 1=On
137 u_int32_t necp_debug
= 0; // 0=None, 1=Basic, 2=EveryMatch
139 u_int32_t necp_session_count
= 0;
141 #define LIST_INSERT_SORTED_ASCENDING(head, elm, field, sortfield, tmpelm) do { \
142 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->sortfield >= (elm)->sortfield)) { \
143 LIST_INSERT_HEAD((head), elm, field); \
145 LIST_FOREACH(tmpelm, head, field) { \
146 if (LIST_NEXT(tmpelm, field) == NULL || LIST_NEXT(tmpelm, field)->sortfield >= (elm)->sortfield) { \
147 LIST_INSERT_AFTER(tmpelm, elm, field); \
154 #define LIST_INSERT_SORTED_TWICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, tmpelm) do { \
155 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield))) { \
156 LIST_INSERT_HEAD((head), elm, field); \
158 LIST_FOREACH(tmpelm, head, field) { \
159 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))) { \
160 LIST_INSERT_AFTER(tmpelm, elm, field); \
167 #define LIST_INSERT_SORTED_THRICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, thirdsortfield, tmpelm) do { \
168 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))) { \
169 LIST_INSERT_HEAD((head), elm, field); \
171 LIST_FOREACH(tmpelm, head, field) { \
172 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))) { \
173 LIST_INSERT_AFTER(tmpelm, elm, field); \
180 #define IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(x) ((x) == NECP_ROUTE_RULE_DENY_INTERFACE || (x) == NECP_ROUTE_RULE_ALLOW_INTERFACE)
182 #define NECP_KERNEL_CONDITION_ALL_INTERFACES 0x00001
183 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE 0x00002
184 #define NECP_KERNEL_CONDITION_PROTOCOL 0x00004
185 #define NECP_KERNEL_CONDITION_LOCAL_START 0x00008
186 #define NECP_KERNEL_CONDITION_LOCAL_END 0x00010
187 #define NECP_KERNEL_CONDITION_LOCAL_PREFIX 0x00020
188 #define NECP_KERNEL_CONDITION_REMOTE_START 0x00040
189 #define NECP_KERNEL_CONDITION_REMOTE_END 0x00080
190 #define NECP_KERNEL_CONDITION_REMOTE_PREFIX 0x00100
191 #define NECP_KERNEL_CONDITION_APP_ID 0x00200
192 #define NECP_KERNEL_CONDITION_REAL_APP_ID 0x00400
193 #define NECP_KERNEL_CONDITION_DOMAIN 0x00800
194 #define NECP_KERNEL_CONDITION_ACCOUNT_ID 0x01000
195 #define NECP_KERNEL_CONDITION_POLICY_ID 0x02000
196 #define NECP_KERNEL_CONDITION_PID 0x04000
197 #define NECP_KERNEL_CONDITION_UID 0x08000
198 #define NECP_KERNEL_CONDITION_LAST_INTERFACE 0x10000 // Only set from packets looping between interfaces
199 #define NECP_KERNEL_CONDITION_TRAFFIC_CLASS 0x20000
200 #define NECP_KERNEL_CONDITION_ENTITLEMENT 0x40000
201 #define NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT 0x80000
203 #define NECP_MAX_POLICY_RESULT_SIZE 512
204 #define NECP_MAX_ROUTE_RULES_ARRAY_SIZE 1024
205 #define NECP_MAX_CONDITIONS_ARRAY_SIZE 4096
207 struct necp_service_registration
{
208 LIST_ENTRY(necp_service_registration
) session_chain
;
209 LIST_ENTRY(necp_service_registration
) kernel_chain
;
210 u_int32_t service_id
;
213 struct necp_session
{
214 u_int32_t control_unit
;
215 u_int32_t session_priority
; // Descriptive priority rating
216 u_int32_t session_order
;
218 bool proc_locked
; // Messages must come from proc_uuid
223 LIST_HEAD(_policies
, necp_session_policy
) policies
;
225 LIST_HEAD(_services
, necp_service_registration
) services
;
228 struct necp_socket_info
{
231 union necp_sockaddr_union local_addr
;
232 union necp_sockaddr_union remote_addr
;
233 u_int32_t bound_interface_index
;
234 u_int32_t traffic_class
;
236 u_int32_t application_id
;
237 u_int32_t real_application_id
;
238 u_int32_t account_id
;
243 static kern_ctl_ref necp_kctlref
;
244 static u_int32_t necp_family
;
245 static OSMallocTag necp_malloc_tag
;
246 static lck_grp_attr_t
*necp_kernel_policy_grp_attr
= NULL
;
247 static lck_attr_t
*necp_kernel_policy_mtx_attr
= NULL
;
248 static lck_grp_t
*necp_kernel_policy_mtx_grp
= NULL
;
249 decl_lck_rw_data(static, necp_kernel_policy_lock
);
251 static lck_grp_attr_t
*necp_route_rule_grp_attr
= NULL
;
252 static lck_attr_t
*necp_route_rule_mtx_attr
= NULL
;
253 static lck_grp_t
*necp_route_rule_mtx_grp
= NULL
;
254 decl_lck_rw_data(static, necp_route_rule_lock
);
256 static necp_policy_id necp_last_policy_id
= 0;
257 static necp_kernel_policy_id necp_last_kernel_policy_id
= 0;
258 static u_int32_t necp_last_uuid_id
= 0;
259 static u_int32_t necp_last_string_id
= 0;
260 static u_int32_t necp_last_route_rule_id
= 0;
261 static u_int32_t necp_last_aggregate_route_rule_id
= 0;
264 * On modification, invalidate cached lookups by bumping the generation count.
265 * Other calls will need to take the slowpath of taking
266 * the subsystem lock.
268 static volatile int32_t necp_kernel_socket_policies_gencount
;
269 #define BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT() do { \
270 if (OSIncrementAtomic(&necp_kernel_socket_policies_gencount) == (INT32_MAX - 1)) { \
271 necp_kernel_socket_policies_gencount = 1; \
275 static u_int32_t necp_kernel_application_policies_condition_mask
;
276 static size_t necp_kernel_application_policies_count
;
277 static u_int32_t necp_kernel_socket_policies_condition_mask
;
278 static size_t necp_kernel_socket_policies_count
;
279 static size_t necp_kernel_socket_policies_non_app_count
;
280 static LIST_HEAD(_necpkernelsocketconnectpolicies
, necp_kernel_socket_policy
) necp_kernel_socket_policies
;
281 #define NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS 5
282 #define NECP_SOCKET_MAP_APP_ID_TO_BUCKET(appid) (appid ? (appid%(NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS - 1) + 1) : 0)
283 static struct necp_kernel_socket_policy
**necp_kernel_socket_policies_map
[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
];
284 static struct necp_kernel_socket_policy
**necp_kernel_socket_policies_app_layer_map
;
286 * A note on policy 'maps': these are used for boosting efficiency when matching policies. For each dimension of the map,
287 * such as an ID, the 0 bucket is reserved for sockets/packets that do not have this parameter, while the other
288 * buckets lead to an array of policy pointers that form the list applicable when the (parameter%(NUM_BUCKETS - 1) + 1) == bucket_index.
290 * For example, a packet with policy ID of 7, when there are 4 ID buckets, will map to bucket (7%3 + 1) = 2.
293 static u_int32_t necp_kernel_ip_output_policies_condition_mask
;
294 static size_t necp_kernel_ip_output_policies_count
;
295 static size_t necp_kernel_ip_output_policies_non_id_count
;
296 static LIST_HEAD(_necpkernelipoutputpolicies
, necp_kernel_ip_output_policy
) necp_kernel_ip_output_policies
;
297 #define NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS 5
298 #define NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(id) (id ? (id%(NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS - 1) + 1) : 0)
299 static struct necp_kernel_ip_output_policy
**necp_kernel_ip_output_policies_map
[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
];
301 static struct necp_session
*necp_create_session(u_int32_t control_unit
);
302 static void necp_delete_session(struct necp_session
*session
);
304 static void necp_handle_policy_add(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
);
305 static void necp_handle_policy_get(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
);
306 static void necp_handle_policy_delete(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
);
307 static void necp_handle_policy_apply_all(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
);
308 static void necp_handle_policy_list_all(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
);
309 static void necp_handle_policy_delete_all(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
);
310 static void necp_handle_policy_dump_all(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
);
311 static void necp_handle_set_session_priority(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
);
312 static void necp_handle_lock_session_to_proc(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
);
313 static void necp_handle_register_service(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
);
314 static void necp_handle_unregister_service(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
);
316 #define MAX_RESULT_STRING_LEN 64
317 static inline const char * necp_get_result_description(char *result_string
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
);
319 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
);
320 static struct necp_session_policy
*necp_policy_find(struct necp_session
*session
, necp_policy_id policy_id
);
321 static bool necp_policy_mark_for_deletion(struct necp_session
*session
, struct necp_session_policy
*policy
);
322 static bool necp_policy_mark_all_for_deletion(struct necp_session
*session
);
323 static bool necp_policy_delete(struct necp_session
*session
, struct necp_session_policy
*policy
);
324 static void necp_policy_apply_all(struct necp_session
*session
);
326 static necp_kernel_policy_id
necp_kernel_socket_policy_add(necp_policy_id parent_policy_id
, necp_policy_order order
, u_int32_t session_order
, int session_pid
, u_int32_t condition_mask
, u_int32_t condition_negated_mask
, necp_app_id cond_app_id
, necp_app_id cond_real_app_id
, char *cond_custom_entitlement
, u_int32_t cond_account_id
, char *domain
, pid_t cond_pid
, uid_t cond_uid
, ifnet_t cond_bound_interface
, struct necp_policy_condition_tc_range cond_traffic_class
, u_int16_t cond_protocol
, union necp_sockaddr_union
*cond_local_start
, union necp_sockaddr_union
*cond_local_end
, u_int8_t cond_local_prefix
, union necp_sockaddr_union
*cond_remote_start
, union necp_sockaddr_union
*cond_remote_end
, u_int8_t cond_remote_prefix
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
);
327 static bool necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id
);
328 static bool necp_kernel_socket_policies_reprocess(void);
329 static bool necp_kernel_socket_policies_update_uuid_table(void);
330 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
, necp_kernel_policy_result
*return_service_action
, necp_kernel_policy_service
*return_service
, u_int32_t
*return_netagent_array
, size_t netagent_array_count
, proc_t proc
);
332 static necp_kernel_policy_id
necp_kernel_ip_output_policy_add(necp_policy_id parent_policy_id
, necp_policy_order order
, necp_policy_order suborder
, u_int32_t session_order
, 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
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
);
333 static bool necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id
);
334 static bool necp_kernel_ip_output_policies_reprocess(void);
336 static bool necp_is_addr_in_range(struct sockaddr
*addr
, struct sockaddr
*range_start
, struct sockaddr
*range_end
);
337 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
);
338 static bool necp_is_addr_in_subnet(struct sockaddr
*addr
, struct sockaddr
*subnet_addr
, u_int8_t subnet_prefix
);
339 static int necp_addr_compare(struct sockaddr
*sa1
, struct sockaddr
*sa2
, int check_port
);
340 static bool necp_buffer_compare_with_bit_prefix(u_int8_t
*p1
, u_int8_t
*p2
, u_int32_t bits
);
341 static bool necp_is_loopback(struct sockaddr
*local_addr
, struct sockaddr
*remote_addr
, struct inpcb
*inp
, struct mbuf
*packet
);
342 static bool necp_is_intcoproc(struct inpcb
*inp
, struct mbuf
*packet
);
344 struct necp_uuid_id_mapping
{
345 LIST_ENTRY(necp_uuid_id_mapping
) chain
;
349 u_int32_t table_refcount
; // Add to UUID policy table count
351 static size_t necp_num_uuid_app_id_mappings
;
352 static bool necp_uuid_app_id_mappings_dirty
;
353 #define NECP_UUID_APP_ID_HASH_SIZE 64
354 static u_long necp_uuid_app_id_hash_mask
;
355 static u_long necp_uuid_app_id_hash_num_buckets
;
356 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
357 #define APPUUIDHASH(uuid) (&necp_uuid_app_id_hashtbl[uuid[0] & necp_uuid_app_id_hash_mask]) // Assume first byte of UUIDs are evenly distributed
358 static u_int32_t
necp_create_uuid_app_id_mapping(uuid_t uuid
, bool *allocated_mapping
, bool uuid_policy_table
);
359 static bool necp_remove_uuid_app_id_mapping(uuid_t uuid
, bool *removed_mapping
, bool uuid_policy_table
);
360 static struct necp_uuid_id_mapping
*necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id
);
362 static struct necp_uuid_id_mapping
*necp_uuid_lookup_service_id_locked(uuid_t uuid
);
363 static struct necp_uuid_id_mapping
*necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id
);
364 static u_int32_t
necp_create_uuid_service_id_mapping(uuid_t uuid
);
365 static bool necp_remove_uuid_service_id_mapping(uuid_t uuid
);
367 struct necp_string_id_mapping
{
368 LIST_ENTRY(necp_string_id_mapping
) chain
;
373 static LIST_HEAD(necp_string_id_mapping_list
, necp_string_id_mapping
) necp_account_id_list
;
374 static u_int32_t
necp_create_string_to_id_mapping(struct necp_string_id_mapping_list
*list
, char *domain
);
375 static bool necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list
*list
, char *domain
);
376 static struct necp_string_id_mapping
*necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list
*list
, u_int32_t local_id
);
378 static LIST_HEAD(_necp_kernel_service_list
, necp_service_registration
) necp_registered_service_list
;
380 static char *necp_create_trimmed_domain(char *string
, size_t length
);
381 static inline int necp_count_dots(char *string
, size_t length
);
383 static char *necp_copy_string(char *string
, size_t length
);
385 #define ROUTE_RULE_IS_AGGREGATE(ruleid) (ruleid > UINT16_MAX)
387 #define MAX_ROUTE_RULE_INTERFACES 10
388 struct necp_route_rule
{
389 LIST_ENTRY(necp_route_rule
) chain
;
391 u_int32_t default_action
;
392 u_int8_t cellular_action
;
393 u_int8_t wifi_action
;
394 u_int8_t wired_action
;
395 u_int8_t expensive_action
;
396 u_int exception_if_indices
[MAX_ROUTE_RULE_INTERFACES
];
397 u_int8_t exception_if_actions
[MAX_ROUTE_RULE_INTERFACES
];
400 static LIST_HEAD(necp_route_rule_list
, necp_route_rule
) necp_route_rules
;
401 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
);
402 static bool necp_remove_route_rule(struct necp_route_rule_list
*list
, u_int32_t route_rule_id
);
403 static bool necp_route_is_allowed(struct rtentry
*route
, ifnet_t interface
, u_int32_t route_rule_id
, u_int32_t
*interface_type_denied
);
404 static struct necp_route_rule
*necp_lookup_route_rule_locked(struct necp_route_rule_list
*list
, u_int32_t route_rule_id
);
406 #define MAX_AGGREGATE_ROUTE_RULES 16
407 struct necp_aggregate_route_rule
{
408 LIST_ENTRY(necp_aggregate_route_rule
) chain
;
410 u_int32_t rule_ids
[MAX_AGGREGATE_ROUTE_RULES
];
412 static LIST_HEAD(necp_aggregate_route_rule_list
, necp_aggregate_route_rule
) necp_aggregate_route_rules
;
413 static u_int32_t
necp_create_aggregate_route_rule(u_int32_t
*rule_ids
);
415 // Sysctl definitions
416 static int sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
;
418 SYSCTL_NODE(_net
, OID_AUTO
, necp
, CTLFLAG_RW
| CTLFLAG_LOCKED
, 0, "NECP");
419 SYSCTL_INT(_net_necp
, NECPCTL_PASS_LOOPBACK
, pass_loopback
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_pass_loopback
, 0, "");
420 SYSCTL_INT(_net_necp
, NECPCTL_PASS_KEEPALIVES
, pass_keepalives
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_pass_keepalives
, 0, "");
421 SYSCTL_INT(_net_necp
, NECPCTL_DEBUG
, debug
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_debug
, 0, "");
422 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", "");
423 SYSCTL_LONG(_net_necp
, NECPCTL_SOCKET_POLICY_COUNT
, socket_policy_count
, CTLFLAG_LOCKED
| CTLFLAG_RD
, &necp_kernel_socket_policies_count
, "");
424 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
, "");
425 SYSCTL_LONG(_net_necp
, NECPCTL_IP_POLICY_COUNT
, ip_policy_count
, CTLFLAG_LOCKED
| CTLFLAG_RD
, &necp_kernel_ip_output_policies_count
, "");
426 SYSCTL_INT(_net_necp
, NECPCTL_SESSION_COUNT
, session_count
, CTLFLAG_LOCKED
| CTLFLAG_RD
, &necp_session_count
, 0, "");
428 // Session order allocation
430 necp_allocate_new_session_order(u_int32_t priority
, u_int32_t control_unit
)
432 u_int32_t new_order
= 0;
434 // For now, just allocate 1000 orders for each priority
435 if (priority
== NECP_SESSION_PRIORITY_UNKNOWN
|| priority
> NECP_SESSION_NUM_PRIORITIES
) {
436 priority
= NECP_SESSION_PRIORITY_DEFAULT
;
439 // Use the control unit to decide the offset into the priority list
440 new_order
= (control_unit
) + ((priority
- 1) * 1000);
445 static inline u_int32_t
446 necp_get_first_order_for_priority(u_int32_t priority
)
448 return (((priority
- 1) * 1000) + 1);
453 sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
455 #pragma unused(arg1, arg2)
456 int error
= sysctl_handle_int(oidp
, oidp
->oid_arg1
, oidp
->oid_arg2
, req
);
457 if (necp_drop_all_level
== 0) {
458 necp_drop_all_order
= 0;
460 necp_drop_all_order
= necp_get_first_order_for_priority(necp_drop_all_level
);
465 // Kernel Control functions
466 static errno_t
necp_register_control(void);
467 static errno_t
necp_ctl_connect(kern_ctl_ref kctlref
, struct sockaddr_ctl
*sac
, void **unitinfo
);
468 static errno_t
necp_ctl_disconnect(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
);
469 static errno_t
necp_ctl_send(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, mbuf_t m
, int flags
);
470 static void necp_ctl_rcvd(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, int flags
);
471 static errno_t
necp_ctl_getopt(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, int opt
, void *data
, size_t *len
);
472 static errno_t
necp_ctl_setopt(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, int opt
, void *data
, size_t len
);
474 static bool necp_send_ctl_data(struct necp_session
*session
, u_int8_t
*buffer
, size_t buffer_size
);
481 result
= necp_register_control();
486 necp_kernel_policy_grp_attr
= lck_grp_attr_alloc_init();
487 if (necp_kernel_policy_grp_attr
== NULL
) {
488 NECPLOG0(LOG_ERR
, "lck_grp_attr_alloc_init failed");
493 necp_kernel_policy_mtx_grp
= lck_grp_alloc_init(NECP_CONTROL_NAME
, necp_kernel_policy_grp_attr
);
494 if (necp_kernel_policy_mtx_grp
== NULL
) {
495 NECPLOG0(LOG_ERR
, "lck_grp_alloc_init failed");
500 necp_kernel_policy_mtx_attr
= lck_attr_alloc_init();
501 if (necp_kernel_policy_mtx_attr
== NULL
) {
502 NECPLOG0(LOG_ERR
, "lck_attr_alloc_init failed");
507 lck_rw_init(&necp_kernel_policy_lock
, necp_kernel_policy_mtx_grp
, necp_kernel_policy_mtx_attr
);
509 necp_route_rule_grp_attr
= lck_grp_attr_alloc_init();
510 if (necp_route_rule_grp_attr
== NULL
) {
511 NECPLOG0(LOG_ERR
, "lck_grp_attr_alloc_init failed");
516 necp_route_rule_mtx_grp
= lck_grp_alloc_init("necp_route_rule", necp_route_rule_grp_attr
);
517 if (necp_route_rule_mtx_grp
== NULL
) {
518 NECPLOG0(LOG_ERR
, "lck_grp_alloc_init failed");
523 necp_route_rule_mtx_attr
= lck_attr_alloc_init();
524 if (necp_route_rule_mtx_attr
== NULL
) {
525 NECPLOG0(LOG_ERR
, "lck_attr_alloc_init failed");
530 lck_rw_init(&necp_route_rule_lock
, necp_route_rule_mtx_grp
, necp_route_rule_mtx_attr
);
534 LIST_INIT(&necp_kernel_socket_policies
);
535 LIST_INIT(&necp_kernel_ip_output_policies
);
537 LIST_INIT(&necp_account_id_list
);
539 LIST_INIT(&necp_uuid_service_id_list
);
541 LIST_INIT(&necp_registered_service_list
);
543 LIST_INIT(&necp_route_rules
);
544 LIST_INIT(&necp_aggregate_route_rules
);
546 necp_uuid_app_id_hashtbl
= hashinit(NECP_UUID_APP_ID_HASH_SIZE
, M_NECP
, &necp_uuid_app_id_hash_mask
);
547 necp_uuid_app_id_hash_num_buckets
= necp_uuid_app_id_hash_mask
+ 1;
548 necp_num_uuid_app_id_mappings
= 0;
549 necp_uuid_app_id_mappings_dirty
= FALSE
;
551 necp_kernel_application_policies_condition_mask
= 0;
552 necp_kernel_socket_policies_condition_mask
= 0;
553 necp_kernel_ip_output_policies_condition_mask
= 0;
555 necp_kernel_application_policies_count
= 0;
556 necp_kernel_socket_policies_count
= 0;
557 necp_kernel_socket_policies_non_app_count
= 0;
558 necp_kernel_ip_output_policies_count
= 0;
559 necp_kernel_ip_output_policies_non_id_count
= 0;
561 necp_last_policy_id
= 0;
562 necp_last_kernel_policy_id
= 0;
563 necp_last_uuid_id
= 0;
564 necp_last_string_id
= 0;
565 necp_last_route_rule_id
= 0;
566 necp_last_aggregate_route_rule_id
= 0;
568 necp_kernel_socket_policies_gencount
= 1;
570 memset(&necp_kernel_socket_policies_map
, 0, sizeof(necp_kernel_socket_policies_map
));
571 memset(&necp_kernel_ip_output_policies_map
, 0, sizeof(necp_kernel_ip_output_policies_map
));
572 necp_kernel_socket_policies_app_layer_map
= NULL
;
576 if (necp_kernel_policy_mtx_attr
!= NULL
) {
577 lck_attr_free(necp_kernel_policy_mtx_attr
);
578 necp_kernel_policy_mtx_attr
= NULL
;
580 if (necp_kernel_policy_mtx_grp
!= NULL
) {
581 lck_grp_free(necp_kernel_policy_mtx_grp
);
582 necp_kernel_policy_mtx_grp
= NULL
;
584 if (necp_kernel_policy_grp_attr
!= NULL
) {
585 lck_grp_attr_free(necp_kernel_policy_grp_attr
);
586 necp_kernel_policy_grp_attr
= NULL
;
588 if (necp_route_rule_mtx_attr
!= NULL
) {
589 lck_attr_free(necp_route_rule_mtx_attr
);
590 necp_route_rule_mtx_attr
= NULL
;
592 if (necp_route_rule_mtx_grp
!= NULL
) {
593 lck_grp_free(necp_route_rule_mtx_grp
);
594 necp_route_rule_mtx_grp
= NULL
;
596 if (necp_route_rule_grp_attr
!= NULL
) {
597 lck_grp_attr_free(necp_route_rule_grp_attr
);
598 necp_route_rule_grp_attr
= NULL
;
600 if (necp_kctlref
!= NULL
) {
601 ctl_deregister(necp_kctlref
);
609 necp_register_control(void)
611 struct kern_ctl_reg kern_ctl
;
614 // Create a tag to allocate memory
615 necp_malloc_tag
= OSMalloc_Tagalloc(NECP_CONTROL_NAME
, OSMT_DEFAULT
);
617 // Find a unique value for our interface family
618 result
= mbuf_tag_id_find(NECP_CONTROL_NAME
, &necp_family
);
620 NECPLOG(LOG_ERR
, "mbuf_tag_id_find_internal failed: %d", result
);
624 bzero(&kern_ctl
, sizeof(kern_ctl
));
625 strlcpy(kern_ctl
.ctl_name
, NECP_CONTROL_NAME
, sizeof(kern_ctl
.ctl_name
));
626 kern_ctl
.ctl_name
[sizeof(kern_ctl
.ctl_name
) - 1] = 0;
627 kern_ctl
.ctl_flags
= CTL_FLAG_PRIVILEGED
; // Require root
628 kern_ctl
.ctl_sendsize
= 64 * 1024;
629 kern_ctl
.ctl_recvsize
= 64 * 1024;
630 kern_ctl
.ctl_connect
= necp_ctl_connect
;
631 kern_ctl
.ctl_disconnect
= necp_ctl_disconnect
;
632 kern_ctl
.ctl_send
= necp_ctl_send
;
633 kern_ctl
.ctl_rcvd
= necp_ctl_rcvd
;
634 kern_ctl
.ctl_setopt
= necp_ctl_setopt
;
635 kern_ctl
.ctl_getopt
= necp_ctl_getopt
;
637 result
= ctl_register(&kern_ctl
, &necp_kctlref
);
639 NECPLOG(LOG_ERR
, "ctl_register failed: %d", result
);
647 necp_post_change_event(struct kev_necp_policies_changed_data
*necp_event_data
)
649 struct kev_msg ev_msg
;
650 memset(&ev_msg
, 0, sizeof(ev_msg
));
652 ev_msg
.vendor_code
= KEV_VENDOR_APPLE
;
653 ev_msg
.kev_class
= KEV_NETWORK_CLASS
;
654 ev_msg
.kev_subclass
= KEV_NECP_SUBCLASS
;
655 ev_msg
.event_code
= KEV_NECP_POLICIES_CHANGED
;
657 ev_msg
.dv
[0].data_ptr
= necp_event_data
;
658 ev_msg
.dv
[0].data_length
= sizeof(necp_event_data
->changed_count
);
659 ev_msg
.dv
[1].data_length
= 0;
661 kev_post_msg(&ev_msg
);
665 necp_ctl_connect(kern_ctl_ref kctlref
, struct sockaddr_ctl
*sac
, void **unitinfo
)
667 #pragma unused(kctlref)
668 *unitinfo
= necp_create_session(sac
->sc_unit
);
669 if (*unitinfo
== NULL
) {
670 // Could not allocate session
678 necp_ctl_disconnect(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
)
680 #pragma unused(kctlref, unit)
681 struct necp_session
*session
= (struct necp_session
*)unitinfo
;
682 if (session
!= NULL
) {
683 necp_policy_mark_all_for_deletion(session
);
684 necp_policy_apply_all(session
);
685 necp_delete_session((struct necp_session
*)unitinfo
);
694 necp_packet_find_tlv(mbuf_t packet
, int offset
, u_int8_t type
, int *err
, int next
)
696 size_t cursor
= offset
;
698 u_int32_t curr_length
;
705 error
= mbuf_copydata(packet
, cursor
, sizeof(curr_type
), &curr_type
);
712 curr_type
= NECP_TLV_NIL
;
715 if (curr_type
!= type
) {
716 cursor
+= sizeof(curr_type
);
717 error
= mbuf_copydata(packet
, cursor
, sizeof(curr_length
), &curr_length
);
722 cursor
+= (sizeof(curr_length
) + curr_length
);
724 } while (curr_type
!= type
);
730 necp_packet_get_tlv_at_offset(mbuf_t packet
, int tlv_offset
, u_int32_t buff_len
, void *buff
, u_int32_t
*value_size
)
735 if (tlv_offset
< 0) {
739 error
= mbuf_copydata(packet
, tlv_offset
+ sizeof(u_int8_t
), sizeof(length
), &length
);
744 u_int32_t total_len
= m_length2(packet
, NULL
);
745 if (total_len
< (tlv_offset
+ sizeof(u_int8_t
) + sizeof(length
) + length
)) {
746 NECPLOG(LOG_ERR
, "Got a bad TLV, length (%u) + offset (%d) < total length (%u)",
747 length
, (tlv_offset
+ sizeof(u_int8_t
) + sizeof(length
)), total_len
);
751 if (value_size
!= NULL
) {
752 *value_size
= length
;
755 if (buff
!= NULL
&& buff_len
> 0) {
756 u_int32_t to_copy
= (length
< buff_len
) ? length
: buff_len
;
757 error
= mbuf_copydata(packet
, tlv_offset
+ sizeof(u_int8_t
) + sizeof(length
), to_copy
, buff
);
767 necp_packet_get_tlv(mbuf_t packet
, int offset
, u_int8_t type
, u_int32_t buff_len
, void *buff
, u_int32_t
*value_size
)
772 tlv_offset
= necp_packet_find_tlv(packet
, offset
, type
, &error
, 0);
773 if (tlv_offset
< 0) {
777 return (necp_packet_get_tlv_at_offset(packet
, tlv_offset
, buff_len
, buff
, value_size
));
781 necp_buffer_write_packet_header(u_int8_t
*buffer
, u_int8_t packet_type
, u_int8_t flags
, u_int32_t message_id
)
783 ((struct necp_packet_header
*)(void *)buffer
)->packet_type
= packet_type
;
784 ((struct necp_packet_header
*)(void *)buffer
)->flags
= flags
;
785 ((struct necp_packet_header
*)(void *)buffer
)->message_id
= message_id
;
786 return (buffer
+ sizeof(struct necp_packet_header
));
791 necp_buffer_write_tlv_if_different(u_int8_t
*buffer
, const u_int8_t
*max
, u_int8_t type
,
792 u_int32_t length
, const void *value
, bool *updated
)
794 u_int8_t
*next_tlv
= (u_int8_t
*)(buffer
+ sizeof(type
) + sizeof(length
) + length
);
795 if (next_tlv
<= max
) {
796 if (*updated
|| *(u_int8_t
*)(buffer
) != type
) {
797 *(u_int8_t
*)(buffer
) = type
;
800 if (*updated
|| *(u_int32_t
*)(void *)(buffer
+ sizeof(type
)) != length
) {
801 *(u_int32_t
*)(void *)(buffer
+ sizeof(type
)) = length
;
805 if (*updated
|| memcmp((u_int8_t
*)(buffer
+ sizeof(type
) + sizeof(length
)), value
, length
) != 0) {
806 memcpy((u_int8_t
*)(buffer
+ sizeof(type
) + sizeof(length
)), value
, length
);
815 necp_buffer_write_tlv(u_int8_t
*buffer
, u_int8_t type
, u_int32_t length
, const void *value
)
817 *(u_int8_t
*)(buffer
) = type
;
818 *(u_int32_t
*)(void *)(buffer
+ sizeof(type
)) = length
;
820 memcpy((u_int8_t
*)(buffer
+ sizeof(type
) + sizeof(length
)), value
, length
);
823 return ((u_int8_t
*)(buffer
+ sizeof(type
) + sizeof(length
) + length
));
827 necp_buffer_get_tlv_type(u_int8_t
*buffer
, int tlv_offset
)
829 u_int8_t
*type
= NULL
;
831 if (buffer
== NULL
) {
835 type
= (u_int8_t
*)((u_int8_t
*)buffer
+ tlv_offset
);
836 return (type
? *type
: 0);
840 necp_buffer_get_tlv_length(u_int8_t
*buffer
, int tlv_offset
)
842 u_int32_t
*length
= NULL
;
844 if (buffer
== NULL
) {
848 length
= (u_int32_t
*)(void *)((u_int8_t
*)buffer
+ tlv_offset
+ sizeof(u_int8_t
));
849 return (length
? *length
: 0);
853 necp_buffer_get_tlv_value(u_int8_t
*buffer
, int tlv_offset
, u_int32_t
*value_size
)
855 u_int8_t
*value
= NULL
;
856 u_int32_t length
= necp_buffer_get_tlv_length(buffer
, tlv_offset
);
862 *value_size
= length
;
865 value
= (u_int8_t
*)((u_int8_t
*)buffer
+ tlv_offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
));
870 necp_buffer_find_tlv(u_int8_t
*buffer
, u_int32_t buffer_length
, int offset
, u_int8_t type
, int next
)
877 u_int32_t curr_length
;
881 if ((((u_int32_t
)cursor
) + sizeof(curr_type
) + sizeof(curr_length
)) > buffer_length
) {
885 curr_type
= necp_buffer_get_tlv_type(buffer
, cursor
);
888 curr_type
= NECP_TLV_NIL
;
890 curr_length
= necp_buffer_get_tlv_length(buffer
, cursor
);
891 next_cursor
= (cursor
+ sizeof(curr_type
) + sizeof(curr_length
) + curr_length
);
892 if (curr_type
== type
) {
893 // check if entire TLV fits inside buffer
894 if (((u_int32_t
)next_cursor
) <= buffer_length
) {
900 cursor
= next_cursor
;
905 necp_send_ctl_data(struct necp_session
*session
, u_int8_t
*buffer
, size_t buffer_size
)
909 if (necp_kctlref
== NULL
|| session
== NULL
|| buffer
== NULL
|| buffer_size
== 0) {
913 error
= ctl_enqueuedata(necp_kctlref
, session
->control_unit
, buffer
, buffer_size
, CTL_DATA_EOR
);
919 necp_send_success_response(struct necp_session
*session
, u_int8_t packet_type
, u_int32_t message_id
)
922 u_int8_t
*response
= NULL
;
923 u_int8_t
*cursor
= NULL
;
924 size_t response_size
= sizeof(struct necp_packet_header
) + sizeof(u_int8_t
) + sizeof(u_int32_t
);
925 MALLOC(response
, u_int8_t
*, response_size
, M_NECP
, M_WAITOK
);
926 if (response
== NULL
) {
930 cursor
= necp_buffer_write_packet_header(cursor
, packet_type
, NECP_PACKET_FLAGS_RESPONSE
, message_id
);
931 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_NIL
, 0, NULL
);
933 if (!(success
= necp_send_ctl_data(session
, (u_int8_t
*)response
, response_size
))) {
934 NECPLOG0(LOG_ERR
, "Failed to send response");
937 FREE(response
, M_NECP
);
942 necp_send_error_response(struct necp_session
*session
, u_int8_t packet_type
, u_int32_t message_id
, u_int32_t error
)
945 u_int8_t
*response
= NULL
;
946 u_int8_t
*cursor
= NULL
;
947 size_t response_size
= sizeof(struct necp_packet_header
) + sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(u_int32_t
);
948 MALLOC(response
, u_int8_t
*, response_size
, M_NECP
, M_WAITOK
);
949 if (response
== NULL
) {
953 cursor
= necp_buffer_write_packet_header(cursor
, packet_type
, NECP_PACKET_FLAGS_RESPONSE
, message_id
);
954 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_ERROR
, sizeof(error
), &error
);
956 if (!(success
= necp_send_ctl_data(session
, (u_int8_t
*)response
, response_size
))) {
957 NECPLOG0(LOG_ERR
, "Failed to send response");
960 FREE(response
, M_NECP
);
965 necp_send_policy_id_response(struct necp_session
*session
, u_int8_t packet_type
, u_int32_t message_id
, necp_policy_id policy_id
)
968 u_int8_t
*response
= NULL
;
969 u_int8_t
*cursor
= NULL
;
970 size_t response_size
= sizeof(struct necp_packet_header
) + sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(u_int32_t
);
971 MALLOC(response
, u_int8_t
*, response_size
, M_NECP
, M_WAITOK
);
972 if (response
== NULL
) {
976 cursor
= necp_buffer_write_packet_header(cursor
, packet_type
, NECP_PACKET_FLAGS_RESPONSE
, message_id
);
977 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ID
, sizeof(policy_id
), &policy_id
);
979 if (!(success
= necp_send_ctl_data(session
, (u_int8_t
*)response
, response_size
))) {
980 NECPLOG0(LOG_ERR
, "Failed to send response");
983 FREE(response
, M_NECP
);
988 necp_ctl_send(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, mbuf_t packet
, int flags
)
990 #pragma unused(kctlref, unit, flags)
991 struct necp_session
*session
= (struct necp_session
*)unitinfo
;
992 struct necp_packet_header header
;
995 if (session
== NULL
) {
996 NECPLOG0(LOG_ERR
, "Got a NULL session");
1001 if (mbuf_pkthdr_len(packet
) < sizeof(header
)) {
1002 NECPLOG(LOG_ERR
, "Got a bad packet, length (%lu) < sizeof header (%lu)", mbuf_pkthdr_len(packet
), sizeof(header
));
1007 error
= mbuf_copydata(packet
, 0, sizeof(header
), &header
);
1009 NECPLOG(LOG_ERR
, "mbuf_copydata failed for the header: %d", error
);
1014 if (session
->proc_locked
) {
1015 // Verify that the calling process is allowed to send messages
1017 proc_getexecutableuuid(current_proc(), proc_uuid
, sizeof(proc_uuid
));
1018 if (uuid_compare(proc_uuid
, session
->proc_uuid
) != 0) {
1019 necp_send_error_response(session
, header
.packet_type
, header
.message_id
, NECP_ERROR_INVALID_PROCESS
);
1023 // If not locked, update the proc_uuid and proc_pid of the session
1024 proc_getexecutableuuid(current_proc(), session
->proc_uuid
, sizeof(session
->proc_uuid
));
1025 session
->proc_pid
= proc_pid(current_proc());
1028 switch (header
.packet_type
) {
1029 case NECP_PACKET_TYPE_POLICY_ADD
: {
1030 necp_handle_policy_add(session
, header
.message_id
, packet
, sizeof(header
));
1033 case NECP_PACKET_TYPE_POLICY_GET
: {
1034 necp_handle_policy_get(session
, header
.message_id
, packet
, sizeof(header
));
1037 case NECP_PACKET_TYPE_POLICY_DELETE
: {
1038 necp_handle_policy_delete(session
, header
.message_id
, packet
, sizeof(header
));
1041 case NECP_PACKET_TYPE_POLICY_APPLY_ALL
: {
1042 necp_handle_policy_apply_all(session
, header
.message_id
, packet
, sizeof(header
));
1045 case NECP_PACKET_TYPE_POLICY_LIST_ALL
: {
1046 necp_handle_policy_list_all(session
, header
.message_id
, packet
, sizeof(header
));
1049 case NECP_PACKET_TYPE_POLICY_DELETE_ALL
: {
1050 necp_handle_policy_delete_all(session
, header
.message_id
, packet
, sizeof(header
));
1053 case NECP_PACKET_TYPE_POLICY_DUMP_ALL
: {
1054 necp_handle_policy_dump_all(session
, header
.message_id
, packet
, sizeof(header
));
1057 case NECP_PACKET_TYPE_SET_SESSION_PRIORITY
: {
1058 necp_handle_set_session_priority(session
, header
.message_id
, packet
, sizeof(header
));
1061 case NECP_PACKET_TYPE_LOCK_SESSION_TO_PROC
: {
1062 necp_handle_lock_session_to_proc(session
, header
.message_id
, packet
, sizeof(header
));
1065 case NECP_PACKET_TYPE_REGISTER_SERVICE
: {
1066 necp_handle_register_service(session
, header
.message_id
, packet
, sizeof(header
));
1069 case NECP_PACKET_TYPE_UNREGISTER_SERVICE
: {
1070 necp_handle_unregister_service(session
, header
.message_id
, packet
, sizeof(header
));
1074 NECPLOG(LOG_ERR
, "Received unknown message type %d", header
.packet_type
);
1075 necp_send_error_response(session
, header
.packet_type
, header
.message_id
, NECP_ERROR_UNKNOWN_PACKET_TYPE
);
1086 necp_ctl_rcvd(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, int flags
)
1088 #pragma unused(kctlref, unit, unitinfo, flags)
1093 necp_ctl_getopt(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, int opt
, void *data
, size_t *len
)
1095 #pragma unused(kctlref, unit, unitinfo, opt, data, len)
1100 necp_ctl_setopt(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, int opt
, void *data
, size_t len
)
1102 #pragma unused(kctlref, unit, unitinfo, opt, data, len)
1106 // Session Management
1107 static struct necp_session
*
1108 necp_create_session(u_int32_t control_unit
)
1110 struct necp_session
*new_session
= NULL
;
1112 MALLOC(new_session
, struct necp_session
*, sizeof(*new_session
), M_NECP
, M_WAITOK
);
1113 if (new_session
== NULL
) {
1117 NECPLOG(LOG_DEBUG
, "Create NECP session, control unit %d", control_unit
);
1119 memset(new_session
, 0, sizeof(*new_session
));
1120 new_session
->session_priority
= NECP_SESSION_PRIORITY_UNKNOWN
;
1121 new_session
->session_order
= necp_allocate_new_session_order(new_session
->session_priority
, control_unit
);
1122 new_session
->control_unit
= control_unit
;
1123 new_session
->dirty
= FALSE
;
1124 LIST_INIT(&new_session
->policies
);
1126 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1127 necp_session_count
++;
1128 lck_rw_done(&necp_kernel_policy_lock
);
1131 return (new_session
);
1135 necp_delete_session(struct necp_session
*session
)
1137 if (session
!= NULL
) {
1138 struct necp_service_registration
*service
= NULL
;
1139 struct necp_service_registration
*temp_service
= NULL
;
1140 LIST_FOREACH_SAFE(service
, &session
->services
, session_chain
, temp_service
) {
1141 LIST_REMOVE(service
, session_chain
);
1142 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1143 LIST_REMOVE(service
, kernel_chain
);
1144 lck_rw_done(&necp_kernel_policy_lock
);
1145 FREE(service
, M_NECP
);
1148 NECPLOG0(LOG_DEBUG
, "Deleted NECP session");
1150 FREE(session
, M_NECP
);
1152 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1153 necp_session_count
--;
1154 lck_rw_done(&necp_kernel_policy_lock
);
1158 // Session Policy Management
1160 static inline u_int8_t
1161 necp_policy_result_get_type_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1163 return ((buffer
&& length
>= sizeof(u_int8_t
)) ? buffer
[0] : 0);
1166 static inline u_int32_t
1167 necp_policy_result_get_parameter_length_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1169 return ((buffer
&& length
> sizeof(u_int8_t
)) ? (length
- sizeof(u_int8_t
)) : 0);
1172 static inline u_int8_t
*
1173 necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1175 return ((buffer
&& length
> sizeof(u_int8_t
)) ? (buffer
+ sizeof(u_int8_t
)) : NULL
);
1179 necp_policy_result_requires_route_rules(u_int8_t
*buffer
, u_int32_t length
)
1181 u_int8_t type
= necp_policy_result_get_type_from_buffer(buffer
, length
);
1182 if (type
== NECP_POLICY_RESULT_ROUTE_RULES
) {
1189 necp_address_is_valid(struct sockaddr
*address
)
1191 if (address
->sa_family
== AF_INET
) {
1192 return (address
->sa_len
== sizeof(struct sockaddr_in
));
1193 } else if (address
->sa_family
== AF_INET6
) {
1194 return (address
->sa_len
== sizeof(struct sockaddr_in6
));
1201 necp_policy_result_is_valid(u_int8_t
*buffer
, u_int32_t length
)
1203 bool validated
= FALSE
;
1204 u_int8_t type
= necp_policy_result_get_type_from_buffer(buffer
, length
);
1205 u_int32_t parameter_length
= necp_policy_result_get_parameter_length_from_buffer(buffer
, length
);
1207 case NECP_POLICY_RESULT_PASS
: {
1211 case NECP_POLICY_RESULT_SKIP
: {
1212 if (parameter_length
>= sizeof(u_int32_t
)) {
1217 case NECP_POLICY_RESULT_DROP
: {
1221 case NECP_POLICY_RESULT_SOCKET_DIVERT
: {
1222 if (parameter_length
>= sizeof(u_int32_t
)) {
1227 case NECP_POLICY_RESULT_SOCKET_SCOPED
: {
1228 if (parameter_length
> 0) {
1233 case NECP_POLICY_RESULT_IP_TUNNEL
: {
1234 if (parameter_length
> sizeof(u_int32_t
)) {
1239 case NECP_POLICY_RESULT_SOCKET_FILTER
: {
1240 if (parameter_length
>= sizeof(u_int32_t
)) {
1245 case NECP_POLICY_RESULT_ROUTE_RULES
: {
1249 case NECP_POLICY_RESULT_TRIGGER
:
1250 case NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
:
1251 case NECP_POLICY_RESULT_TRIGGER_SCOPED
:
1252 case NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
:
1253 case NECP_POLICY_RESULT_USE_NETAGENT
: {
1254 if (parameter_length
>= sizeof(uuid_t
)) {
1266 NECPLOG(LOG_DEBUG
, "Policy result type %d, valid %d", type
, validated
);
1272 static inline u_int8_t
1273 necp_policy_condition_get_type_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1275 return ((buffer
&& length
>= sizeof(u_int8_t
)) ? buffer
[0] : 0);
1278 static inline u_int8_t
1279 necp_policy_condition_get_flags_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1281 return ((buffer
&& length
>= (2 * sizeof(u_int8_t
))) ? buffer
[1] : 0);
1284 static inline u_int32_t
1285 necp_policy_condition_get_value_length_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1287 return ((buffer
&& length
>= (2 * sizeof(u_int8_t
))) ? (length
- (2 * sizeof(u_int8_t
))) : 0);
1290 static inline u_int8_t
*
1291 necp_policy_condition_get_value_pointer_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1293 return ((buffer
&& length
> (2 * sizeof(u_int8_t
))) ? (buffer
+ (2 * sizeof(u_int8_t
))) : NULL
);
1297 necp_policy_condition_is_default(u_int8_t
*buffer
, u_int32_t length
)
1299 return (necp_policy_condition_get_type_from_buffer(buffer
, length
) == NECP_POLICY_CONDITION_DEFAULT
);
1303 necp_policy_condition_is_application(u_int8_t
*buffer
, u_int32_t length
)
1305 return (necp_policy_condition_get_type_from_buffer(buffer
, length
) == NECP_POLICY_CONDITION_APPLICATION
);
1309 necp_policy_condition_requires_application(u_int8_t
*buffer
, u_int32_t length
)
1311 u_int8_t type
= necp_policy_condition_get_type_from_buffer(buffer
, length
);
1312 return (type
== NECP_POLICY_CONDITION_REAL_APPLICATION
);
1316 necp_policy_condition_is_valid(u_int8_t
*buffer
, u_int32_t length
, u_int8_t policy_result_type
)
1318 bool validated
= FALSE
;
1319 bool result_cannot_have_ip_layer
= (policy_result_type
== NECP_POLICY_RESULT_SOCKET_DIVERT
||
1320 policy_result_type
== NECP_POLICY_RESULT_SOCKET_FILTER
||
1321 policy_result_type
== NECP_POLICY_RESULT_TRIGGER
||
1322 policy_result_type
== NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
||
1323 policy_result_type
== NECP_POLICY_RESULT_TRIGGER_SCOPED
||
1324 policy_result_type
== NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
||
1325 policy_result_type
== NECP_POLICY_RESULT_SOCKET_SCOPED
||
1326 policy_result_type
== NECP_POLICY_RESULT_ROUTE_RULES
||
1327 policy_result_type
== NECP_POLICY_RESULT_USE_NETAGENT
) ? TRUE
: FALSE
;
1328 u_int32_t condition_length
= necp_policy_condition_get_value_length_from_buffer(buffer
, length
);
1329 u_int8_t
*condition_value
= necp_policy_condition_get_value_pointer_from_buffer(buffer
, length
);
1330 u_int8_t type
= necp_policy_condition_get_type_from_buffer(buffer
, length
);
1331 u_int8_t flags
= necp_policy_condition_get_flags_from_buffer(buffer
, length
);
1333 case NECP_POLICY_CONDITION_APPLICATION
:
1334 case NECP_POLICY_CONDITION_REAL_APPLICATION
: {
1335 if (!(flags
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
) &&
1336 condition_length
>= sizeof(uuid_t
) &&
1337 condition_value
!= NULL
&&
1338 !uuid_is_null(condition_value
)) {
1343 case NECP_POLICY_CONDITION_DOMAIN
:
1344 case NECP_POLICY_CONDITION_ACCOUNT
:
1345 case NECP_POLICY_CONDITION_BOUND_INTERFACE
: {
1346 if (condition_length
> 0) {
1351 case NECP_POLICY_CONDITION_TRAFFIC_CLASS
: {
1352 if (condition_length
>= sizeof(struct necp_policy_condition_tc_range
)) {
1357 case NECP_POLICY_CONDITION_DEFAULT
:
1358 case NECP_POLICY_CONDITION_ALL_INTERFACES
:
1359 case NECP_POLICY_CONDITION_ENTITLEMENT
: {
1360 if (!(flags
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
)) {
1365 case NECP_POLICY_CONDITION_IP_PROTOCOL
: {
1366 if (condition_length
>= sizeof(u_int16_t
)) {
1371 case NECP_POLICY_CONDITION_PID
: {
1372 if (condition_length
>= sizeof(pid_t
) &&
1373 condition_value
!= NULL
&&
1374 *((pid_t
*)(void *)condition_value
) != 0) {
1379 case NECP_POLICY_CONDITION_UID
: {
1380 if (condition_length
>= sizeof(uid_t
)) {
1385 case NECP_POLICY_CONDITION_LOCAL_ADDR
:
1386 case NECP_POLICY_CONDITION_REMOTE_ADDR
: {
1387 if (!result_cannot_have_ip_layer
&& condition_length
>= sizeof(struct necp_policy_condition_addr
) &&
1388 necp_address_is_valid(&((struct necp_policy_condition_addr
*)(void *)condition_value
)->address
.sa
)) {
1393 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE
:
1394 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE
: {
1395 if (!result_cannot_have_ip_layer
&& condition_length
>= sizeof(struct necp_policy_condition_addr_range
) &&
1396 necp_address_is_valid(&((struct necp_policy_condition_addr_range
*)(void *)condition_value
)->start_address
.sa
) &&
1397 necp_address_is_valid(&((struct necp_policy_condition_addr_range
*)(void *)condition_value
)->end_address
.sa
)) {
1409 NECPLOG(LOG_DEBUG
, "Policy condition type %d, valid %d", type
, validated
);
1416 necp_policy_route_rule_is_default(u_int8_t
*buffer
, u_int32_t length
)
1418 return (necp_policy_condition_get_value_length_from_buffer(buffer
, length
) == 0 &&
1419 necp_policy_condition_get_flags_from_buffer(buffer
, length
) == 0);
1423 necp_policy_route_rule_is_valid(u_int8_t
*buffer
, u_int32_t length
)
1425 bool validated
= FALSE
;
1426 u_int8_t type
= necp_policy_condition_get_type_from_buffer(buffer
, length
);
1428 case NECP_ROUTE_RULE_ALLOW_INTERFACE
: {
1432 case NECP_ROUTE_RULE_DENY_INTERFACE
: {
1436 case NECP_ROUTE_RULE_QOS_MARKING
: {
1447 NECPLOG(LOG_DEBUG
, "Policy route rule type %d, valid %d", type
, validated
);
1454 necp_handle_set_session_priority(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1457 struct necp_session_policy
*policy
= NULL
;
1458 struct necp_session_policy
*temp_policy
= NULL
;
1459 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
1460 u_int32_t requested_session_priority
= NECP_SESSION_PRIORITY_UNKNOWN
;
1463 error
= necp_packet_get_tlv(packet
, offset
, NECP_TLV_SESSION_PRIORITY
, sizeof(requested_session_priority
), &requested_session_priority
, NULL
);
1465 NECPLOG(LOG_ERR
, "Failed to get session priority: %d", error
);
1466 response_error
= NECP_ERROR_INVALID_TLV
;
1470 if (session
== NULL
) {
1471 NECPLOG0(LOG_ERR
, "Failed to find session");
1472 response_error
= NECP_ERROR_INTERNAL
;
1476 // Enforce special session priorities with entitlements
1477 if (requested_session_priority
== NECP_SESSION_PRIORITY_CONTROL
||
1478 requested_session_priority
== NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL
) {
1479 errno_t cred_result
= priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES
, 0);
1480 if (cred_result
!= 0) {
1481 NECPLOG(LOG_ERR
, "Session does not hold necessary entitlement to claim priority level %d", requested_session_priority
);
1486 if (session
->session_priority
!= requested_session_priority
) {
1487 session
->session_priority
= requested_session_priority
;
1488 session
->session_order
= necp_allocate_new_session_order(session
->session_priority
, session
->control_unit
);
1489 session
->dirty
= TRUE
;
1491 // Mark all policies as needing updates
1492 LIST_FOREACH_SAFE(policy
, &session
->policies
, chain
, temp_policy
) {
1493 policy
->pending_update
= TRUE
;
1497 necp_send_success_response(session
, NECP_PACKET_TYPE_SET_SESSION_PRIORITY
, message_id
);
1501 necp_send_error_response(session
, NECP_PACKET_TYPE_SET_SESSION_PRIORITY
, message_id
, response_error
);
1505 necp_handle_lock_session_to_proc(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1507 #pragma unused(packet, offset)
1508 // proc_uuid already filled out
1509 session
->proc_locked
= TRUE
;
1510 necp_send_success_response(session
, NECP_PACKET_TYPE_LOCK_SESSION_TO_PROC
, message_id
);
1514 necp_handle_register_service(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1517 struct necp_service_registration
*new_service
= NULL
;
1518 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
1519 uuid_t service_uuid
;
1520 uuid_clear(service_uuid
);
1522 if (session
== NULL
) {
1523 NECPLOG0(LOG_ERR
, "Failed to find session");
1524 response_error
= NECP_ERROR_INTERNAL
;
1528 // Enforce entitlements
1529 errno_t cred_result
= priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES
, 0);
1530 if (cred_result
!= 0) {
1531 NECPLOG0(LOG_ERR
, "Session does not hold necessary entitlement to register service");
1535 // Read service uuid
1536 error
= necp_packet_get_tlv(packet
, offset
, NECP_TLV_SERVICE_UUID
, sizeof(uuid_t
), service_uuid
, NULL
);
1538 NECPLOG(LOG_ERR
, "Failed to get service UUID: %d", error
);
1539 response_error
= NECP_ERROR_INVALID_TLV
;
1543 MALLOC(new_service
, struct necp_service_registration
*, sizeof(*new_service
), M_NECP
, M_WAITOK
);
1544 if (new_service
== NULL
) {
1545 NECPLOG0(LOG_ERR
, "Failed to allocate service registration");
1546 response_error
= NECP_ERROR_INTERNAL
;
1550 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1551 memset(new_service
, 0, sizeof(*new_service
));
1552 new_service
->service_id
= necp_create_uuid_service_id_mapping(service_uuid
);
1553 LIST_INSERT_HEAD(&session
->services
, new_service
, session_chain
);
1554 LIST_INSERT_HEAD(&necp_registered_service_list
, new_service
, kernel_chain
);
1555 lck_rw_done(&necp_kernel_policy_lock
);
1557 necp_send_success_response(session
, NECP_PACKET_TYPE_REGISTER_SERVICE
, message_id
);
1560 necp_send_error_response(session
, NECP_PACKET_TYPE_REGISTER_SERVICE
, message_id
, response_error
);
1564 necp_handle_unregister_service(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1567 struct necp_service_registration
*service
= NULL
;
1568 struct necp_service_registration
*temp_service
= NULL
;
1569 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
1570 struct necp_uuid_id_mapping
*mapping
= NULL
;
1571 uuid_t service_uuid
;
1572 uuid_clear(service_uuid
);
1574 if (session
== NULL
) {
1575 NECPLOG0(LOG_ERR
, "Failed to find session");
1576 response_error
= NECP_ERROR_INTERNAL
;
1580 // Read service uuid
1581 error
= necp_packet_get_tlv(packet
, offset
, NECP_TLV_SERVICE_UUID
, sizeof(uuid_t
), service_uuid
, NULL
);
1583 NECPLOG(LOG_ERR
, "Failed to get service UUID: %d", error
);
1584 response_error
= NECP_ERROR_INVALID_TLV
;
1588 // Mark remove all matching services for this session
1589 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1590 mapping
= necp_uuid_lookup_service_id_locked(service_uuid
);
1591 if (mapping
!= NULL
) {
1592 LIST_FOREACH_SAFE(service
, &session
->services
, session_chain
, temp_service
) {
1593 if (service
->service_id
== mapping
->id
) {
1594 LIST_REMOVE(service
, session_chain
);
1595 LIST_REMOVE(service
, kernel_chain
);
1596 FREE(service
, M_NECP
);
1599 necp_remove_uuid_service_id_mapping(service_uuid
);
1601 lck_rw_done(&necp_kernel_policy_lock
);
1603 necp_send_success_response(session
, NECP_PACKET_TYPE_UNREGISTER_SERVICE
, message_id
);
1606 necp_send_error_response(session
, NECP_PACKET_TYPE_UNREGISTER_SERVICE
, message_id
, response_error
);
1610 necp_handle_policy_add(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1612 bool has_default_condition
= FALSE
;
1613 bool has_non_default_condition
= FALSE
;
1614 bool has_application_condition
= FALSE
;
1615 bool requires_application_condition
= FALSE
;
1616 u_int8_t
*conditions_array
= NULL
;
1617 u_int32_t conditions_array_size
= 0;
1618 int conditions_array_cursor
;
1620 bool has_default_route_rule
= FALSE
;
1621 u_int8_t
*route_rules_array
= NULL
;
1622 u_int32_t route_rules_array_size
= 0;
1623 int route_rules_array_cursor
;
1627 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
1629 necp_policy_order order
= 0;
1630 struct necp_session_policy
*policy
= NULL
;
1631 u_int8_t
*policy_result
= NULL
;
1632 u_int32_t policy_result_size
= 0;
1634 // Read policy order
1635 error
= necp_packet_get_tlv(packet
, offset
, NECP_TLV_POLICY_ORDER
, sizeof(order
), &order
, NULL
);
1637 NECPLOG(LOG_ERR
, "Failed to get policy order: %d", error
);
1638 response_error
= NECP_ERROR_INVALID_TLV
;
1642 // Read policy result
1643 cursor
= necp_packet_find_tlv(packet
, offset
, NECP_TLV_POLICY_RESULT
, &error
, 0);
1644 error
= necp_packet_get_tlv_at_offset(packet
, cursor
, 0, NULL
, &policy_result_size
);
1645 if (error
|| policy_result_size
== 0) {
1646 NECPLOG(LOG_ERR
, "Failed to get policy result length: %d", error
);
1647 response_error
= NECP_ERROR_INVALID_TLV
;
1650 if (policy_result_size
> NECP_MAX_POLICY_RESULT_SIZE
) {
1651 NECPLOG(LOG_ERR
, "Policy result length too large: %u", policy_result_size
);
1652 response_error
= NECP_ERROR_INVALID_TLV
;
1655 MALLOC(policy_result
, u_int8_t
*, policy_result_size
, M_NECP
, M_WAITOK
);
1656 if (policy_result
== NULL
) {
1657 NECPLOG(LOG_ERR
, "Failed to allocate a policy result buffer (size %d)", policy_result_size
);
1658 response_error
= NECP_ERROR_INTERNAL
;
1661 error
= necp_packet_get_tlv_at_offset(packet
, cursor
, policy_result_size
, policy_result
, NULL
);
1663 NECPLOG(LOG_ERR
, "Failed to get policy result: %d", error
);
1664 response_error
= NECP_ERROR_POLICY_RESULT_INVALID
;
1667 if (!necp_policy_result_is_valid(policy_result
, policy_result_size
)) {
1668 NECPLOG0(LOG_ERR
, "Failed to validate policy result");
1669 response_error
= NECP_ERROR_POLICY_RESULT_INVALID
;
1673 if (necp_policy_result_requires_route_rules(policy_result
, policy_result_size
)) {
1674 // Read route rules conditions
1675 for (cursor
= necp_packet_find_tlv(packet
, offset
, NECP_TLV_ROUTE_RULE
, &error
, 0);
1677 cursor
= necp_packet_find_tlv(packet
, cursor
, NECP_TLV_ROUTE_RULE
, &error
, 1)) {
1678 u_int32_t route_rule_size
= 0;
1679 necp_packet_get_tlv_at_offset(packet
, cursor
, 0, NULL
, &route_rule_size
);
1680 if (route_rule_size
> 0) {
1681 route_rules_array_size
+= (sizeof(u_int8_t
) + sizeof(u_int32_t
) + route_rule_size
);
1685 if (route_rules_array_size
== 0) {
1686 NECPLOG0(LOG_ERR
, "Failed to get policy route rules");
1687 response_error
= NECP_ERROR_INVALID_TLV
;
1690 if (route_rules_array_size
> NECP_MAX_ROUTE_RULES_ARRAY_SIZE
) {
1691 NECPLOG(LOG_ERR
, "Route rules length too large: %u", route_rules_array_size
);
1692 response_error
= NECP_ERROR_INVALID_TLV
;
1695 MALLOC(route_rules_array
, u_int8_t
*, route_rules_array_size
, M_NECP
, M_WAITOK
);
1696 if (route_rules_array
== NULL
) {
1697 NECPLOG(LOG_ERR
, "Failed to allocate a policy route rules array (size %d)", route_rules_array_size
);
1698 response_error
= NECP_ERROR_INTERNAL
;
1702 route_rules_array_cursor
= 0;
1703 for (cursor
= necp_packet_find_tlv(packet
, offset
, NECP_TLV_ROUTE_RULE
, &error
, 0);
1705 cursor
= necp_packet_find_tlv(packet
, cursor
, NECP_TLV_ROUTE_RULE
, &error
, 1)) {
1706 u_int8_t route_rule_type
= NECP_TLV_ROUTE_RULE
;
1707 u_int32_t route_rule_size
= 0;
1708 necp_packet_get_tlv_at_offset(packet
, cursor
, 0, NULL
, &route_rule_size
);
1709 if (route_rule_size
> 0 && route_rule_size
<= (route_rules_array_size
- route_rules_array_cursor
)) {
1711 memcpy((route_rules_array
+ route_rules_array_cursor
), &route_rule_type
, sizeof(route_rule_type
));
1712 route_rules_array_cursor
+= sizeof(route_rule_type
);
1715 memcpy((route_rules_array
+ route_rules_array_cursor
), &route_rule_size
, sizeof(route_rule_size
));
1716 route_rules_array_cursor
+= sizeof(route_rule_size
);
1719 necp_packet_get_tlv_at_offset(packet
, cursor
, route_rule_size
, (route_rules_array
+ route_rules_array_cursor
), NULL
);
1721 if (!necp_policy_route_rule_is_valid((route_rules_array
+ route_rules_array_cursor
), route_rule_size
)) {
1722 NECPLOG0(LOG_ERR
, "Failed to validate policy route rule");
1723 response_error
= NECP_ERROR_ROUTE_RULES_INVALID
;
1727 if (necp_policy_route_rule_is_default((route_rules_array
+ route_rules_array_cursor
), route_rule_size
)) {
1728 if (has_default_route_rule
) {
1729 NECPLOG0(LOG_ERR
, "Failed to validate route rule; contained multiple default route rules");
1730 response_error
= NECP_ERROR_ROUTE_RULES_INVALID
;
1733 has_default_route_rule
= TRUE
;
1736 route_rules_array_cursor
+= route_rule_size
;
1741 // Read policy conditions
1742 for (cursor
= necp_packet_find_tlv(packet
, offset
, NECP_TLV_POLICY_CONDITION
, &error
, 0);
1744 cursor
= necp_packet_find_tlv(packet
, cursor
, NECP_TLV_POLICY_CONDITION
, &error
, 1)) {
1745 u_int32_t condition_size
= 0;
1746 necp_packet_get_tlv_at_offset(packet
, cursor
, 0, NULL
, &condition_size
);
1748 if (condition_size
> 0) {
1749 conditions_array_size
+= (sizeof(u_int8_t
) + sizeof(u_int32_t
) + condition_size
);
1753 if (conditions_array_size
== 0) {
1754 NECPLOG0(LOG_ERR
, "Failed to get policy conditions");
1755 response_error
= NECP_ERROR_INVALID_TLV
;
1758 if (conditions_array_size
> NECP_MAX_CONDITIONS_ARRAY_SIZE
) {
1759 NECPLOG(LOG_ERR
, "Conditions length too large: %u", conditions_array_size
);
1760 response_error
= NECP_ERROR_INVALID_TLV
;
1763 MALLOC(conditions_array
, u_int8_t
*, conditions_array_size
, M_NECP
, M_WAITOK
);
1764 if (conditions_array
== NULL
) {
1765 NECPLOG(LOG_ERR
, "Failed to allocate a policy conditions array (size %d)", conditions_array_size
);
1766 response_error
= NECP_ERROR_INTERNAL
;
1770 conditions_array_cursor
= 0;
1771 for (cursor
= necp_packet_find_tlv(packet
, offset
, NECP_TLV_POLICY_CONDITION
, &error
, 0);
1773 cursor
= necp_packet_find_tlv(packet
, cursor
, NECP_TLV_POLICY_CONDITION
, &error
, 1)) {
1774 u_int8_t condition_type
= NECP_TLV_POLICY_CONDITION
;
1775 u_int32_t condition_size
= 0;
1776 necp_packet_get_tlv_at_offset(packet
, cursor
, 0, NULL
, &condition_size
);
1777 if (condition_size
> 0 && condition_size
<= (conditions_array_size
- conditions_array_cursor
)) {
1779 memcpy((conditions_array
+ conditions_array_cursor
), &condition_type
, sizeof(condition_type
));
1780 conditions_array_cursor
+= sizeof(condition_type
);
1783 memcpy((conditions_array
+ conditions_array_cursor
), &condition_size
, sizeof(condition_size
));
1784 conditions_array_cursor
+= sizeof(condition_size
);
1787 necp_packet_get_tlv_at_offset(packet
, cursor
, condition_size
, (conditions_array
+ conditions_array_cursor
), NULL
);
1788 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
))) {
1789 NECPLOG0(LOG_ERR
, "Failed to validate policy condition");
1790 response_error
= NECP_ERROR_POLICY_CONDITIONS_INVALID
;
1794 if (necp_policy_condition_is_default((conditions_array
+ conditions_array_cursor
), condition_size
)) {
1795 has_default_condition
= TRUE
;
1797 has_non_default_condition
= TRUE
;
1799 if (has_default_condition
&& has_non_default_condition
) {
1800 NECPLOG0(LOG_ERR
, "Failed to validate conditions; contained default and non-default conditions");
1801 response_error
= NECP_ERROR_POLICY_CONDITIONS_INVALID
;
1805 if (necp_policy_condition_is_application((conditions_array
+ conditions_array_cursor
), condition_size
)) {
1806 has_application_condition
= TRUE
;
1809 if (necp_policy_condition_requires_application((conditions_array
+ conditions_array_cursor
), condition_size
)) {
1810 requires_application_condition
= TRUE
;
1813 conditions_array_cursor
+= condition_size
;
1817 if (requires_application_condition
&& !has_application_condition
) {
1818 NECPLOG0(LOG_ERR
, "Failed to validate conditions; did not contain application condition");
1819 response_error
= NECP_ERROR_POLICY_CONDITIONS_INVALID
;
1823 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
) {
1824 response_error
= NECP_ERROR_INTERNAL
;
1828 necp_send_policy_id_response(session
, NECP_PACKET_TYPE_POLICY_ADD
, message_id
, policy
->id
);
1832 if (policy_result
!= NULL
) {
1833 FREE(policy_result
, M_NECP
);
1835 if (conditions_array
!= NULL
) {
1836 FREE(conditions_array
, M_NECP
);
1838 if (route_rules_array
!= NULL
) {
1839 FREE(route_rules_array
, M_NECP
);
1842 necp_send_error_response(session
, NECP_PACKET_TYPE_POLICY_ADD
, message_id
, response_error
);
1846 necp_handle_policy_get(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1848 #pragma unused(offset)
1850 u_int8_t
*response
= NULL
;
1851 u_int8_t
*cursor
= NULL
;
1852 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
1853 necp_policy_id policy_id
= 0;
1854 u_int32_t order_tlv_size
= 0;
1855 u_int32_t result_tlv_size
= 0;
1856 u_int32_t response_size
= 0;
1858 struct necp_session_policy
*policy
= NULL
;
1861 error
= necp_packet_get_tlv(packet
, offset
, NECP_TLV_POLICY_ID
, sizeof(policy_id
), &policy_id
, NULL
);
1863 NECPLOG(LOG_ERR
, "Failed to get policy id: %d", error
);
1864 response_error
= NECP_ERROR_INVALID_TLV
;
1868 policy
= necp_policy_find(session
, policy_id
);
1869 if (policy
== NULL
|| policy
->pending_deletion
) {
1870 NECPLOG(LOG_ERR
, "Failed to find policy with id %d", policy_id
);
1871 response_error
= NECP_ERROR_POLICY_ID_NOT_FOUND
;
1875 order_tlv_size
= sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(necp_policy_order
);
1876 result_tlv_size
= (policy
->result_size
? (sizeof(u_int8_t
) + sizeof(u_int32_t
) + policy
->result_size
) : 0);
1877 response_size
= sizeof(struct necp_packet_header
) + order_tlv_size
+ result_tlv_size
+ policy
->conditions_size
;
1878 MALLOC(response
, u_int8_t
*, response_size
, M_NECP
, M_WAITOK
);
1879 if (response
== NULL
) {
1880 necp_send_error_response(session
, NECP_PACKET_TYPE_POLICY_LIST_ALL
, message_id
, NECP_ERROR_INTERNAL
);
1885 cursor
= necp_buffer_write_packet_header(cursor
, NECP_PACKET_TYPE_POLICY_GET
, NECP_PACKET_FLAGS_RESPONSE
, message_id
);
1886 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ORDER
, sizeof(necp_policy_order
), &policy
->order
);
1888 if (result_tlv_size
) {
1889 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_RESULT
, policy
->result_size
, &policy
->result
);
1891 if (policy
->conditions_size
) {
1892 memcpy(((u_int8_t
*)(void *)(cursor
)), policy
->conditions
, policy
->conditions_size
);
1895 if (!necp_send_ctl_data(session
, (u_int8_t
*)response
, response_size
)) {
1896 NECPLOG0(LOG_ERR
, "Failed to send response");
1899 FREE(response
, M_NECP
);
1903 necp_send_error_response(session
, NECP_PACKET_TYPE_POLICY_GET
, message_id
, response_error
);
1907 necp_handle_policy_delete(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1910 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
1911 necp_policy_id policy_id
= 0;
1913 struct necp_session_policy
*policy
= NULL
;
1916 error
= necp_packet_get_tlv(packet
, offset
, NECP_TLV_POLICY_ID
, sizeof(policy_id
), &policy_id
, NULL
);
1918 NECPLOG(LOG_ERR
, "Failed to get policy id: %d", error
);
1919 response_error
= NECP_ERROR_INVALID_TLV
;
1923 policy
= necp_policy_find(session
, policy_id
);
1924 if (policy
== NULL
|| policy
->pending_deletion
) {
1925 NECPLOG(LOG_ERR
, "Failed to find policy with id %d", policy_id
);
1926 response_error
= NECP_ERROR_POLICY_ID_NOT_FOUND
;
1930 necp_policy_mark_for_deletion(session
, policy
);
1932 necp_send_success_response(session
, NECP_PACKET_TYPE_POLICY_DELETE
, message_id
);
1936 necp_send_error_response(session
, NECP_PACKET_TYPE_POLICY_DELETE
, message_id
, response_error
);
1940 necp_handle_policy_apply_all(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1942 #pragma unused(packet, offset)
1943 necp_policy_apply_all(session
);
1944 necp_send_success_response(session
, NECP_PACKET_TYPE_POLICY_APPLY_ALL
, message_id
);
1948 necp_handle_policy_list_all(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1950 #pragma unused(packet, offset)
1951 u_int32_t tlv_size
= (sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(u_int32_t
));
1952 u_int32_t response_size
= 0;
1953 u_int8_t
*response
= NULL
;
1954 u_int8_t
*cursor
= NULL
;
1955 int num_policies
= 0;
1956 int cur_policy_index
= 0;
1957 struct necp_session_policy
*policy
;
1959 LIST_FOREACH(policy
, &session
->policies
, chain
) {
1960 if (!policy
->pending_deletion
) {
1965 // Create a response with one Policy ID TLV for each policy
1966 response_size
= sizeof(struct necp_packet_header
) + num_policies
* tlv_size
;
1967 MALLOC(response
, u_int8_t
*, response_size
, M_NECP
, M_WAITOK
);
1968 if (response
== NULL
) {
1969 necp_send_error_response(session
, NECP_PACKET_TYPE_POLICY_LIST_ALL
, message_id
, NECP_ERROR_INTERNAL
);
1974 cursor
= necp_buffer_write_packet_header(cursor
, NECP_PACKET_TYPE_POLICY_LIST_ALL
, NECP_PACKET_FLAGS_RESPONSE
, message_id
);
1976 LIST_FOREACH(policy
, &session
->policies
, chain
) {
1977 if (!policy
->pending_deletion
&& cur_policy_index
< num_policies
) {
1978 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ID
, sizeof(u_int32_t
), &policy
->id
);
1983 if (!necp_send_ctl_data(session
, (u_int8_t
*)response
, response_size
)) {
1984 NECPLOG0(LOG_ERR
, "Failed to send response");
1987 FREE(response
, M_NECP
);
1991 necp_handle_policy_delete_all(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1993 #pragma unused(packet, offset)
1994 necp_policy_mark_all_for_deletion(session
);
1995 necp_send_success_response(session
, NECP_PACKET_TYPE_POLICY_DELETE_ALL
, message_id
);
1998 static necp_policy_id
1999 necp_policy_get_new_id(void)
2001 necp_policy_id newid
= 0;
2003 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
2005 necp_last_policy_id
++;
2006 if (necp_last_policy_id
< 1) {
2007 necp_last_policy_id
= 1;
2010 newid
= necp_last_policy_id
;
2011 lck_rw_done(&necp_kernel_policy_lock
);
2014 NECPLOG0(LOG_DEBUG
, "Allocate policy id failed.\n");
2022 * For the policy dump response this is the structure:
2024 * <NECP_PACKET_HEADER>
2026 * type : NECP_TLV_POLICY_DUMP
2031 * type : NECP_TLV_POLICY_ID
2036 * type : NECP_TLV_POLICY_ORDER
2041 * type : NECP_TLV_POLICY_RESULT_STRING
2046 * type : NECP_TLV_POLICY_OWNER
2051 * type : NECP_TLV_POLICY_CONDITION
2056 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
2061 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
2071 * type : NECP_TLV_POLICY_DUMP
2076 * type : NECP_TLV_POLICY_ID
2081 * type : NECP_TLV_POLICY_ORDER
2086 * type : NECP_TLV_POLICY_RESULT_STRING
2091 * type : NECP_TLV_POLICY_OWNER
2096 * type : NECP_TLV_POLICY_CONDITION
2101 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
2106 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
2118 necp_handle_policy_dump_all(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
2120 #pragma unused(packet, offset)
2121 struct necp_kernel_socket_policy
*policy
= NULL
;
2123 int policy_count
= 0;
2124 u_int8_t
**tlv_buffer_pointers
= NULL
;
2125 u_int32_t
*tlv_buffer_lengths
= NULL
;
2126 int total_tlv_len
= 0;
2127 u_int8_t
*result_buf
= NULL
;
2128 u_int8_t
*result_buf_cursor
= result_buf
;
2129 char result_string
[MAX_RESULT_STRING_LEN
];
2130 char proc_name_string
[MAXCOMLEN
+ 1];
2132 bool error_occured
= false;
2133 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
2135 #define REPORT_ERROR(error) error_occured = true; \
2136 response_error = error; \
2139 #define UNLOCK_AND_REPORT_ERROR(lock, error) lck_rw_done(lock); \
2142 errno_t cred_result
= priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES
, 0);
2143 if (cred_result
!= 0) {
2144 NECPLOG0(LOG_ERR
, "Session does not hold the necessary entitlement to get Network Extension Policy information");
2145 REPORT_ERROR(NECP_ERROR_INTERNAL
);
2149 lck_rw_lock_shared(&necp_kernel_policy_lock
);
2151 NECPLOG0(LOG_DEBUG
, "Gathering policies");
2153 policy_count
= necp_kernel_application_policies_count
;
2155 MALLOC(tlv_buffer_pointers
, u_int8_t
**, sizeof(u_int8_t
*) * policy_count
, M_NECP
, M_NOWAIT
| M_ZERO
);
2156 if (tlv_buffer_pointers
== NULL
) {
2157 NECPLOG(LOG_DEBUG
, "Failed to allocate tlv_buffer_pointers (%u bytes)", sizeof(u_int8_t
*) * policy_count
);
2158 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock
, NECP_ERROR_INTERNAL
);
2161 MALLOC(tlv_buffer_lengths
, u_int32_t
*, sizeof(u_int32_t
) * policy_count
, M_NECP
, M_NOWAIT
| M_ZERO
);
2162 if (tlv_buffer_lengths
== NULL
) {
2163 NECPLOG(LOG_DEBUG
, "Failed to allocate tlv_buffer_lengths (%u bytes)", sizeof(u_int32_t
) * policy_count
);
2164 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock
, NECP_ERROR_INTERNAL
);
2167 for (policy_i
= 0; necp_kernel_socket_policies_app_layer_map
!= NULL
&& necp_kernel_socket_policies_app_layer_map
[policy_i
] != NULL
; policy_i
++) {
2168 policy
= necp_kernel_socket_policies_app_layer_map
[policy_i
];
2170 memset(result_string
, 0, MAX_RESULT_STRING_LEN
);
2171 memset(proc_name_string
, 0, MAXCOMLEN
+ 1);
2173 necp_get_result_description(result_string
, policy
->result
, policy
->result_parameter
);
2174 proc_name(policy
->session_pid
, proc_name_string
, MAXCOMLEN
);
2176 u_int16_t proc_name_len
= strlen(proc_name_string
) + 1;
2177 u_int16_t result_string_len
= strlen(result_string
) + 1;
2179 NECPLOG(LOG_DEBUG
, "Policy: process: %s, result: %s", proc_name_string
, result_string
);
2181 u_int32_t total_allocated_bytes
= sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(policy
->id
) + // NECP_TLV_POLICY_ID
2182 sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(policy
->order
) + // NECP_TLV_POLICY_ORDER
2183 sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(policy
->session_order
) + // NECP_TLV_POLICY_SESSION_ORDER
2184 sizeof(u_int8_t
) + sizeof(u_int32_t
) + result_string_len
+ // NECP_TLV_POLICY_RESULT_STRING
2185 sizeof(u_int8_t
) + sizeof(u_int32_t
) + proc_name_len
+ // NECP_TLV_POLICY_OWNER
2186 sizeof(u_int8_t
) + sizeof(u_int32_t
); // NECP_TLV_POLICY_CONDITION
2188 // We now traverse the condition_mask to see how much space we need to allocate
2189 u_int32_t condition_mask
= policy
->condition_mask
;
2190 u_int8_t num_conditions
= 0;
2191 struct necp_string_id_mapping
*account_id_entry
= NULL
;
2192 char if_name
[IFXNAMSIZ
];
2193 u_int32_t condition_tlv_length
= 0;
2194 memset(if_name
, 0, sizeof(if_name
));
2196 if (condition_mask
== NECP_POLICY_CONDITION_DEFAULT
) {
2199 if (condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) {
2202 if (condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
2203 snprintf(if_name
, IFXNAMSIZ
, "%s%d", ifnet_name(policy
->cond_bound_interface
), ifnet_unit(policy
->cond_bound_interface
));
2204 condition_tlv_length
+= strlen(if_name
) + 1;
2207 if (condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
2208 condition_tlv_length
+= sizeof(policy
->cond_protocol
);
2211 if (condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
2212 condition_tlv_length
+= sizeof(uuid_t
);
2215 if (condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
2216 condition_tlv_length
+= sizeof(uuid_t
);
2219 if (condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
2220 u_int32_t domain_len
= strlen(policy
->cond_domain
) + 1;
2221 condition_tlv_length
+= domain_len
;
2224 if (condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
2225 account_id_entry
= necp_lookup_string_with_id_locked(&necp_account_id_list
, policy
->cond_account_id
);
2226 u_int32_t account_id_len
= 0;
2227 if (account_id_entry
) {
2228 account_id_len
= account_id_entry
->string
? strlen(account_id_entry
->string
) + 1 : 0;
2230 condition_tlv_length
+= account_id_len
;
2233 if (condition_mask
& NECP_KERNEL_CONDITION_PID
) {
2234 condition_tlv_length
+= sizeof(pid_t
);
2237 if (condition_mask
& NECP_KERNEL_CONDITION_UID
) {
2238 condition_tlv_length
+= sizeof(uid_t
);
2241 if (condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
2242 condition_tlv_length
+= sizeof(struct necp_policy_condition_tc_range
);
2245 if (condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
) {
2248 if (condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) {
2249 u_int32_t entitlement_len
= strlen(policy
->cond_custom_entitlement
) + 1;
2250 condition_tlv_length
+= entitlement_len
;
2253 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
2254 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
2255 condition_tlv_length
+= sizeof(struct necp_policy_condition_addr_range
);
2257 condition_tlv_length
+= sizeof(struct necp_policy_condition_addr
);
2261 if (condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
2262 if (condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
2263 condition_tlv_length
+= sizeof(struct necp_policy_condition_addr_range
);
2265 condition_tlv_length
+= sizeof(struct necp_policy_condition_addr
);
2271 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.
2272 total_allocated_bytes
+= condition_tlv_length
;
2274 u_int8_t
*tlv_buffer
;
2275 MALLOC(tlv_buffer
, u_int8_t
*, total_allocated_bytes
, M_NECP
, M_NOWAIT
| M_ZERO
);
2276 if (tlv_buffer
== NULL
) {
2277 NECPLOG(LOG_DEBUG
, "Failed to allocate tlv_buffer (%u bytes)", total_allocated_bytes
);
2281 u_int8_t
*cursor
= tlv_buffer
;
2282 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ID
, sizeof(policy
->id
), &policy
->id
);
2283 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ORDER
, sizeof(necp_policy_order
), &policy
->order
);
2284 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_SESSION_ORDER
, sizeof(policy
->session_order
), &policy
->session_order
);
2285 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_RESULT_STRING
, result_string_len
, result_string
);
2286 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_OWNER
, proc_name_len
, proc_name_string
);
2289 u_int8_t q_cond_buf
[N_QUICK
]; // Minor optimization
2291 u_int8_t
*cond_buf
; // To be used for condition TLVs
2292 if (condition_tlv_length
<= N_QUICK
) {
2293 cond_buf
= q_cond_buf
;
2295 MALLOC(cond_buf
, u_int8_t
*, condition_tlv_length
, M_NECP
, M_NOWAIT
);
2296 if (cond_buf
== NULL
) {
2297 NECPLOG(LOG_DEBUG
, "Failed to allocate cond_buffer (%u bytes)", condition_tlv_length
);
2298 FREE(tlv_buffer
, M_NECP
);
2303 memset(cond_buf
, 0, condition_tlv_length
);
2304 u_int8_t
*cond_buf_cursor
= cond_buf
;
2305 if (condition_mask
== NECP_POLICY_CONDITION_DEFAULT
) {
2306 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_DEFAULT
, 0, "");
2308 if (condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) {
2309 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_ALL_INTERFACES
, 0, "");
2311 if (condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
2312 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_BOUND_INTERFACE
, strlen(if_name
) + 1, if_name
);
2314 if (condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
2315 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_IP_PROTOCOL
, sizeof(policy
->cond_protocol
), &policy
->cond_protocol
);
2317 if (condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
2318 struct necp_uuid_id_mapping
*entry
= necp_uuid_lookup_uuid_with_app_id_locked(policy
->cond_app_id
);
2319 if (entry
!= NULL
) {
2320 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_APPLICATION
, sizeof(entry
->uuid
), entry
->uuid
);
2323 if (condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
2324 struct necp_uuid_id_mapping
*entry
= necp_uuid_lookup_uuid_with_app_id_locked(policy
->cond_real_app_id
);
2325 if (entry
!= NULL
) {
2326 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_REAL_APPLICATION
, sizeof(entry
->uuid
), entry
->uuid
);
2329 if (condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
2330 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_DOMAIN
, strlen(policy
->cond_domain
) + 1, policy
->cond_domain
);
2332 if (condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
2333 if (account_id_entry
!= NULL
) {
2334 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_ACCOUNT
, strlen(account_id_entry
->string
) + 1, account_id_entry
->string
);
2337 if (condition_mask
& NECP_KERNEL_CONDITION_PID
) {
2338 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_PID
, sizeof(policy
->cond_pid
), &policy
->cond_pid
);
2340 if (condition_mask
& NECP_KERNEL_CONDITION_UID
) {
2341 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_UID
, sizeof(policy
->cond_uid
), &policy
->cond_uid
);
2343 if (condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
2344 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_TRAFFIC_CLASS
, sizeof(policy
->cond_traffic_class
), &policy
->cond_traffic_class
);
2346 if (condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
) {
2347 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_ENTITLEMENT
, 0, "");
2349 if (condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) {
2350 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_ENTITLEMENT
, strlen(policy
->cond_custom_entitlement
) + 1, policy
->cond_custom_entitlement
);
2352 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
2353 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
2354 struct necp_policy_condition_addr_range range
;
2355 memcpy(&range
.start_address
, &policy
->cond_local_start
, sizeof(policy
->cond_local_start
));
2356 memcpy(&range
.end_address
, &policy
->cond_local_end
, sizeof(policy
->cond_local_end
));
2357 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE
, sizeof(range
), &range
);
2359 struct necp_policy_condition_addr addr
;
2360 addr
.prefix
= policy
->cond_local_prefix
;
2361 memcpy(&addr
.address
, &policy
->cond_local_start
, sizeof(policy
->cond_local_start
));
2362 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_LOCAL_ADDR
, sizeof(addr
), &addr
);
2365 if (condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
2366 if (condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
2367 struct necp_policy_condition_addr_range range
;
2368 memcpy(&range
.start_address
, &policy
->cond_remote_start
, sizeof(policy
->cond_remote_start
));
2369 memcpy(&range
.end_address
, &policy
->cond_remote_end
, sizeof(policy
->cond_remote_end
));
2370 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE
, sizeof(range
), &range
);
2372 struct necp_policy_condition_addr addr
;
2373 addr
.prefix
= policy
->cond_remote_prefix
;
2374 memcpy(&addr
.address
, &policy
->cond_remote_start
, sizeof(policy
->cond_remote_start
));
2375 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_REMOTE_ADDR
, sizeof(addr
), &addr
);
2380 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_CONDITION
, cond_buf_cursor
- cond_buf
, cond_buf
);
2381 if (cond_buf
!= q_cond_buf
) {
2382 FREE(cond_buf
, M_NECP
);
2385 tlv_buffer_pointers
[policy_i
] = tlv_buffer
;
2386 tlv_buffer_lengths
[policy_i
] = (cursor
- tlv_buffer
);
2388 // This is the length of the TLV for NECP_TLV_POLICY_DUMP
2389 total_tlv_len
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + (cursor
- tlv_buffer
);
2393 lck_rw_done(&necp_kernel_policy_lock
);
2395 u_int32_t total_result_length
= sizeof(struct necp_packet_header
) + total_tlv_len
;
2396 MALLOC(result_buf
, u_int8_t
*, total_result_length
, M_NECP
, M_NOWAIT
| M_ZERO
);
2397 if (result_buf
== NULL
) {
2398 NECPLOG(LOG_DEBUG
, "Failed to allocate result_buffer (%u bytes)", total_result_length
);
2399 REPORT_ERROR(NECP_ERROR_INTERNAL
);
2402 result_buf_cursor
= result_buf
;
2403 result_buf_cursor
= necp_buffer_write_packet_header(result_buf_cursor
, NECP_PACKET_TYPE_POLICY_DUMP_ALL
, NECP_PACKET_FLAGS_RESPONSE
, message_id
);
2405 for (int i
= 0; i
< policy_count
; i
++) {
2406 if (tlv_buffer_pointers
[i
] != NULL
) {
2407 result_buf_cursor
= necp_buffer_write_tlv(result_buf_cursor
, NECP_TLV_POLICY_DUMP
, tlv_buffer_lengths
[i
], tlv_buffer_pointers
[i
]);
2411 if (!necp_send_ctl_data(session
, result_buf
, result_buf_cursor
- result_buf
)) {
2412 NECPLOG(LOG_ERR
, "Failed to send response (%u bytes)", result_buf_cursor
- result_buf
);
2414 NECPLOG(LOG_ERR
, "Sent data worth %u bytes. Total result buffer length was %u bytes", result_buf_cursor
- result_buf
, total_result_length
);
2419 if (error_occured
) {
2420 if(!necp_send_error_response(session
, NECP_PACKET_TYPE_POLICY_DUMP_ALL
, message_id
, response_error
)) {
2421 NECPLOG0(LOG_ERR
, "Failed to send error response");
2423 NECPLOG0(LOG_ERR
, "Sent error response");
2427 if (result_buf
!= NULL
) {
2428 FREE(result_buf
, M_NECP
);
2431 if (tlv_buffer_pointers
!= NULL
) {
2432 for (int i
= 0; i
< policy_count
; i
++) {
2433 if (tlv_buffer_pointers
[i
] != NULL
) {
2434 FREE(tlv_buffer_pointers
[i
], M_NECP
);
2435 tlv_buffer_pointers
[i
] = NULL
;
2438 FREE(tlv_buffer_pointers
, M_NECP
);
2441 if (tlv_buffer_lengths
!= NULL
) {
2442 FREE(tlv_buffer_lengths
, M_NECP
);
2445 #undef RESET_COND_BUF
2447 #undef UNLOCK_AND_REPORT_ERROR
2450 static struct necp_session_policy
*
2451 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
)
2453 struct necp_session_policy
*new_policy
= NULL
;
2454 struct necp_session_policy
*tmp_policy
= NULL
;
2456 if (session
== NULL
|| conditions_array
== NULL
|| result
== NULL
|| result_size
== 0) {
2460 MALLOC_ZONE(new_policy
, struct necp_session_policy
*, sizeof(*new_policy
), M_NECP_SESSION_POLICY
, M_WAITOK
);
2461 if (new_policy
== NULL
) {
2465 memset(new_policy
, 0, sizeof(*new_policy
));
2466 new_policy
->applied
= FALSE
;
2467 new_policy
->pending_deletion
= FALSE
;
2468 new_policy
->pending_update
= FALSE
;
2469 new_policy
->order
= order
;
2470 new_policy
->conditions
= conditions_array
;
2471 new_policy
->conditions_size
= conditions_array_size
;
2472 new_policy
->route_rules
= route_rules_array
;
2473 new_policy
->route_rules_size
= route_rules_array_size
;
2474 new_policy
->result
= result
;
2475 new_policy
->result_size
= result_size
;
2476 new_policy
->id
= necp_policy_get_new_id();
2478 LIST_INSERT_SORTED_ASCENDING(&session
->policies
, new_policy
, chain
, order
, tmp_policy
);
2480 session
->dirty
= TRUE
;
2483 NECPLOG(LOG_DEBUG
, "Created NECP policy, order %d", order
);
2486 return (new_policy
);
2489 static struct necp_session_policy
*
2490 necp_policy_find(struct necp_session
*session
, necp_policy_id policy_id
)
2492 struct necp_session_policy
*policy
= NULL
;
2493 if (policy_id
== 0) {
2497 LIST_FOREACH(policy
, &session
->policies
, chain
) {
2498 if (policy
->id
== policy_id
) {
2506 static inline u_int8_t
2507 necp_policy_get_result_type(struct necp_session_policy
*policy
)
2509 return (policy
? necp_policy_result_get_type_from_buffer(policy
->result
, policy
->result_size
) : 0);
2512 static inline u_int32_t
2513 necp_policy_get_result_parameter_length(struct necp_session_policy
*policy
)
2515 return (policy
? necp_policy_result_get_parameter_length_from_buffer(policy
->result
, policy
->result_size
) : 0);
2519 necp_policy_get_result_parameter(struct necp_session_policy
*policy
, u_int8_t
*parameter_buffer
, u_int32_t parameter_buffer_length
)
2522 u_int32_t parameter_length
= necp_policy_result_get_parameter_length_from_buffer(policy
->result
, policy
->result_size
);
2523 if (parameter_buffer_length
>= parameter_length
) {
2524 u_int8_t
*parameter
= necp_policy_result_get_parameter_pointer_from_buffer(policy
->result
, policy
->result_size
);
2525 if (parameter
&& parameter_buffer
) {
2526 memcpy(parameter_buffer
, parameter
, parameter_length
);
2536 necp_policy_mark_for_deletion(struct necp_session
*session
, struct necp_session_policy
*policy
)
2538 if (session
== NULL
|| policy
== NULL
) {
2542 policy
->pending_deletion
= TRUE
;
2543 session
->dirty
= TRUE
;
2546 NECPLOG0(LOG_DEBUG
, "Marked NECP policy for removal");
2552 necp_policy_mark_all_for_deletion(struct necp_session
*session
)
2554 struct necp_session_policy
*policy
= NULL
;
2555 struct necp_session_policy
*temp_policy
= NULL
;
2557 LIST_FOREACH_SAFE(policy
, &session
->policies
, chain
, temp_policy
) {
2558 necp_policy_mark_for_deletion(session
, policy
);
2565 necp_policy_delete(struct necp_session
*session
, struct necp_session_policy
*policy
)
2567 if (session
== NULL
|| policy
== NULL
) {
2571 LIST_REMOVE(policy
, chain
);
2573 if (policy
->result
) {
2574 FREE(policy
->result
, M_NECP
);
2575 policy
->result
= NULL
;
2578 if (policy
->conditions
) {
2579 FREE(policy
->conditions
, M_NECP
);
2580 policy
->conditions
= NULL
;
2583 if (policy
->route_rules
) {
2584 FREE(policy
->route_rules
, M_NECP
);
2585 policy
->route_rules
= NULL
;
2588 FREE_ZONE(policy
, sizeof(*policy
), M_NECP_SESSION_POLICY
);
2591 NECPLOG0(LOG_DEBUG
, "Removed NECP policy");
2597 necp_policy_unapply(struct necp_session_policy
*policy
)
2600 if (policy
== NULL
) {
2604 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
2606 // Release local uuid mappings
2607 if (!uuid_is_null(policy
->applied_app_uuid
)) {
2608 bool removed_mapping
= FALSE
;
2609 if (necp_remove_uuid_app_id_mapping(policy
->applied_app_uuid
, &removed_mapping
, TRUE
) && removed_mapping
) {
2610 necp_uuid_app_id_mappings_dirty
= TRUE
;
2611 necp_num_uuid_app_id_mappings
--;
2613 uuid_clear(policy
->applied_app_uuid
);
2615 if (!uuid_is_null(policy
->applied_real_app_uuid
)) {
2616 necp_remove_uuid_app_id_mapping(policy
->applied_real_app_uuid
, NULL
, FALSE
);
2617 uuid_clear(policy
->applied_real_app_uuid
);
2619 if (!uuid_is_null(policy
->applied_result_uuid
)) {
2620 necp_remove_uuid_service_id_mapping(policy
->applied_result_uuid
);
2621 uuid_clear(policy
->applied_result_uuid
);
2624 // Release string mappings
2625 if (policy
->applied_account
!= NULL
) {
2626 necp_remove_string_to_id_mapping(&necp_account_id_list
, policy
->applied_account
);
2627 FREE(policy
->applied_account
, M_NECP
);
2628 policy
->applied_account
= NULL
;
2631 // Release route rule
2632 if (policy
->applied_route_rules_id
!= 0) {
2633 necp_remove_route_rule(&necp_route_rules
, policy
->applied_route_rules_id
);
2634 policy
->applied_route_rules_id
= 0;
2637 // Remove socket policies
2638 for (i
= 0; i
< MAX_KERNEL_SOCKET_POLICIES
; i
++) {
2639 if (policy
->kernel_socket_policies
[i
] != 0) {
2640 necp_kernel_socket_policy_delete(policy
->kernel_socket_policies
[i
]);
2641 policy
->kernel_socket_policies
[i
] = 0;
2645 // Remove IP output policies
2646 for (i
= 0; i
< MAX_KERNEL_IP_OUTPUT_POLICIES
; i
++) {
2647 if (policy
->kernel_ip_output_policies
[i
] != 0) {
2648 necp_kernel_ip_output_policy_delete(policy
->kernel_ip_output_policies
[i
]);
2649 policy
->kernel_ip_output_policies
[i
] = 0;
2653 policy
->applied
= FALSE
;
2658 #define NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION 0
2659 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION 1
2660 #define NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION 2
2661 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS 3
2662 struct necp_policy_result_ip_tunnel
{
2663 u_int32_t secondary_result
;
2664 char interface_name
[IFXNAMSIZ
];
2665 } __attribute__((__packed__
));
2667 struct necp_policy_result_service
{
2670 } __attribute__((__packed__
));
2673 necp_policy_apply(struct necp_session
*session
, struct necp_session_policy
*policy
)
2675 bool socket_only_conditions
= FALSE
;
2676 bool socket_ip_conditions
= FALSE
;
2678 bool socket_layer_non_id_conditions
= FALSE
;
2679 bool ip_output_layer_non_id_conditions
= FALSE
;
2680 bool ip_output_layer_non_id_only
= FALSE
;
2681 bool ip_output_layer_id_condition
= FALSE
;
2682 bool ip_output_layer_tunnel_condition_from_id
= FALSE
;
2683 bool ip_output_layer_tunnel_condition_from_non_id
= FALSE
;
2684 necp_kernel_policy_id cond_ip_output_layer_id
= NECP_KERNEL_POLICY_ID_NONE
;
2686 u_int32_t master_condition_mask
= 0;
2687 u_int32_t master_condition_negated_mask
= 0;
2688 ifnet_t cond_bound_interface
= NULL
;
2689 u_int32_t cond_account_id
= 0;
2690 char *cond_domain
= NULL
;
2691 char *cond_custom_entitlement
= NULL
;
2694 necp_app_id cond_app_id
= 0;
2695 necp_app_id cond_real_app_id
= 0;
2696 struct necp_policy_condition_tc_range cond_traffic_class
;
2697 cond_traffic_class
.start_tc
= 0;
2698 cond_traffic_class
.end_tc
= 0;
2699 u_int16_t cond_protocol
= 0;
2700 union necp_sockaddr_union cond_local_start
;
2701 union necp_sockaddr_union cond_local_end
;
2702 u_int8_t cond_local_prefix
= 0;
2703 union necp_sockaddr_union cond_remote_start
;
2704 union necp_sockaddr_union cond_remote_end
;
2705 u_int8_t cond_remote_prefix
= 0;
2706 u_int32_t offset
= 0;
2707 u_int8_t ultimate_result
= 0;
2708 u_int32_t secondary_result
= 0;
2709 necp_kernel_policy_result_parameter secondary_result_parameter
;
2710 memset(&secondary_result_parameter
, 0, sizeof(secondary_result_parameter
));
2711 u_int32_t cond_last_interface_index
= 0;
2712 necp_kernel_policy_result_parameter ultimate_result_parameter
;
2713 memset(&ultimate_result_parameter
, 0, sizeof(ultimate_result_parameter
));
2715 if (policy
== NULL
) {
2719 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
2721 // Process conditions
2722 while (offset
< policy
->conditions_size
) {
2723 u_int32_t length
= 0;
2724 u_int8_t
*value
= necp_buffer_get_tlv_value(policy
->conditions
, offset
, &length
);
2726 u_int8_t condition_type
= necp_policy_condition_get_type_from_buffer(value
, length
);
2727 u_int8_t condition_flags
= necp_policy_condition_get_flags_from_buffer(value
, length
);
2728 bool condition_is_negative
= condition_flags
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
;
2729 u_int32_t condition_length
= necp_policy_condition_get_value_length_from_buffer(value
, length
);
2730 u_int8_t
*condition_value
= necp_policy_condition_get_value_pointer_from_buffer(value
, length
);
2731 switch (condition_type
) {
2732 case NECP_POLICY_CONDITION_DEFAULT
: {
2733 socket_ip_conditions
= TRUE
;
2736 case NECP_POLICY_CONDITION_ALL_INTERFACES
: {
2737 master_condition_mask
|= NECP_KERNEL_CONDITION_ALL_INTERFACES
;
2738 socket_ip_conditions
= TRUE
;
2741 case NECP_POLICY_CONDITION_ENTITLEMENT
: {
2742 if (condition_length
> 0) {
2743 if (cond_custom_entitlement
== NULL
) {
2744 cond_custom_entitlement
= necp_copy_string((char *)condition_value
, condition_length
);
2745 if (cond_custom_entitlement
!= NULL
) {
2746 master_condition_mask
|= NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
;
2747 socket_only_conditions
= TRUE
;
2751 master_condition_mask
|= NECP_KERNEL_CONDITION_ENTITLEMENT
;
2752 socket_only_conditions
= TRUE
;
2756 case NECP_POLICY_CONDITION_DOMAIN
: {
2757 // Make sure there is only one such rule
2758 if (condition_length
> 0 && cond_domain
== NULL
) {
2759 cond_domain
= necp_create_trimmed_domain((char *)condition_value
, condition_length
);
2760 if (cond_domain
!= NULL
) {
2761 master_condition_mask
|= NECP_KERNEL_CONDITION_DOMAIN
;
2762 if (condition_is_negative
) {
2763 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_DOMAIN
;
2765 socket_only_conditions
= TRUE
;
2770 case NECP_POLICY_CONDITION_ACCOUNT
: {
2771 // Make sure there is only one such rule
2772 if (condition_length
> 0 && cond_account_id
== 0 && policy
->applied_account
== NULL
) {
2773 char *string
= NULL
;
2774 MALLOC(string
, char *, condition_length
+ 1, M_NECP
, M_WAITOK
);
2775 if (string
!= NULL
) {
2776 memcpy(string
, condition_value
, condition_length
);
2777 string
[condition_length
] = 0;
2778 cond_account_id
= necp_create_string_to_id_mapping(&necp_account_id_list
, string
);
2779 if (cond_account_id
!= 0) {
2780 policy
->applied_account
= string
; // Save the string in parent policy
2781 master_condition_mask
|= NECP_KERNEL_CONDITION_ACCOUNT_ID
;
2782 if (condition_is_negative
) {
2783 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_ACCOUNT_ID
;
2785 socket_only_conditions
= TRUE
;
2787 FREE(string
, M_NECP
);
2793 case NECP_POLICY_CONDITION_APPLICATION
: {
2794 // Make sure there is only one such rule, because we save the uuid in the policy
2795 if (condition_length
>= sizeof(uuid_t
) && cond_app_id
== 0) {
2796 bool allocated_mapping
= FALSE
;
2797 uuid_t application_uuid
;
2798 memcpy(application_uuid
, condition_value
, sizeof(uuid_t
));
2799 cond_app_id
= necp_create_uuid_app_id_mapping(application_uuid
, &allocated_mapping
, TRUE
);
2800 if (cond_app_id
!= 0) {
2801 if (allocated_mapping
) {
2802 necp_uuid_app_id_mappings_dirty
= TRUE
;
2803 necp_num_uuid_app_id_mappings
++;
2805 uuid_copy(policy
->applied_app_uuid
, application_uuid
);
2806 master_condition_mask
|= NECP_KERNEL_CONDITION_APP_ID
;
2807 if (condition_is_negative
) {
2808 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_APP_ID
;
2810 socket_only_conditions
= TRUE
;
2815 case NECP_POLICY_CONDITION_REAL_APPLICATION
: {
2816 // Make sure there is only one such rule, because we save the uuid in the policy
2817 if (condition_length
>= sizeof(uuid_t
) && cond_real_app_id
== 0) {
2818 uuid_t real_application_uuid
;
2819 memcpy(real_application_uuid
, condition_value
, sizeof(uuid_t
));
2820 cond_real_app_id
= necp_create_uuid_app_id_mapping(real_application_uuid
, NULL
, FALSE
);
2821 if (cond_real_app_id
!= 0) {
2822 uuid_copy(policy
->applied_real_app_uuid
, real_application_uuid
);
2823 master_condition_mask
|= NECP_KERNEL_CONDITION_REAL_APP_ID
;
2824 if (condition_is_negative
) {
2825 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REAL_APP_ID
;
2827 socket_only_conditions
= TRUE
;
2832 case NECP_POLICY_CONDITION_PID
: {
2833 if (condition_length
>= sizeof(pid_t
)) {
2834 master_condition_mask
|= NECP_KERNEL_CONDITION_PID
;
2835 if (condition_is_negative
) {
2836 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_PID
;
2838 memcpy(&cond_pid
, condition_value
, sizeof(cond_pid
));
2839 socket_only_conditions
= TRUE
;
2843 case NECP_POLICY_CONDITION_UID
: {
2844 if (condition_length
>= sizeof(uid_t
)) {
2845 master_condition_mask
|= NECP_KERNEL_CONDITION_UID
;
2846 if (condition_is_negative
) {
2847 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_UID
;
2849 memcpy(&cond_uid
, condition_value
, sizeof(cond_uid
));
2850 socket_only_conditions
= TRUE
;
2854 case NECP_POLICY_CONDITION_TRAFFIC_CLASS
: {
2855 if (condition_length
>= sizeof(struct necp_policy_condition_tc_range
)) {
2856 master_condition_mask
|= NECP_KERNEL_CONDITION_TRAFFIC_CLASS
;
2857 if (condition_is_negative
) {
2858 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_TRAFFIC_CLASS
;
2860 memcpy(&cond_traffic_class
, condition_value
, sizeof(cond_traffic_class
));
2861 socket_only_conditions
= TRUE
;
2865 case NECP_POLICY_CONDITION_BOUND_INTERFACE
: {
2866 if (condition_length
<= IFXNAMSIZ
&& condition_length
> 0) {
2867 char interface_name
[IFXNAMSIZ
];
2868 memcpy(interface_name
, condition_value
, condition_length
);
2869 interface_name
[condition_length
- 1] = 0; // Make sure the string is NULL terminated
2870 if (ifnet_find_by_name(interface_name
, &cond_bound_interface
) == 0) {
2871 master_condition_mask
|= NECP_KERNEL_CONDITION_BOUND_INTERFACE
;
2872 if (condition_is_negative
) {
2873 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_BOUND_INTERFACE
;
2876 socket_ip_conditions
= TRUE
;
2880 case NECP_POLICY_CONDITION_IP_PROTOCOL
: {
2881 if (condition_length
>= sizeof(u_int16_t
)) {
2882 master_condition_mask
|= NECP_KERNEL_CONDITION_PROTOCOL
;
2883 if (condition_is_negative
) {
2884 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_PROTOCOL
;
2886 memcpy(&cond_protocol
, condition_value
, sizeof(cond_protocol
));
2887 socket_ip_conditions
= TRUE
;
2891 case NECP_POLICY_CONDITION_LOCAL_ADDR
: {
2892 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)condition_value
;
2893 if (!necp_address_is_valid(&address_struct
->address
.sa
)) {
2897 cond_local_prefix
= address_struct
->prefix
;
2898 memcpy(&cond_local_start
, &address_struct
->address
, sizeof(address_struct
->address
));
2899 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_START
;
2900 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_PREFIX
;
2901 if (condition_is_negative
) {
2902 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_START
;
2903 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_PREFIX
;
2905 socket_ip_conditions
= TRUE
;
2908 case NECP_POLICY_CONDITION_REMOTE_ADDR
: {
2909 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)condition_value
;
2910 if (!necp_address_is_valid(&address_struct
->address
.sa
)) {
2914 cond_remote_prefix
= address_struct
->prefix
;
2915 memcpy(&cond_remote_start
, &address_struct
->address
, sizeof(address_struct
->address
));
2916 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_START
;
2917 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_PREFIX
;
2918 if (condition_is_negative
) {
2919 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_START
;
2920 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_PREFIX
;
2922 socket_ip_conditions
= TRUE
;
2925 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE
: {
2926 struct necp_policy_condition_addr_range
*address_struct
= (struct necp_policy_condition_addr_range
*)(void *)condition_value
;
2927 if (!necp_address_is_valid(&address_struct
->start_address
.sa
) ||
2928 !necp_address_is_valid(&address_struct
->end_address
.sa
)) {
2932 memcpy(&cond_local_start
, &address_struct
->start_address
, sizeof(address_struct
->start_address
));
2933 memcpy(&cond_local_end
, &address_struct
->end_address
, sizeof(address_struct
->end_address
));
2934 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_START
;
2935 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_END
;
2936 if (condition_is_negative
) {
2937 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_START
;
2938 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_END
;
2940 socket_ip_conditions
= TRUE
;
2943 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE
: {
2944 struct necp_policy_condition_addr_range
*address_struct
= (struct necp_policy_condition_addr_range
*)(void *)condition_value
;
2945 if (!necp_address_is_valid(&address_struct
->start_address
.sa
) ||
2946 !necp_address_is_valid(&address_struct
->end_address
.sa
)) {
2950 memcpy(&cond_remote_start
, &address_struct
->start_address
, sizeof(address_struct
->start_address
));
2951 memcpy(&cond_remote_end
, &address_struct
->end_address
, sizeof(address_struct
->end_address
));
2952 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_START
;
2953 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_END
;
2954 if (condition_is_negative
) {
2955 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_START
;
2956 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_END
;
2958 socket_ip_conditions
= TRUE
;
2966 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
2970 ultimate_result
= necp_policy_get_result_type(policy
);
2971 switch (ultimate_result
) {
2972 case NECP_POLICY_RESULT_PASS
: {
2973 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
2974 socket_layer_non_id_conditions
= TRUE
;
2975 ip_output_layer_id_condition
= TRUE
;
2976 } else if (socket_ip_conditions
) {
2977 socket_layer_non_id_conditions
= TRUE
;
2978 ip_output_layer_id_condition
= TRUE
;
2979 ip_output_layer_non_id_conditions
= TRUE
;
2983 case NECP_POLICY_RESULT_DROP
: {
2984 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
2985 socket_layer_non_id_conditions
= TRUE
;
2986 } else if (socket_ip_conditions
) {
2987 socket_layer_non_id_conditions
= TRUE
;
2988 ip_output_layer_non_id_conditions
= TRUE
;
2989 ip_output_layer_non_id_only
= TRUE
; // Only apply drop to packets that didn't go through socket layer
2993 case NECP_POLICY_RESULT_SKIP
: {
2994 u_int32_t skip_policy_order
= 0;
2995 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&skip_policy_order
, sizeof(skip_policy_order
))) {
2996 ultimate_result_parameter
.skip_policy_order
= skip_policy_order
;
2999 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
3000 socket_layer_non_id_conditions
= TRUE
;
3001 ip_output_layer_id_condition
= TRUE
;
3002 } else if (socket_ip_conditions
) {
3003 socket_layer_non_id_conditions
= TRUE
;
3004 ip_output_layer_non_id_conditions
= TRUE
;
3008 case NECP_POLICY_RESULT_SOCKET_DIVERT
:
3009 case NECP_POLICY_RESULT_SOCKET_FILTER
: {
3010 u_int32_t control_unit
= 0;
3011 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&control_unit
, sizeof(control_unit
))) {
3012 ultimate_result_parameter
.flow_divert_control_unit
= control_unit
;
3014 socket_layer_non_id_conditions
= TRUE
;
3017 case NECP_POLICY_RESULT_IP_TUNNEL
: {
3018 struct necp_policy_result_ip_tunnel tunnel_parameters
;
3019 u_int32_t tunnel_parameters_length
= necp_policy_get_result_parameter_length(policy
);
3020 if (tunnel_parameters_length
> sizeof(u_int32_t
) &&
3021 tunnel_parameters_length
<= sizeof(struct necp_policy_result_ip_tunnel
) &&
3022 necp_policy_get_result_parameter(policy
, (u_int8_t
*)&tunnel_parameters
, sizeof(tunnel_parameters
))) {
3023 ifnet_t tunnel_interface
= NULL
;
3024 tunnel_parameters
.interface_name
[tunnel_parameters_length
- sizeof(u_int32_t
) - 1] = 0; // Make sure the string is NULL terminated
3025 if (ifnet_find_by_name(tunnel_parameters
.interface_name
, &tunnel_interface
) == 0) {
3026 ultimate_result_parameter
.tunnel_interface_index
= tunnel_interface
->if_index
;
3027 ifnet_release(tunnel_interface
);
3030 secondary_result
= tunnel_parameters
.secondary_result
;
3031 if (secondary_result
) {
3032 cond_last_interface_index
= ultimate_result_parameter
.tunnel_interface_index
;
3036 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
3037 socket_layer_non_id_conditions
= TRUE
;
3038 ip_output_layer_id_condition
= TRUE
;
3039 if (secondary_result
) {
3040 ip_output_layer_tunnel_condition_from_id
= TRUE
;
3042 } else if (socket_ip_conditions
) {
3043 socket_layer_non_id_conditions
= TRUE
;
3044 ip_output_layer_id_condition
= TRUE
;
3045 ip_output_layer_non_id_conditions
= TRUE
;
3046 if (secondary_result
) {
3047 ip_output_layer_tunnel_condition_from_id
= TRUE
;
3048 ip_output_layer_tunnel_condition_from_non_id
= TRUE
;
3053 case NECP_POLICY_RESULT_TRIGGER
:
3054 case NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
:
3055 case NECP_POLICY_RESULT_TRIGGER_SCOPED
:
3056 case NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
: {
3057 struct necp_policy_result_service service_parameters
;
3058 u_int32_t service_result_length
= necp_policy_get_result_parameter_length(policy
);
3059 bool has_extra_service_data
= FALSE
;
3060 if (service_result_length
>= (sizeof(service_parameters
))) {
3061 has_extra_service_data
= TRUE
;
3063 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&service_parameters
, sizeof(service_parameters
))) {
3064 ultimate_result_parameter
.service
.identifier
= necp_create_uuid_service_id_mapping(service_parameters
.identifier
);
3065 if (ultimate_result_parameter
.service
.identifier
!= 0) {
3066 uuid_copy(policy
->applied_result_uuid
, service_parameters
.identifier
);
3067 socket_layer_non_id_conditions
= TRUE
;
3068 if (has_extra_service_data
) {
3069 ultimate_result_parameter
.service
.data
= service_parameters
.data
;
3071 ultimate_result_parameter
.service
.data
= 0;
3077 case NECP_POLICY_RESULT_USE_NETAGENT
: {
3078 uuid_t netagent_uuid
;
3079 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&netagent_uuid
, sizeof(netagent_uuid
))) {
3080 ultimate_result_parameter
.netagent_id
= necp_create_uuid_service_id_mapping(netagent_uuid
);
3081 if (ultimate_result_parameter
.netagent_id
!= 0) {
3082 uuid_copy(policy
->applied_result_uuid
, netagent_uuid
);
3083 socket_layer_non_id_conditions
= TRUE
;
3088 case NECP_POLICY_RESULT_SOCKET_SCOPED
: {
3089 u_int32_t interface_name_length
= necp_policy_get_result_parameter_length(policy
);
3090 if (interface_name_length
<= IFXNAMSIZ
&& interface_name_length
> 0) {
3091 char interface_name
[IFXNAMSIZ
];
3092 ifnet_t scope_interface
= NULL
;
3093 necp_policy_get_result_parameter(policy
, (u_int8_t
*)interface_name
, interface_name_length
);
3094 interface_name
[interface_name_length
- 1] = 0; // Make sure the string is NULL terminated
3095 if (ifnet_find_by_name(interface_name
, &scope_interface
) == 0) {
3096 ultimate_result_parameter
.scoped_interface_index
= scope_interface
->if_index
;
3097 socket_layer_non_id_conditions
= TRUE
;
3098 ifnet_release(scope_interface
);
3103 case NECP_POLICY_RESULT_ROUTE_RULES
: {
3104 if (policy
->route_rules
!= NULL
&& policy
->route_rules_size
> 0) {
3105 u_int32_t route_rule_id
= necp_create_route_rule(&necp_route_rules
, policy
->route_rules
, policy
->route_rules_size
);
3106 if (route_rule_id
> 0) {
3107 policy
->applied_route_rules_id
= route_rule_id
;
3108 ultimate_result_parameter
.route_rule_id
= route_rule_id
;
3109 socket_layer_non_id_conditions
= TRUE
;
3119 if (socket_layer_non_id_conditions
) {
3120 necp_kernel_policy_id policy_id
= necp_kernel_socket_policy_add(policy
->id
, policy
->order
, session
->session_order
, session
->proc_pid
, master_condition_mask
, master_condition_negated_mask
, cond_app_id
, cond_real_app_id
, cond_custom_entitlement
, cond_account_id
, cond_domain
, cond_pid
, cond_uid
, cond_bound_interface
, cond_traffic_class
, cond_protocol
, &cond_local_start
, &cond_local_end
, cond_local_prefix
, &cond_remote_start
, &cond_remote_end
, cond_remote_prefix
, ultimate_result
, ultimate_result_parameter
);
3122 if (policy_id
== 0) {
3123 NECPLOG0(LOG_DEBUG
, "Error applying socket kernel policy");
3127 cond_ip_output_layer_id
= policy_id
;
3128 policy
->kernel_socket_policies
[0] = policy_id
;
3131 if (ip_output_layer_non_id_conditions
) {
3132 u_int32_t condition_mask
= master_condition_mask
;
3133 if (ip_output_layer_non_id_only
) {
3134 condition_mask
|= NECP_KERNEL_CONDITION_POLICY_ID
;
3136 necp_kernel_policy_id policy_id
= necp_kernel_ip_output_policy_add(policy
->id
, policy
->order
, NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS
, session
->session_order
, 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
, ultimate_result
, ultimate_result_parameter
);
3138 if (policy_id
== 0) {
3139 NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy");
3143 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS
] = policy_id
;
3146 if (ip_output_layer_id_condition
) {
3147 necp_kernel_policy_id policy_id
= necp_kernel_ip_output_policy_add(policy
->id
, policy
->order
, NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION
, session
->session_order
, 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, ultimate_result
, ultimate_result_parameter
);
3149 if (policy_id
== 0) {
3150 NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy");
3154 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION
] = policy_id
;
3157 // Extra policies for IP Output tunnels for when packets loop back
3158 if (ip_output_layer_tunnel_condition_from_id
) {
3159 necp_kernel_policy_id policy_id
= necp_kernel_ip_output_policy_add(policy
->id
, policy
->order
, NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION
, session
->session_order
, 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, secondary_result
, secondary_result_parameter
);
3161 if (policy_id
== 0) {
3162 NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy");
3166 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION
] = policy_id
;
3169 if (ip_output_layer_tunnel_condition_from_id
) {
3170 necp_kernel_policy_id policy_id
= necp_kernel_ip_output_policy_add(policy
->id
, policy
->order
, NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION
, session
->session_order
, 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, secondary_result
, secondary_result_parameter
);
3172 if (policy_id
== 0) {
3173 NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy");
3177 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION
] = policy_id
;
3180 policy
->applied
= TRUE
;
3181 policy
->pending_update
= FALSE
;
3189 necp_policy_apply_all(struct necp_session
*session
)
3191 struct necp_session_policy
*policy
= NULL
;
3192 struct necp_session_policy
*temp_policy
= NULL
;
3193 struct kev_necp_policies_changed_data kev_data
;
3194 kev_data
.changed_count
= 0;
3196 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
3198 // Remove exisiting applied policies
3199 if (session
->dirty
) {
3200 LIST_FOREACH_SAFE(policy
, &session
->policies
, chain
, temp_policy
) {
3201 if (policy
->pending_deletion
) {
3202 if (policy
->applied
) {
3203 necp_policy_unapply(policy
);
3205 // Delete the policy
3206 necp_policy_delete(session
, policy
);
3207 } else if (!policy
->applied
) {
3208 necp_policy_apply(session
, policy
);
3209 } else if (policy
->pending_update
) {
3210 // Must have been applied, but needs an update. Remove and re-add.
3211 necp_policy_unapply(policy
);
3212 necp_policy_apply(session
, policy
);
3216 necp_kernel_socket_policies_update_uuid_table();
3217 necp_kernel_socket_policies_reprocess();
3218 necp_kernel_ip_output_policies_reprocess();
3220 // Clear dirty bit flags
3221 session
->dirty
= FALSE
;
3224 lck_rw_done(&necp_kernel_policy_lock
);
3226 necp_update_all_clients();
3227 necp_post_change_event(&kev_data
);
3230 NECPLOG0(LOG_DEBUG
, "Applied NECP policies");
3234 // Kernel Policy Management
3235 // ---------------------
3236 // Kernel policies are derived from session policies
3237 static necp_kernel_policy_id
3238 necp_kernel_policy_get_new_id(void)
3240 necp_kernel_policy_id newid
= NECP_KERNEL_POLICY_ID_NONE
;
3242 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
3244 necp_last_kernel_policy_id
++;
3245 if (necp_last_kernel_policy_id
< NECP_KERNEL_POLICY_ID_FIRST_VALID
) {
3246 necp_last_kernel_policy_id
= NECP_KERNEL_POLICY_ID_FIRST_VALID
;
3249 newid
= necp_last_kernel_policy_id
;
3250 if (newid
== NECP_KERNEL_POLICY_ID_NONE
) {
3251 NECPLOG0(LOG_DEBUG
, "Allocate kernel policy id failed.\n");
3258 #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)
3259 static necp_kernel_policy_id
3260 necp_kernel_socket_policy_add(necp_policy_id parent_policy_id
, necp_policy_order order
, u_int32_t session_order
, int session_pid
, u_int32_t condition_mask
, u_int32_t condition_negated_mask
, necp_app_id cond_app_id
, necp_app_id cond_real_app_id
, char *cond_custom_entitlement
, u_int32_t cond_account_id
, char *cond_domain
, pid_t cond_pid
, uid_t cond_uid
, ifnet_t cond_bound_interface
, struct necp_policy_condition_tc_range cond_traffic_class
, u_int16_t cond_protocol
, union necp_sockaddr_union
*cond_local_start
, union necp_sockaddr_union
*cond_local_end
, u_int8_t cond_local_prefix
, union necp_sockaddr_union
*cond_remote_start
, union necp_sockaddr_union
*cond_remote_end
, u_int8_t cond_remote_prefix
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
)
3262 struct necp_kernel_socket_policy
*new_kernel_policy
= NULL
;
3263 struct necp_kernel_socket_policy
*tmp_kernel_policy
= NULL
;
3265 MALLOC_ZONE(new_kernel_policy
, struct necp_kernel_socket_policy
*, sizeof(*new_kernel_policy
), M_NECP_SOCKET_POLICY
, M_WAITOK
);
3266 if (new_kernel_policy
== NULL
) {
3270 memset(new_kernel_policy
, 0, sizeof(*new_kernel_policy
));
3271 new_kernel_policy
->parent_policy_id
= parent_policy_id
;
3272 new_kernel_policy
->id
= necp_kernel_policy_get_new_id();
3273 new_kernel_policy
->order
= order
;
3274 new_kernel_policy
->session_order
= session_order
;
3275 new_kernel_policy
->session_pid
= session_pid
;
3277 // Sanitize condition mask
3278 new_kernel_policy
->condition_mask
= (condition_mask
& NECP_KERNEL_VALID_SOCKET_CONDITIONS
);
3279 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
)) {
3280 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE
;
3282 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) && !(new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
)) {
3283 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_REAL_APP_ID
;
3285 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
) && !(new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
)) {
3286 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_ENTITLEMENT
;
3288 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
)) {
3289 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX
;
3291 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
)) {
3292 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX
;
3294 new_kernel_policy
->condition_negated_mask
= condition_negated_mask
& new_kernel_policy
->condition_mask
;
3296 // Set condition values
3297 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
3298 new_kernel_policy
->cond_app_id
= cond_app_id
;
3300 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
3301 new_kernel_policy
->cond_real_app_id
= cond_real_app_id
;
3303 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) {
3304 new_kernel_policy
->cond_custom_entitlement
= cond_custom_entitlement
;
3306 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
3307 new_kernel_policy
->cond_account_id
= cond_account_id
;
3309 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
3310 new_kernel_policy
->cond_domain
= cond_domain
;
3311 new_kernel_policy
->cond_domain_dot_count
= necp_count_dots(cond_domain
, strlen(cond_domain
));
3313 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PID
) {
3314 new_kernel_policy
->cond_pid
= cond_pid
;
3316 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_UID
) {
3317 new_kernel_policy
->cond_uid
= cond_uid
;
3319 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
3320 if (cond_bound_interface
) {
3321 ifnet_reference(cond_bound_interface
);
3323 new_kernel_policy
->cond_bound_interface
= cond_bound_interface
;
3325 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
3326 new_kernel_policy
->cond_traffic_class
= cond_traffic_class
;
3328 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
3329 new_kernel_policy
->cond_protocol
= cond_protocol
;
3331 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
3332 memcpy(&new_kernel_policy
->cond_local_start
, cond_local_start
, cond_local_start
->sa
.sa_len
);
3334 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
3335 memcpy(&new_kernel_policy
->cond_local_end
, cond_local_end
, cond_local_end
->sa
.sa_len
);
3337 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
3338 new_kernel_policy
->cond_local_prefix
= cond_local_prefix
;
3340 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
3341 memcpy(&new_kernel_policy
->cond_remote_start
, cond_remote_start
, cond_remote_start
->sa
.sa_len
);
3343 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
3344 memcpy(&new_kernel_policy
->cond_remote_end
, cond_remote_end
, cond_remote_end
->sa
.sa_len
);
3346 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
3347 new_kernel_policy
->cond_remote_prefix
= cond_remote_prefix
;
3350 new_kernel_policy
->result
= result
;
3351 memcpy(&new_kernel_policy
->result_parameter
, &result_parameter
, sizeof(result_parameter
));
3354 NECPLOG(LOG_DEBUG
, "Added kernel policy: socket, id=%d, mask=%x\n", new_kernel_policy
->id
, new_kernel_policy
->condition_mask
);
3356 LIST_INSERT_SORTED_TWICE_ASCENDING(&necp_kernel_socket_policies
, new_kernel_policy
, chain
, session_order
, order
, tmp_kernel_policy
);
3358 return (new_kernel_policy
? new_kernel_policy
->id
: 0);
3361 static struct necp_kernel_socket_policy
*
3362 necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id
)
3364 struct necp_kernel_socket_policy
*kernel_policy
= NULL
;
3365 struct necp_kernel_socket_policy
*tmp_kernel_policy
= NULL
;
3367 if (policy_id
== 0) {
3371 LIST_FOREACH_SAFE(kernel_policy
, &necp_kernel_socket_policies
, chain
, tmp_kernel_policy
) {
3372 if (kernel_policy
->id
== policy_id
) {
3373 return (kernel_policy
);
3381 necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id
)
3383 struct necp_kernel_socket_policy
*policy
= NULL
;
3385 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
3387 policy
= necp_kernel_socket_policy_find(policy_id
);
3389 LIST_REMOVE(policy
, chain
);
3391 if (policy
->cond_bound_interface
) {
3392 ifnet_release(policy
->cond_bound_interface
);
3393 policy
->cond_bound_interface
= NULL
;
3396 if (policy
->cond_domain
) {
3397 FREE(policy
->cond_domain
, M_NECP
);
3398 policy
->cond_domain
= NULL
;
3401 if (policy
->cond_custom_entitlement
) {
3402 FREE(policy
->cond_custom_entitlement
, M_NECP
);
3403 policy
->cond_custom_entitlement
= NULL
;
3406 FREE_ZONE(policy
, sizeof(*policy
), M_NECP_SOCKET_POLICY
);
3413 static inline const char *
3414 necp_get_result_description(char *result_string
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
)
3416 uuid_string_t uuid_string
;
3418 case NECP_KERNEL_POLICY_RESULT_NONE
: {
3419 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "None");
3422 case NECP_KERNEL_POLICY_RESULT_PASS
: {
3423 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Pass");
3426 case NECP_KERNEL_POLICY_RESULT_SKIP
: {
3427 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Skip (%u)", result_parameter
.skip_policy_order
);
3430 case NECP_KERNEL_POLICY_RESULT_DROP
: {
3431 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Drop");
3434 case NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
: {
3435 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "SocketDivert (%d)", result_parameter
.flow_divert_control_unit
);
3438 case NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER
: {
3439 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "SocketFilter (%d)", result_parameter
.filter_control_unit
);
3442 case NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
: {
3443 ifnet_t interface
= ifindex2ifnet
[result_parameter
.tunnel_interface_index
];
3444 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "IPTunnel (%s%d)", ifnet_name(interface
), ifnet_unit(interface
));
3447 case NECP_KERNEL_POLICY_RESULT_IP_FILTER
: {
3448 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "IPFilter");
3451 case NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
: {
3452 ifnet_t interface
= ifindex2ifnet
[result_parameter
.scoped_interface_index
];
3453 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "SocketScoped (%s%d)", ifnet_name(interface
), ifnet_unit(interface
));
3456 case NECP_KERNEL_POLICY_RESULT_ROUTE_RULES
: {
3458 char interface_names
[IFXNAMSIZ
][MAX_ROUTE_RULE_INTERFACES
];
3459 struct necp_route_rule
*route_rule
= necp_lookup_route_rule_locked(&necp_route_rules
, result_parameter
.route_rule_id
);
3460 if (route_rule
!= NULL
) {
3461 for (index
= 0; index
< MAX_ROUTE_RULE_INTERFACES
; index
++) {
3462 if (route_rule
->exception_if_indices
[index
] != 0) {
3463 ifnet_t interface
= ifindex2ifnet
[route_rule
->exception_if_indices
[index
]];
3464 snprintf(interface_names
[index
], IFXNAMSIZ
, "%s%d", ifnet_name(interface
), ifnet_unit(interface
));
3466 memset(interface_names
[index
], 0, IFXNAMSIZ
);
3469 switch (route_rule
->default_action
) {
3470 case NECP_ROUTE_RULE_DENY_INTERFACE
:
3471 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)",
3472 (route_rule
->cellular_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "Cell " : "",
3473 (route_rule
->wifi_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "WiFi " : "",
3474 (route_rule
->wired_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "Wired " : "",
3475 (route_rule
->expensive_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "Exp " : "",
3476 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[0] : "",
3477 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
3478 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[1] : "",
3479 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
3480 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[2] : "",
3481 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
3482 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[3] : "",
3483 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
3484 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[4] : "",
3485 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
3486 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[5] : "",
3487 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
3488 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[6] : "",
3489 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
3490 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[7] : "",
3491 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
3492 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[8] : "",
3493 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
3494 (route_rule
->exception_if_actions
[9] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[9] : "");
3496 case NECP_ROUTE_RULE_ALLOW_INTERFACE
:
3497 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)",
3498 (route_rule
->cellular_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!Cell " : "",
3499 (route_rule
->wifi_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!WiFi " : "",
3500 (route_rule
->wired_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!Wired " : "",
3501 (route_rule
->expensive_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!Exp " : "",
3502 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
3503 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[0] : "",
3504 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
3505 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[1] : "",
3506 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
3507 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[2] : "",
3508 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
3509 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[3] : "",
3510 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
3511 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[4] : "",
3512 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
3513 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[5] : "",
3514 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
3515 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[6] : "",
3516 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
3517 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[7] : "",
3518 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
3519 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[8] : "",
3520 (route_rule
->exception_if_actions
[9] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
3521 (route_rule
->exception_if_actions
[9] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[9] : "");
3523 case NECP_ROUTE_RULE_QOS_MARKING
:
3524 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)",
3525 (route_rule
->cellular_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? "Cell " : "",
3526 (route_rule
->wifi_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? "WiFi " : "",
3527 (route_rule
->wired_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? "Wired " : "",
3528 (route_rule
->expensive_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? "Exp " : "",
3529 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[0] : "",
3530 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
3531 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[1] : "",
3532 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
3533 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[2] : "",
3534 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
3535 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[3] : "",
3536 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
3537 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[4] : "",
3538 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
3539 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[5] : "",
3540 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
3541 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[6] : "",
3542 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
3543 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[7] : "",
3544 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
3545 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[8] : "",
3546 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
3547 (route_rule
->exception_if_actions
[9] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[9] : "");
3550 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "RouteRules (Unknown)");
3556 case NECP_KERNEL_POLICY_RESULT_USE_NETAGENT
: {
3557 bool found_mapping
= FALSE
;
3558 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.netagent_id
);
3559 if (mapping
!= NULL
) {
3560 uuid_unparse(mapping
->uuid
, uuid_string
);
3561 found_mapping
= TRUE
;
3563 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "UseNetAgent (%s)", found_mapping
? uuid_string
: "Unknown");
3566 case NECP_POLICY_RESULT_TRIGGER
: {
3567 bool found_mapping
= FALSE
;
3568 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.service
.identifier
);
3569 if (mapping
!= NULL
) {
3570 uuid_unparse(mapping
->uuid
, uuid_string
);
3571 found_mapping
= TRUE
;
3573 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Trigger (%s.%d)", found_mapping
? uuid_string
: "Unknown", result_parameter
.service
.data
);
3576 case NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
: {
3577 bool found_mapping
= FALSE
;
3578 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.service
.identifier
);
3579 if (mapping
!= NULL
) {
3580 uuid_unparse(mapping
->uuid
, uuid_string
);
3581 found_mapping
= TRUE
;
3583 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "TriggerIfNeeded (%s.%d)", found_mapping
? uuid_string
: "Unknown", result_parameter
.service
.data
);
3586 case NECP_POLICY_RESULT_TRIGGER_SCOPED
: {
3587 bool found_mapping
= FALSE
;
3588 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.service
.identifier
);
3589 if (mapping
!= NULL
) {
3590 uuid_unparse(mapping
->uuid
, uuid_string
);
3591 found_mapping
= TRUE
;
3593 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "TriggerScoped (%s.%d)", found_mapping
? uuid_string
: "Unknown", result_parameter
.service
.data
);
3596 case NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
: {
3597 bool found_mapping
= FALSE
;
3598 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.service
.identifier
);
3599 if (mapping
!= NULL
) {
3600 uuid_unparse(mapping
->uuid
, uuid_string
);
3601 found_mapping
= TRUE
;
3603 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "NoTriggerScoped (%s.%d)", found_mapping
? uuid_string
: "Unknown", result_parameter
.service
.data
);
3607 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Unknown %d (%d)", result
, result_parameter
.tunnel_interface_index
);
3611 return (result_string
);
3615 necp_kernel_socket_policies_dump_all(void)
3618 struct necp_kernel_socket_policy
*policy
= NULL
;
3621 char result_string
[MAX_RESULT_STRING_LEN
];
3622 char proc_name_string
[MAXCOMLEN
+ 1];
3623 memset(result_string
, 0, MAX_RESULT_STRING_LEN
);
3624 memset(proc_name_string
, 0, MAXCOMLEN
+ 1);
3626 NECPLOG0(LOG_DEBUG
, "NECP Application Policies:\n");
3627 NECPLOG0(LOG_DEBUG
, "-----------\n");
3628 for (policy_i
= 0; necp_kernel_socket_policies_app_layer_map
!= NULL
&& necp_kernel_socket_policies_app_layer_map
[policy_i
] != NULL
; policy_i
++) {
3629 policy
= necp_kernel_socket_policies_app_layer_map
[policy_i
];
3630 proc_name(policy
->session_pid
, proc_name_string
, MAXCOMLEN
);
3631 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
));
3633 if (necp_kernel_socket_policies_app_layer_map
[0] != NULL
) {
3634 NECPLOG0(LOG_DEBUG
, "-----------\n");
3637 NECPLOG0(LOG_DEBUG
, "NECP Socket Policies:\n");
3638 NECPLOG0(LOG_DEBUG
, "-----------\n");
3639 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
3640 NECPLOG(LOG_DEBUG
, "\tApp Bucket: %d\n", app_i
);
3641 for (policy_i
= 0; necp_kernel_socket_policies_map
[app_i
] != NULL
&& (necp_kernel_socket_policies_map
[app_i
])[policy_i
] != NULL
; policy_i
++) {
3642 policy
= (necp_kernel_socket_policies_map
[app_i
])[policy_i
];
3643 proc_name(policy
->session_pid
, proc_name_string
, MAXCOMLEN
);
3644 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
));
3646 NECPLOG0(LOG_DEBUG
, "-----------\n");
3652 necp_kernel_socket_result_is_trigger_service_type(struct necp_kernel_socket_policy
*kernel_policy
)
3654 return (kernel_policy
->result
>= NECP_KERNEL_POLICY_RESULT_TRIGGER
&& kernel_policy
->result
<= NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED
);
3658 necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy
*upper_policy
, struct necp_kernel_socket_policy
*lower_policy
)
3660 if (upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_DROP
) {
3661 // Drop always cancels out lower policies
3663 } else if (upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER
||
3664 upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_ROUTE_RULES
||
3665 upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_USE_NETAGENT
) {
3666 // Filters and route rules never cancel out lower policies
3668 } else if (necp_kernel_socket_result_is_trigger_service_type(upper_policy
)) {
3669 // Trigger/Scoping policies can overlap one another, but not other results
3670 return (necp_kernel_socket_result_is_trigger_service_type(lower_policy
));
3671 } else if (upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
3672 if (upper_policy
->session_order
!= lower_policy
->session_order
) {
3673 // A skip cannot override a policy of a different session
3676 if (upper_policy
->result_parameter
.skip_policy_order
== 0 ||
3677 lower_policy
->order
>= upper_policy
->result_parameter
.skip_policy_order
) {
3678 // This policy is beyond the skip
3681 // This policy is inside the skip
3687 // A hard pass, flow divert, tunnel, or scope will currently block out lower policies
3692 necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy
*policy
, struct necp_kernel_socket_policy
**policy_array
, int valid_indices
)
3694 bool can_skip
= FALSE
;
3695 u_int32_t highest_skip_session_order
= 0;
3696 u_int32_t highest_skip_order
= 0;
3698 for (i
= 0; i
< valid_indices
; i
++) {
3699 struct necp_kernel_socket_policy
*compared_policy
= policy_array
[i
];
3701 // For policies in a skip window, we can't mark conflicting policies as unnecessary
3703 if (highest_skip_session_order
!= compared_policy
->session_order
||
3704 (highest_skip_order
!= 0 && compared_policy
->order
>= highest_skip_order
)) {
3705 // If we've moved on to the next session, or passed the skip window
3706 highest_skip_session_order
= 0;
3707 highest_skip_order
= 0;
3710 // If this policy is also a skip, in can increase the skip window
3711 if (compared_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
3712 if (compared_policy
->result_parameter
.skip_policy_order
> highest_skip_order
) {
3713 highest_skip_order
= compared_policy
->result_parameter
.skip_policy_order
;
3720 if (compared_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
3721 // This policy is a skip. Set the skip window accordingly
3723 highest_skip_session_order
= compared_policy
->session_order
;
3724 highest_skip_order
= compared_policy
->result_parameter
.skip_policy_order
;
3727 // The result of the compared policy must be able to block out this policy result
3728 if (!necp_kernel_socket_policy_results_overlap(compared_policy
, policy
)) {
3732 // If new policy matches All Interfaces, compared policy must also
3733 if ((policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && !(compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) {
3737 // Default makes lower policies unecessary always
3738 if (compared_policy
->condition_mask
== 0) {
3742 // Compared must be more general than policy, and include only conditions within policy
3743 if ((policy
->condition_mask
& compared_policy
->condition_mask
) != compared_policy
->condition_mask
) {
3747 // Negative conditions must match for the overlapping conditions
3748 if ((policy
->condition_negated_mask
& compared_policy
->condition_mask
) != (compared_policy
->condition_negated_mask
& compared_policy
->condition_mask
)) {
3752 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
&&
3753 strcmp(compared_policy
->cond_domain
, policy
->cond_domain
) != 0) {
3757 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
&&
3758 strcmp(compared_policy
->cond_custom_entitlement
, policy
->cond_custom_entitlement
) != 0) {
3762 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
&&
3763 compared_policy
->cond_account_id
!= policy
->cond_account_id
) {
3767 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
&&
3768 compared_policy
->cond_policy_id
!= policy
->cond_policy_id
) {
3772 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
&&
3773 compared_policy
->cond_app_id
!= policy
->cond_app_id
) {
3777 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
&&
3778 compared_policy
->cond_real_app_id
!= policy
->cond_real_app_id
) {
3782 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_PID
&&
3783 compared_policy
->cond_pid
!= policy
->cond_pid
) {
3787 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_UID
&&
3788 compared_policy
->cond_uid
!= policy
->cond_uid
) {
3792 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
&&
3793 compared_policy
->cond_bound_interface
!= policy
->cond_bound_interface
) {
3797 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
&&
3798 compared_policy
->cond_protocol
!= policy
->cond_protocol
) {
3802 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
&&
3803 !(compared_policy
->cond_traffic_class
.start_tc
<= policy
->cond_traffic_class
.start_tc
&&
3804 compared_policy
->cond_traffic_class
.end_tc
>= policy
->cond_traffic_class
.end_tc
)) {
3808 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
3809 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
3810 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
)) {
3813 } else if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
3814 if (compared_policy
->cond_local_prefix
> policy
->cond_local_prefix
||
3815 !necp_is_addr_in_subnet((struct sockaddr
*)&policy
->cond_local_start
, (struct sockaddr
*)&compared_policy
->cond_local_start
, compared_policy
->cond_local_prefix
)) {
3821 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
3822 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
3823 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
)) {
3826 } else if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
3827 if (compared_policy
->cond_remote_prefix
> policy
->cond_remote_prefix
||
3828 !necp_is_addr_in_subnet((struct sockaddr
*)&policy
->cond_remote_start
, (struct sockaddr
*)&compared_policy
->cond_remote_start
, compared_policy
->cond_remote_prefix
)) {
3841 necp_kernel_socket_policies_reprocess(void)
3844 int bucket_allocation_counts
[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
];
3845 int bucket_current_free_index
[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
];
3846 int app_layer_allocation_count
= 0;
3847 int app_layer_current_free_index
= 0;
3848 struct necp_kernel_socket_policy
*kernel_policy
= NULL
;
3850 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
3853 necp_kernel_application_policies_condition_mask
= 0;
3854 necp_kernel_socket_policies_condition_mask
= 0;
3855 necp_kernel_application_policies_count
= 0;
3856 necp_kernel_socket_policies_count
= 0;
3857 necp_kernel_socket_policies_non_app_count
= 0;
3859 // Reset all maps to NULL
3860 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
3861 if (necp_kernel_socket_policies_map
[app_i
] != NULL
) {
3862 FREE(necp_kernel_socket_policies_map
[app_i
], M_NECP
);
3863 necp_kernel_socket_policies_map
[app_i
] = NULL
;
3867 bucket_allocation_counts
[app_i
] = 0;
3869 if (necp_kernel_socket_policies_app_layer_map
!= NULL
) {
3870 FREE(necp_kernel_socket_policies_app_layer_map
, M_NECP
);
3871 necp_kernel_socket_policies_app_layer_map
= NULL
;
3874 // Create masks and counts
3875 LIST_FOREACH(kernel_policy
, &necp_kernel_socket_policies
, chain
) {
3876 // App layer mask/count
3877 necp_kernel_application_policies_condition_mask
|= kernel_policy
->condition_mask
;
3878 necp_kernel_application_policies_count
++;
3879 app_layer_allocation_count
++;
3881 // Update socket layer bucket mask/counts
3882 necp_kernel_socket_policies_condition_mask
|= kernel_policy
->condition_mask
;
3883 necp_kernel_socket_policies_count
++;
3885 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) ||
3886 kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
3887 necp_kernel_socket_policies_non_app_count
++;
3888 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
3889 bucket_allocation_counts
[app_i
]++;
3892 bucket_allocation_counts
[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy
->cond_app_id
)]++;
3897 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
3898 if (bucket_allocation_counts
[app_i
] > 0) {
3899 // Allocate a NULL-terminated array of policy pointers for each bucket
3900 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
);
3901 if (necp_kernel_socket_policies_map
[app_i
] == NULL
) {
3905 // Initialize the first entry to NULL
3906 (necp_kernel_socket_policies_map
[app_i
])[0] = NULL
;
3908 bucket_current_free_index
[app_i
] = 0;
3910 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
);
3911 if (necp_kernel_socket_policies_app_layer_map
== NULL
) {
3914 necp_kernel_socket_policies_app_layer_map
[0] = NULL
;
3917 LIST_FOREACH(kernel_policy
, &necp_kernel_socket_policies
, chain
) {
3918 // Insert pointers into map
3919 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) ||
3920 kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
3921 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
3922 if (!necp_kernel_socket_policy_is_unnecessary(kernel_policy
, necp_kernel_socket_policies_map
[app_i
], bucket_current_free_index
[app_i
])) {
3923 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = kernel_policy
;
3924 bucket_current_free_index
[app_i
]++;
3925 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = NULL
;
3929 app_i
= NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy
->cond_app_id
);
3930 if (!necp_kernel_socket_policy_is_unnecessary(kernel_policy
, necp_kernel_socket_policies_map
[app_i
], bucket_current_free_index
[app_i
])) {
3931 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = kernel_policy
;
3932 bucket_current_free_index
[app_i
]++;
3933 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = NULL
;
3937 if (!necp_kernel_socket_policy_is_unnecessary(kernel_policy
, necp_kernel_socket_policies_app_layer_map
, app_layer_current_free_index
)) {
3938 necp_kernel_socket_policies_app_layer_map
[app_layer_current_free_index
] = kernel_policy
;
3939 app_layer_current_free_index
++;
3940 necp_kernel_socket_policies_app_layer_map
[app_layer_current_free_index
] = NULL
;
3943 necp_kernel_socket_policies_dump_all();
3944 BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT();
3948 // Free memory, reset masks to 0
3949 necp_kernel_application_policies_condition_mask
= 0;
3950 necp_kernel_socket_policies_condition_mask
= 0;
3951 necp_kernel_application_policies_count
= 0;
3952 necp_kernel_socket_policies_count
= 0;
3953 necp_kernel_socket_policies_non_app_count
= 0;
3954 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
3955 if (necp_kernel_socket_policies_map
[app_i
] != NULL
) {
3956 FREE(necp_kernel_socket_policies_map
[app_i
], M_NECP
);
3957 necp_kernel_socket_policies_map
[app_i
] = NULL
;
3960 if (necp_kernel_socket_policies_app_layer_map
!= NULL
) {
3961 FREE(necp_kernel_socket_policies_app_layer_map
, M_NECP
);
3962 necp_kernel_socket_policies_app_layer_map
= NULL
;
3968 necp_get_new_string_id(void)
3970 u_int32_t newid
= 0;
3972 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
3974 necp_last_string_id
++;
3975 if (necp_last_string_id
< 1) {
3976 necp_last_string_id
= 1;
3979 newid
= necp_last_string_id
;
3981 NECPLOG0(LOG_DEBUG
, "Allocate string id failed.\n");
3988 static struct necp_string_id_mapping
*
3989 necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list
*list
, char *string
)
3991 struct necp_string_id_mapping
*searchentry
= NULL
;
3992 struct necp_string_id_mapping
*foundentry
= NULL
;
3994 LIST_FOREACH(searchentry
, list
, chain
) {
3995 if (strcmp(searchentry
->string
, string
) == 0) {
3996 foundentry
= searchentry
;
4001 return (foundentry
);
4004 static struct necp_string_id_mapping
*
4005 necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list
*list
, u_int32_t local_id
)
4007 struct necp_string_id_mapping
*searchentry
= NULL
;
4008 struct necp_string_id_mapping
*foundentry
= NULL
;
4010 LIST_FOREACH(searchentry
, list
, chain
) {
4011 if (searchentry
->id
== local_id
) {
4012 foundentry
= searchentry
;
4017 return (foundentry
);
4021 necp_create_string_to_id_mapping(struct necp_string_id_mapping_list
*list
, char *string
)
4023 u_int32_t string_id
= 0;
4024 struct necp_string_id_mapping
*existing_mapping
= NULL
;
4026 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4028 existing_mapping
= necp_lookup_string_to_id_locked(list
, string
);
4029 if (existing_mapping
!= NULL
) {
4030 string_id
= existing_mapping
->id
;
4031 existing_mapping
->refcount
++;
4033 struct necp_string_id_mapping
*new_mapping
= NULL
;
4034 MALLOC(new_mapping
, struct necp_string_id_mapping
*, sizeof(struct necp_string_id_mapping
), M_NECP
, M_WAITOK
);
4035 if (new_mapping
!= NULL
) {
4036 memset(new_mapping
, 0, sizeof(struct necp_string_id_mapping
));
4038 size_t length
= strlen(string
) + 1;
4039 MALLOC(new_mapping
->string
, char *, length
, M_NECP
, M_WAITOK
);
4040 if (new_mapping
->string
!= NULL
) {
4041 memcpy(new_mapping
->string
, string
, length
);
4042 new_mapping
->id
= necp_get_new_string_id();
4043 new_mapping
->refcount
= 1;
4044 LIST_INSERT_HEAD(list
, new_mapping
, chain
);
4045 string_id
= new_mapping
->id
;
4047 FREE(new_mapping
, M_NECP
);
4056 necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list
*list
, char *string
)
4058 struct necp_string_id_mapping
*existing_mapping
= NULL
;
4060 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4062 existing_mapping
= necp_lookup_string_to_id_locked(list
, string
);
4063 if (existing_mapping
!= NULL
) {
4064 if (--existing_mapping
->refcount
== 0) {
4065 LIST_REMOVE(existing_mapping
, chain
);
4066 FREE(existing_mapping
->string
, M_NECP
);
4067 FREE(existing_mapping
, M_NECP
);
4076 necp_get_new_route_rule_id(void)
4078 u_int32_t newid
= 0;
4080 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4082 necp_last_route_rule_id
++;
4083 if (necp_last_route_rule_id
< 1 || necp_last_route_rule_id
> UINT16_MAX
) {
4084 necp_last_route_rule_id
= 1;
4087 newid
= necp_last_route_rule_id
;
4089 NECPLOG0(LOG_DEBUG
, "Allocate route rule id failed.\n");
4097 necp_get_new_aggregate_route_rule_id(void)
4099 u_int32_t newid
= 0;
4101 lck_rw_assert(&necp_route_rule_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4103 necp_last_aggregate_route_rule_id
++;
4104 if (necp_last_aggregate_route_rule_id
<= UINT16_MAX
) {
4105 necp_last_aggregate_route_rule_id
= UINT16_MAX
+ 1;
4108 newid
= necp_last_aggregate_route_rule_id
;
4110 NECPLOG0(LOG_DEBUG
, "Allocate aggregate route rule id failed.\n");
4117 static struct necp_route_rule
*
4118 necp_lookup_route_rule_locked(struct necp_route_rule_list
*list
, u_int32_t route_rule_id
)
4120 struct necp_route_rule
*searchentry
= NULL
;
4121 struct necp_route_rule
*foundentry
= NULL
;
4123 LIST_FOREACH(searchentry
, list
, chain
) {
4124 if (searchentry
->id
== route_rule_id
) {
4125 foundentry
= searchentry
;
4130 return (foundentry
);
4133 static struct necp_route_rule
*
4134 necp_lookup_route_rule_by_contents_locked(struct necp_route_rule_list
*list
, u_int32_t default_action
, u_int8_t cellular_action
, u_int8_t wifi_action
, u_int8_t wired_action
, u_int8_t expensive_action
, u_int32_t
*if_indices
, u_int8_t
*if_actions
)
4136 struct necp_route_rule
*searchentry
= NULL
;
4137 struct necp_route_rule
*foundentry
= NULL
;
4139 LIST_FOREACH(searchentry
, list
, chain
) {
4140 if (searchentry
->default_action
== default_action
&&
4141 searchentry
->cellular_action
== cellular_action
&&
4142 searchentry
->wifi_action
== wifi_action
&&
4143 searchentry
->wired_action
== wired_action
&&
4144 searchentry
->expensive_action
== expensive_action
) {
4145 bool match_failed
= FALSE
;
4150 for (index_a
= 0; index_a
< MAX_ROUTE_RULE_INTERFACES
; index_a
++) {
4151 bool found_index
= FALSE
;
4152 if (searchentry
->exception_if_indices
[index_a
] == 0) {
4156 for (index_b
= 0; index_b
< MAX_ROUTE_RULE_INTERFACES
; index_b
++) {
4157 if (if_indices
[index_b
] == 0) {
4160 if (index_b
>= count_b
) {
4161 count_b
= index_b
+ 1;
4163 if (searchentry
->exception_if_indices
[index_a
] == if_indices
[index_b
] &&
4164 searchentry
->exception_if_actions
[index_a
] == if_actions
[index_b
]) {
4170 match_failed
= TRUE
;
4174 if (!match_failed
&& count_a
== count_b
) {
4175 foundentry
= searchentry
;
4181 return (foundentry
);
4185 necp_create_route_rule(struct necp_route_rule_list
*list
, u_int8_t
*route_rules_array
, u_int32_t route_rules_array_size
)
4188 u_int32_t route_rule_id
= 0;
4189 struct necp_route_rule
*existing_rule
= NULL
;
4190 u_int32_t default_action
= NECP_ROUTE_RULE_ALLOW_INTERFACE
;
4191 u_int8_t cellular_action
= NECP_ROUTE_RULE_NONE
;
4192 u_int8_t wifi_action
= NECP_ROUTE_RULE_NONE
;
4193 u_int8_t wired_action
= NECP_ROUTE_RULE_NONE
;
4194 u_int8_t expensive_action
= NECP_ROUTE_RULE_NONE
;
4195 u_int32_t if_indices
[MAX_ROUTE_RULE_INTERFACES
];
4196 size_t num_valid_indices
= 0;
4197 memset(&if_indices
, 0, sizeof(if_indices
));
4198 u_int8_t if_actions
[MAX_ROUTE_RULE_INTERFACES
];
4199 memset(&if_actions
, 0, sizeof(if_actions
));
4201 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4203 if (route_rules_array
== NULL
|| route_rules_array_size
== 0) {
4208 while (offset
< route_rules_array_size
) {
4209 ifnet_t rule_interface
= NULL
;
4210 char interface_name
[IFXNAMSIZ
];
4211 u_int32_t length
= 0;
4212 u_int8_t
*value
= necp_buffer_get_tlv_value(route_rules_array
, offset
, &length
);
4214 u_int8_t rule_type
= necp_policy_condition_get_type_from_buffer(value
, length
);
4215 u_int8_t rule_flags
= necp_policy_condition_get_flags_from_buffer(value
, length
);
4216 u_int32_t rule_length
= necp_policy_condition_get_value_length_from_buffer(value
, length
);
4217 u_int8_t
*rule_value
= necp_policy_condition_get_value_pointer_from_buffer(value
, length
);
4219 if (rule_type
== NECP_ROUTE_RULE_NONE
) {
4220 // Don't allow an explicit rule to be None action
4224 if (rule_length
== 0) {
4225 if (rule_flags
& NECP_ROUTE_RULE_FLAG_CELLULAR
) {
4226 cellular_action
= rule_type
;
4228 if (rule_flags
& NECP_ROUTE_RULE_FLAG_WIFI
) {
4229 wifi_action
= rule_type
;
4231 if (rule_flags
& NECP_ROUTE_RULE_FLAG_WIRED
) {
4232 wired_action
= rule_type
;
4234 if (rule_flags
& NECP_ROUTE_RULE_FLAG_EXPENSIVE
) {
4235 expensive_action
= rule_type
;
4237 if (rule_flags
== 0) {
4238 default_action
= rule_type
;
4240 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
4244 if (num_valid_indices
>= MAX_ROUTE_RULE_INTERFACES
) {
4245 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
4249 if (rule_length
<= IFXNAMSIZ
) {
4250 memcpy(interface_name
, rule_value
, rule_length
);
4251 interface_name
[rule_length
- 1] = 0; // Make sure the string is NULL terminated
4252 if (ifnet_find_by_name(interface_name
, &rule_interface
) == 0) {
4253 if_actions
[num_valid_indices
] = rule_type
;
4254 if_indices
[num_valid_indices
++] = rule_interface
->if_index
;
4255 ifnet_release(rule_interface
);
4258 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
4261 existing_rule
= necp_lookup_route_rule_by_contents_locked(list
, default_action
, cellular_action
, wifi_action
, wired_action
, expensive_action
, if_indices
, if_actions
);
4262 if (existing_rule
!= NULL
) {
4263 route_rule_id
= existing_rule
->id
;
4264 existing_rule
->refcount
++;
4266 struct necp_route_rule
*new_rule
= NULL
;
4267 MALLOC(new_rule
, struct necp_route_rule
*, sizeof(struct necp_route_rule
), M_NECP
, M_WAITOK
);
4268 if (new_rule
!= NULL
) {
4269 memset(new_rule
, 0, sizeof(struct necp_route_rule
));
4270 route_rule_id
= new_rule
->id
= necp_get_new_route_rule_id();
4271 new_rule
->default_action
= default_action
;
4272 new_rule
->cellular_action
= cellular_action
;
4273 new_rule
->wifi_action
= wifi_action
;
4274 new_rule
->wired_action
= wired_action
;
4275 new_rule
->expensive_action
= expensive_action
;
4276 memcpy(&new_rule
->exception_if_indices
, &if_indices
, sizeof(if_indices
));
4277 memcpy(&new_rule
->exception_if_actions
, &if_actions
, sizeof(if_actions
));
4278 new_rule
->refcount
= 1;
4279 LIST_INSERT_HEAD(list
, new_rule
, chain
);
4282 return (route_rule_id
);
4286 necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id
)
4289 lck_rw_lock_exclusive(&necp_route_rule_lock
);
4291 struct necp_aggregate_route_rule
*existing_rule
= NULL
;
4292 struct necp_aggregate_route_rule
*tmp_rule
= NULL
;
4294 LIST_FOREACH_SAFE(existing_rule
, &necp_aggregate_route_rules
, chain
, tmp_rule
) {
4296 for (index
= 0; index
< MAX_AGGREGATE_ROUTE_RULES
; index
++) {
4297 u_int32_t route_rule_id
= existing_rule
->rule_ids
[index
];
4298 if (route_rule_id
== rule_id
) {
4299 LIST_REMOVE(existing_rule
, chain
);
4300 FREE(existing_rule
, M_NECP
);
4306 lck_rw_done(&necp_route_rule_lock
);
4311 necp_remove_route_rule(struct necp_route_rule_list
*list
, u_int32_t route_rule_id
)
4313 struct necp_route_rule
*existing_rule
= NULL
;
4315 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4317 existing_rule
= necp_lookup_route_rule_locked(list
, route_rule_id
);
4318 if (existing_rule
!= NULL
) {
4319 if (--existing_rule
->refcount
== 0) {
4320 necp_remove_aggregate_route_rule_for_id(existing_rule
->id
);
4321 LIST_REMOVE(existing_rule
, chain
);
4322 FREE(existing_rule
, M_NECP
);
4330 static struct necp_aggregate_route_rule
*
4331 necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id
)
4333 struct necp_aggregate_route_rule
*searchentry
= NULL
;
4334 struct necp_aggregate_route_rule
*foundentry
= NULL
;
4336 lck_rw_lock_shared(&necp_route_rule_lock
);
4338 LIST_FOREACH(searchentry
, &necp_aggregate_route_rules
, chain
) {
4339 if (searchentry
->id
== route_rule_id
) {
4340 foundentry
= searchentry
;
4345 lck_rw_done(&necp_route_rule_lock
);
4347 return (foundentry
);
4351 necp_create_aggregate_route_rule(u_int32_t
*rule_ids
)
4353 u_int32_t aggregate_route_rule_id
= 0;
4354 struct necp_aggregate_route_rule
*new_rule
= NULL
;
4355 struct necp_aggregate_route_rule
*existing_rule
= NULL
;
4357 LIST_FOREACH(existing_rule
, &necp_aggregate_route_rules
, chain
) {
4358 if (memcmp(existing_rule
->rule_ids
, rule_ids
, (sizeof(u_int32_t
) * MAX_AGGREGATE_ROUTE_RULES
)) == 0) {
4359 return (existing_rule
->id
);
4363 lck_rw_lock_exclusive(&necp_route_rule_lock
);
4365 LIST_FOREACH(existing_rule
, &necp_aggregate_route_rules
, chain
) {
4366 // Re-check, in case something else created the rule while we are waiting to lock
4367 if (memcmp(existing_rule
->rule_ids
, rule_ids
, (sizeof(u_int32_t
) * MAX_AGGREGATE_ROUTE_RULES
)) == 0) {
4368 lck_rw_done(&necp_route_rule_lock
);
4369 return (existing_rule
->id
);
4373 MALLOC(new_rule
, struct necp_aggregate_route_rule
*, sizeof(struct necp_aggregate_route_rule
), M_NECP
, M_WAITOK
);
4374 if (new_rule
!= NULL
) {
4375 memset(new_rule
, 0, sizeof(struct necp_aggregate_route_rule
));
4376 aggregate_route_rule_id
= new_rule
->id
= necp_get_new_aggregate_route_rule_id();
4377 new_rule
->id
= aggregate_route_rule_id
;
4378 memcpy(new_rule
->rule_ids
, rule_ids
, (sizeof(u_int32_t
) * MAX_AGGREGATE_ROUTE_RULES
));
4379 LIST_INSERT_HEAD(&necp_aggregate_route_rules
, new_rule
, chain
);
4381 lck_rw_done(&necp_route_rule_lock
);
4383 return (aggregate_route_rule_id
);
4386 #define NECP_NULL_SERVICE_ID 1
4388 necp_get_new_uuid_id(void)
4390 u_int32_t newid
= 0;
4392 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4394 necp_last_uuid_id
++;
4395 if (necp_last_uuid_id
< (NECP_NULL_SERVICE_ID
+ 1)) {
4396 necp_last_uuid_id
= (NECP_NULL_SERVICE_ID
+ 1);
4399 newid
= necp_last_uuid_id
;
4401 NECPLOG0(LOG_DEBUG
, "Allocate uuid id failed.\n");
4408 static struct necp_uuid_id_mapping
*
4409 necp_uuid_lookup_app_id_locked(uuid_t uuid
)
4411 struct necp_uuid_id_mapping
*searchentry
= NULL
;
4412 struct necp_uuid_id_mapping
*foundentry
= NULL
;
4414 LIST_FOREACH(searchentry
, APPUUIDHASH(uuid
), chain
) {
4415 if (uuid_compare(searchentry
->uuid
, uuid
) == 0) {
4416 foundentry
= searchentry
;
4421 return (foundentry
);
4424 static struct necp_uuid_id_mapping
*
4425 necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id
)
4427 struct necp_uuid_id_mapping
*searchentry
= NULL
;
4428 struct necp_uuid_id_mapping
*foundentry
= NULL
;
4430 struct necp_uuid_id_mapping_head
*uuid_list_head
= NULL
;
4431 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
--) {
4432 LIST_FOREACH(searchentry
, uuid_list_head
, chain
) {
4433 if (searchentry
->id
== local_id
) {
4434 foundentry
= searchentry
;
4440 return (foundentry
);
4444 necp_create_uuid_app_id_mapping(uuid_t uuid
, bool *allocated_mapping
, bool uuid_policy_table
)
4446 u_int32_t local_id
= 0;
4447 struct necp_uuid_id_mapping
*existing_mapping
= NULL
;
4449 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4451 if (allocated_mapping
) {
4452 *allocated_mapping
= FALSE
;
4455 existing_mapping
= necp_uuid_lookup_app_id_locked(uuid
);
4456 if (existing_mapping
!= NULL
) {
4457 local_id
= existing_mapping
->id
;
4458 existing_mapping
->refcount
++;
4459 if (uuid_policy_table
) {
4460 existing_mapping
->table_refcount
++;
4463 struct necp_uuid_id_mapping
*new_mapping
= NULL
;
4464 MALLOC(new_mapping
, struct necp_uuid_id_mapping
*, sizeof(*new_mapping
), M_NECP
, M_WAITOK
);
4465 if (new_mapping
!= NULL
) {
4466 uuid_copy(new_mapping
->uuid
, uuid
);
4467 new_mapping
->id
= necp_get_new_uuid_id();
4468 new_mapping
->refcount
= 1;
4469 if (uuid_policy_table
) {
4470 new_mapping
->table_refcount
= 1;
4472 new_mapping
->table_refcount
= 0;
4475 LIST_INSERT_HEAD(APPUUIDHASH(uuid
), new_mapping
, chain
);
4477 if (allocated_mapping
) {
4478 *allocated_mapping
= TRUE
;
4481 local_id
= new_mapping
->id
;
4489 necp_remove_uuid_app_id_mapping(uuid_t uuid
, bool *removed_mapping
, bool uuid_policy_table
)
4491 struct necp_uuid_id_mapping
*existing_mapping
= NULL
;
4493 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4495 if (removed_mapping
) {
4496 *removed_mapping
= FALSE
;
4499 existing_mapping
= necp_uuid_lookup_app_id_locked(uuid
);
4500 if (existing_mapping
!= NULL
) {
4501 if (uuid_policy_table
) {
4502 existing_mapping
->table_refcount
--;
4504 if (--existing_mapping
->refcount
== 0) {
4505 LIST_REMOVE(existing_mapping
, chain
);
4506 FREE(existing_mapping
, M_NECP
);
4507 if (removed_mapping
) {
4508 *removed_mapping
= TRUE
;
4517 static struct necp_uuid_id_mapping
*
4518 necp_uuid_get_null_service_id_mapping(void)
4520 static struct necp_uuid_id_mapping null_mapping
;
4521 uuid_clear(null_mapping
.uuid
);
4522 null_mapping
.id
= NECP_NULL_SERVICE_ID
;
4524 return (&null_mapping
);
4527 static struct necp_uuid_id_mapping
*
4528 necp_uuid_lookup_service_id_locked(uuid_t uuid
)
4530 struct necp_uuid_id_mapping
*searchentry
= NULL
;
4531 struct necp_uuid_id_mapping
*foundentry
= NULL
;
4533 if (uuid_is_null(uuid
)) {
4534 return necp_uuid_get_null_service_id_mapping();
4537 LIST_FOREACH(searchentry
, &necp_uuid_service_id_list
, chain
) {
4538 if (uuid_compare(searchentry
->uuid
, uuid
) == 0) {
4539 foundentry
= searchentry
;
4544 return (foundentry
);
4547 static struct necp_uuid_id_mapping
*
4548 necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id
)
4550 struct necp_uuid_id_mapping
*searchentry
= NULL
;
4551 struct necp_uuid_id_mapping
*foundentry
= NULL
;
4553 if (local_id
== NECP_NULL_SERVICE_ID
) {
4554 return necp_uuid_get_null_service_id_mapping();
4557 LIST_FOREACH(searchentry
, &necp_uuid_service_id_list
, chain
) {
4558 if (searchentry
->id
== local_id
) {
4559 foundentry
= searchentry
;
4564 return (foundentry
);
4568 necp_create_uuid_service_id_mapping(uuid_t uuid
)
4570 u_int32_t local_id
= 0;
4571 struct necp_uuid_id_mapping
*existing_mapping
= NULL
;
4573 if (uuid_is_null(uuid
)) {
4574 return (NECP_NULL_SERVICE_ID
);
4577 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4579 existing_mapping
= necp_uuid_lookup_service_id_locked(uuid
);
4580 if (existing_mapping
!= NULL
) {
4581 local_id
= existing_mapping
->id
;
4582 existing_mapping
->refcount
++;
4584 struct necp_uuid_id_mapping
*new_mapping
= NULL
;
4585 MALLOC(new_mapping
, struct necp_uuid_id_mapping
*, sizeof(*new_mapping
), M_NECP
, M_WAITOK
);
4586 if (new_mapping
!= NULL
) {
4587 uuid_copy(new_mapping
->uuid
, uuid
);
4588 new_mapping
->id
= necp_get_new_uuid_id();
4589 new_mapping
->refcount
= 1;
4591 LIST_INSERT_HEAD(&necp_uuid_service_id_list
, new_mapping
, chain
);
4593 local_id
= new_mapping
->id
;
4601 necp_remove_uuid_service_id_mapping(uuid_t uuid
)
4603 struct necp_uuid_id_mapping
*existing_mapping
= NULL
;
4605 if (uuid_is_null(uuid
)) {
4609 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4611 existing_mapping
= necp_uuid_lookup_app_id_locked(uuid
);
4612 if (existing_mapping
!= NULL
) {
4613 if (--existing_mapping
->refcount
== 0) {
4614 LIST_REMOVE(existing_mapping
, chain
);
4615 FREE(existing_mapping
, M_NECP
);
4625 necp_kernel_socket_policies_update_uuid_table(void)
4627 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4629 if (necp_uuid_app_id_mappings_dirty
) {
4630 if (proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_CLEAR
, NULL
, PROC_UUID_NECP_APP_POLICY
) < 0) {
4631 NECPLOG0(LOG_DEBUG
, "Error clearing uuids from policy table\n");
4635 if (necp_num_uuid_app_id_mappings
> 0) {
4636 struct necp_uuid_id_mapping_head
*uuid_list_head
= NULL
;
4637 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
--) {
4638 struct necp_uuid_id_mapping
*mapping
= NULL
;
4639 LIST_FOREACH(mapping
, uuid_list_head
, chain
) {
4640 if (mapping
->table_refcount
> 0 &&
4641 proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_ADD
, mapping
->uuid
, PROC_UUID_NECP_APP_POLICY
) < 0) {
4642 NECPLOG0(LOG_DEBUG
, "Error adding uuid to policy table\n");
4648 necp_uuid_app_id_mappings_dirty
= FALSE
;
4654 #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)
4655 static necp_kernel_policy_id
4656 necp_kernel_ip_output_policy_add(necp_policy_id parent_policy_id
, necp_policy_order order
, necp_policy_order suborder
, u_int32_t session_order
, 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
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
)
4658 struct necp_kernel_ip_output_policy
*new_kernel_policy
= NULL
;
4659 struct necp_kernel_ip_output_policy
*tmp_kernel_policy
= NULL
;
4661 MALLOC_ZONE(new_kernel_policy
, struct necp_kernel_ip_output_policy
*, sizeof(*new_kernel_policy
), M_NECP_IP_POLICY
, M_WAITOK
);
4662 if (new_kernel_policy
== NULL
) {
4666 memset(new_kernel_policy
, 0, sizeof(*new_kernel_policy
));
4667 new_kernel_policy
->parent_policy_id
= parent_policy_id
;
4668 new_kernel_policy
->id
= necp_kernel_policy_get_new_id();
4669 new_kernel_policy
->suborder
= suborder
;
4670 new_kernel_policy
->order
= order
;
4671 new_kernel_policy
->session_order
= session_order
;
4672 new_kernel_policy
->session_pid
= session_pid
;
4674 // Sanitize condition mask
4675 new_kernel_policy
->condition_mask
= (condition_mask
& NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS
);
4676 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
)) {
4677 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE
;
4679 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
)) {
4680 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX
;
4682 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
)) {
4683 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX
;
4685 new_kernel_policy
->condition_negated_mask
= condition_negated_mask
& new_kernel_policy
->condition_mask
;
4687 // Set condition values
4688 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
) {
4689 new_kernel_policy
->cond_policy_id
= cond_policy_id
;
4691 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
4692 if (cond_bound_interface
) {
4693 ifnet_reference(cond_bound_interface
);
4695 new_kernel_policy
->cond_bound_interface
= cond_bound_interface
;
4697 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LAST_INTERFACE
) {
4698 new_kernel_policy
->cond_last_interface_index
= cond_last_interface_index
;
4700 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
4701 new_kernel_policy
->cond_protocol
= cond_protocol
;
4703 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
4704 memcpy(&new_kernel_policy
->cond_local_start
, cond_local_start
, cond_local_start
->sa
.sa_len
);
4706 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
4707 memcpy(&new_kernel_policy
->cond_local_end
, cond_local_end
, cond_local_end
->sa
.sa_len
);
4709 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
4710 new_kernel_policy
->cond_local_prefix
= cond_local_prefix
;
4712 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
4713 memcpy(&new_kernel_policy
->cond_remote_start
, cond_remote_start
, cond_remote_start
->sa
.sa_len
);
4715 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
4716 memcpy(&new_kernel_policy
->cond_remote_end
, cond_remote_end
, cond_remote_end
->sa
.sa_len
);
4718 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
4719 new_kernel_policy
->cond_remote_prefix
= cond_remote_prefix
;
4722 new_kernel_policy
->result
= result
;
4723 memcpy(&new_kernel_policy
->result_parameter
, &result_parameter
, sizeof(result_parameter
));
4726 NECPLOG(LOG_DEBUG
, "Added kernel policy: ip output, id=%d, mask=%x\n", new_kernel_policy
->id
, new_kernel_policy
->condition_mask
);
4728 LIST_INSERT_SORTED_THRICE_ASCENDING(&necp_kernel_ip_output_policies
, new_kernel_policy
, chain
, session_order
, order
, suborder
, tmp_kernel_policy
);
4730 return (new_kernel_policy
? new_kernel_policy
->id
: 0);
4733 static struct necp_kernel_ip_output_policy
*
4734 necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id
)
4736 struct necp_kernel_ip_output_policy
*kernel_policy
= NULL
;
4737 struct necp_kernel_ip_output_policy
*tmp_kernel_policy
= NULL
;
4739 if (policy_id
== 0) {
4743 LIST_FOREACH_SAFE(kernel_policy
, &necp_kernel_ip_output_policies
, chain
, tmp_kernel_policy
) {
4744 if (kernel_policy
->id
== policy_id
) {
4745 return (kernel_policy
);
4753 necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id
)
4755 struct necp_kernel_ip_output_policy
*policy
= NULL
;
4757 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4759 policy
= necp_kernel_ip_output_policy_find(policy_id
);
4761 LIST_REMOVE(policy
, chain
);
4763 if (policy
->cond_bound_interface
) {
4764 ifnet_release(policy
->cond_bound_interface
);
4765 policy
->cond_bound_interface
= NULL
;
4768 FREE_ZONE(policy
, sizeof(*policy
), M_NECP_IP_POLICY
);
4776 necp_kernel_ip_output_policies_dump_all(void)
4779 struct necp_kernel_ip_output_policy
*policy
= NULL
;
4782 char result_string
[MAX_RESULT_STRING_LEN
];
4783 char proc_name_string
[MAXCOMLEN
+ 1];
4784 memset(result_string
, 0, MAX_RESULT_STRING_LEN
);
4785 memset(proc_name_string
, 0, MAXCOMLEN
+ 1);
4787 NECPLOG0(LOG_DEBUG
, "NECP IP Output Policies:\n");
4788 NECPLOG0(LOG_DEBUG
, "-----------\n");
4789 for (id_i
= 0; id_i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; id_i
++) {
4790 NECPLOG(LOG_DEBUG
, " ID Bucket: %d\n", id_i
);
4791 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
++) {
4792 policy
= (necp_kernel_ip_output_policies_map
[id_i
])[policy_i
];
4793 proc_name(policy
->session_pid
, proc_name_string
, MAXCOMLEN
);
4794 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
));
4796 NECPLOG0(LOG_DEBUG
, "-----------\n");
4802 necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy
*upper_policy
, struct necp_kernel_ip_output_policy
*lower_policy
)
4804 if (upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
4805 if (upper_policy
->session_order
!= lower_policy
->session_order
) {
4806 // A skip cannot override a policy of a different session
4809 if (upper_policy
->result_parameter
.skip_policy_order
== 0 ||
4810 lower_policy
->order
>= upper_policy
->result_parameter
.skip_policy_order
) {
4811 // This policy is beyond the skip
4814 // This policy is inside the skip
4820 // All other IP Output policy results (drop, tunnel, hard pass) currently overlap
4825 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
)
4827 bool can_skip
= FALSE
;
4828 u_int32_t highest_skip_session_order
= 0;
4829 u_int32_t highest_skip_order
= 0;
4831 for (i
= 0; i
< valid_indices
; i
++) {
4832 struct necp_kernel_ip_output_policy
*compared_policy
= policy_array
[i
];
4834 // For policies in a skip window, we can't mark conflicting policies as unnecessary
4836 if (highest_skip_session_order
!= compared_policy
->session_order
||
4837 (highest_skip_order
!= 0 && compared_policy
->order
>= highest_skip_order
)) {
4838 // If we've moved on to the next session, or passed the skip window
4839 highest_skip_session_order
= 0;
4840 highest_skip_order
= 0;
4843 // If this policy is also a skip, in can increase the skip window
4844 if (compared_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
4845 if (compared_policy
->result_parameter
.skip_policy_order
> highest_skip_order
) {
4846 highest_skip_order
= compared_policy
->result_parameter
.skip_policy_order
;
4853 if (compared_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
4854 // This policy is a skip. Set the skip window accordingly
4856 highest_skip_session_order
= compared_policy
->session_order
;
4857 highest_skip_order
= compared_policy
->result_parameter
.skip_policy_order
;
4860 // The result of the compared policy must be able to block out this policy result
4861 if (!necp_kernel_ip_output_policy_results_overlap(compared_policy
, policy
)) {
4865 // If new policy matches All Interfaces, compared policy must also
4866 if ((policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && !(compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) {
4870 // Default makes lower policies unecessary always
4871 if (compared_policy
->condition_mask
== 0) {
4875 // Compared must be more general than policy, and include only conditions within policy
4876 if ((policy
->condition_mask
& compared_policy
->condition_mask
) != compared_policy
->condition_mask
) {
4880 // Negative conditions must match for the overlapping conditions
4881 if ((policy
->condition_negated_mask
& compared_policy
->condition_mask
) != (compared_policy
->condition_negated_mask
& compared_policy
->condition_mask
)) {
4885 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
&&
4886 compared_policy
->cond_policy_id
!= policy
->cond_policy_id
) {
4890 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
&&
4891 compared_policy
->cond_bound_interface
!= policy
->cond_bound_interface
) {
4895 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
&&
4896 compared_policy
->cond_protocol
!= policy
->cond_protocol
) {
4900 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
4901 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
4902 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
)) {
4905 } else if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
4906 if (compared_policy
->cond_local_prefix
> policy
->cond_local_prefix
||
4907 !necp_is_addr_in_subnet((struct sockaddr
*)&policy
->cond_local_start
, (struct sockaddr
*)&compared_policy
->cond_local_start
, compared_policy
->cond_local_prefix
)) {
4913 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
4914 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
4915 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
)) {
4918 } else if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
4919 if (compared_policy
->cond_remote_prefix
> policy
->cond_remote_prefix
||
4920 !necp_is_addr_in_subnet((struct sockaddr
*)&policy
->cond_remote_start
, (struct sockaddr
*)&compared_policy
->cond_remote_start
, compared_policy
->cond_remote_prefix
)) {
4933 necp_kernel_ip_output_policies_reprocess(void)
4936 int bucket_allocation_counts
[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
];
4937 int bucket_current_free_index
[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
];
4938 struct necp_kernel_ip_output_policy
*kernel_policy
= NULL
;
4940 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4943 necp_kernel_ip_output_policies_condition_mask
= 0;
4944 necp_kernel_ip_output_policies_count
= 0;
4945 necp_kernel_ip_output_policies_non_id_count
= 0;
4947 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
4948 if (necp_kernel_ip_output_policies_map
[i
] != NULL
) {
4949 FREE(necp_kernel_ip_output_policies_map
[i
], M_NECP
);
4950 necp_kernel_ip_output_policies_map
[i
] = NULL
;
4954 bucket_allocation_counts
[i
] = 0;
4957 LIST_FOREACH(kernel_policy
, &necp_kernel_ip_output_policies
, chain
) {
4959 necp_kernel_ip_output_policies_condition_mask
|= kernel_policy
->condition_mask
;
4960 necp_kernel_ip_output_policies_count
++;
4962 // Update bucket counts
4963 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
)) {
4964 necp_kernel_ip_output_policies_non_id_count
++;
4965 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
4966 bucket_allocation_counts
[i
]++;
4969 bucket_allocation_counts
[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy
->cond_policy_id
)]++;
4973 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
4974 if (bucket_allocation_counts
[i
] > 0) {
4975 // Allocate a NULL-terminated array of policy pointers for each bucket
4976 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
);
4977 if (necp_kernel_ip_output_policies_map
[i
] == NULL
) {
4981 // Initialize the first entry to NULL
4982 (necp_kernel_ip_output_policies_map
[i
])[0] = NULL
;
4984 bucket_current_free_index
[i
] = 0;
4987 LIST_FOREACH(kernel_policy
, &necp_kernel_ip_output_policies
, chain
) {
4988 // Insert pointers into map
4989 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
)) {
4990 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
4991 if (!necp_kernel_ip_output_policy_is_unnecessary(kernel_policy
, necp_kernel_ip_output_policies_map
[i
], bucket_current_free_index
[i
])) {
4992 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = kernel_policy
;
4993 bucket_current_free_index
[i
]++;
4994 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = NULL
;
4998 i
= NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy
->cond_policy_id
);
4999 if (!necp_kernel_ip_output_policy_is_unnecessary(kernel_policy
, necp_kernel_ip_output_policies_map
[i
], bucket_current_free_index
[i
])) {
5000 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = kernel_policy
;
5001 bucket_current_free_index
[i
]++;
5002 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = NULL
;
5006 necp_kernel_ip_output_policies_dump_all();
5010 // Free memory, reset mask to 0
5011 necp_kernel_ip_output_policies_condition_mask
= 0;
5012 necp_kernel_ip_output_policies_count
= 0;
5013 necp_kernel_ip_output_policies_non_id_count
= 0;
5014 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
5015 if (necp_kernel_ip_output_policies_map
[i
] != NULL
) {
5016 FREE(necp_kernel_ip_output_policies_map
[i
], M_NECP
);
5017 necp_kernel_ip_output_policies_map
[i
] = NULL
;
5023 // Outbound Policy Matching
5024 // ---------------------
5030 static struct substring
5031 necp_trim_dots_and_stars(char *string
, size_t length
)
5033 struct substring sub
;
5034 sub
.string
= string
;
5035 sub
.length
= string
? length
: 0;
5037 while (sub
.length
&& (sub
.string
[0] == '.' || sub
.string
[0] == '*')) {
5042 while (sub
.length
&& (sub
.string
[sub
.length
- 1] == '.' || sub
.string
[sub
.length
- 1] == '*')) {
5050 necp_create_trimmed_domain(char *string
, size_t length
)
5052 char *trimmed_domain
= NULL
;
5053 struct substring sub
= necp_trim_dots_and_stars(string
, length
);
5055 MALLOC(trimmed_domain
, char *, sub
.length
+ 1, M_NECP
, M_WAITOK
);
5056 if (trimmed_domain
== NULL
) {
5060 memcpy(trimmed_domain
, sub
.string
, sub
.length
);
5061 trimmed_domain
[sub
.length
] = 0;
5063 return (trimmed_domain
);
5067 necp_count_dots(char *string
, size_t length
)
5072 for (i
= 0; i
< length
; i
++) {
5073 if (string
[i
] == '.') {
5082 necp_check_suffix(struct substring parent
, struct substring suffix
, bool require_dot_before_suffix
)
5084 if (parent
.length
<= suffix
.length
) {
5088 size_t length_difference
= (parent
.length
- suffix
.length
);
5090 if (require_dot_before_suffix
) {
5091 if (((char *)(parent
.string
+ length_difference
- 1))[0] != '.') {
5096 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
5097 return (strncasecmp(parent
.string
+ length_difference
, suffix
.string
, suffix
.length
) == 0);
5101 necp_hostname_matches_domain(struct substring hostname_substring
, u_int8_t hostname_dot_count
, char *domain
, u_int8_t domain_dot_count
)
5103 if (hostname_substring
.string
== NULL
|| domain
== NULL
) {
5104 return (hostname_substring
.string
== domain
);
5107 struct substring domain_substring
;
5108 domain_substring
.string
= domain
;
5109 domain_substring
.length
= strlen(domain
);
5111 if (hostname_dot_count
== domain_dot_count
) {
5112 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
5113 if (hostname_substring
.length
== domain_substring
.length
&&
5114 strncasecmp(hostname_substring
.string
, domain_substring
.string
, hostname_substring
.length
) == 0) {
5117 } else if (domain_dot_count
< hostname_dot_count
) {
5118 if (necp_check_suffix(hostname_substring
, domain_substring
, TRUE
)) {
5127 necp_copy_string(char *string
, size_t length
)
5129 char *copied_string
= NULL
;
5131 MALLOC(copied_string
, char *, length
+ 1, M_NECP
, M_WAITOK
);
5132 if (copied_string
== NULL
) {
5136 memcpy(copied_string
, string
, length
);
5137 copied_string
[length
] = 0;
5139 return (copied_string
);
5142 #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)
5144 necp_application_fillout_info_locked(uuid_t application_uuid
, uuid_t real_application_uuid
, char *account
, char *domain
, pid_t pid
, uid_t uid
, u_int16_t protocol
, u_int32_t bound_interface_index
, u_int32_t traffic_class
, union necp_sockaddr_union
*local_addr
, union necp_sockaddr_union
*remote_addr
, proc_t proc
, struct necp_socket_info
*info
)
5146 memset(info
, 0, sizeof(struct necp_socket_info
));
5150 info
->protocol
= protocol
;
5151 info
->bound_interface_index
= bound_interface_index
;
5152 info
->traffic_class
= traffic_class
;
5154 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
&& proc
!= NULL
) {
5155 info
->cred_result
= priv_check_cred(proc_ucred(proc
), PRIV_NET_PRIVILEGED_NECP_MATCH
, 0);
5158 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_APP_ID
&& !uuid_is_null(application_uuid
)) {
5159 struct necp_uuid_id_mapping
*existing_mapping
= necp_uuid_lookup_app_id_locked(application_uuid
);
5160 if (existing_mapping
) {
5161 info
->application_id
= existing_mapping
->id
;
5165 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
&& !uuid_is_null(real_application_uuid
)) {
5166 if (uuid_compare(application_uuid
, real_application_uuid
) == 0) {
5167 info
->real_application_id
= info
->application_id
;
5169 struct necp_uuid_id_mapping
*existing_mapping
= necp_uuid_lookup_app_id_locked(real_application_uuid
);
5170 if (existing_mapping
) {
5171 info
->real_application_id
= existing_mapping
->id
;
5176 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
&& account
!= NULL
) {
5177 struct necp_string_id_mapping
*existing_mapping
= necp_lookup_string_to_id_locked(&necp_account_id_list
, account
);
5178 if (existing_mapping
) {
5179 info
->account_id
= existing_mapping
->id
;
5183 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
5184 info
->domain
= domain
;
5187 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_ADDRESS_TYPE_CONDITIONS
) {
5188 if (local_addr
&& local_addr
->sa
.sa_len
> 0) {
5189 memcpy(&info
->local_addr
, local_addr
, local_addr
->sa
.sa_len
);
5191 if (remote_addr
&& remote_addr
->sa
.sa_len
> 0) {
5192 memcpy(&info
->remote_addr
, remote_addr
, remote_addr
->sa
.sa_len
);
5198 necp_send_application_interface_denied_event(pid_t pid
, uuid_t proc_uuid
, u_int32_t if_functional_type
)
5200 struct kev_netpolicy_ifdenied ev_ifdenied
;
5202 bzero(&ev_ifdenied
, sizeof(ev_ifdenied
));
5204 ev_ifdenied
.ev_data
.epid
= pid
;
5205 uuid_copy(ev_ifdenied
.ev_data
.euuid
, proc_uuid
);
5206 ev_ifdenied
.ev_if_functional_type
= if_functional_type
;
5208 netpolicy_post_msg(KEV_NETPOLICY_IFDENIED
, &ev_ifdenied
.ev_data
, sizeof(ev_ifdenied
));
5211 extern char *proc_name_address(void *p
);
5213 #define NECP_VERIFY_DELEGATION_ENTITLEMENT(_p, _d) \
5214 if (!has_checked_delegation_entitlement) { \
5215 has_delegation_entitlement = (priv_check_cred(proc_ucred(_p), PRIV_NET_PRIVILEGED_SOCKET_DELEGATE, 0) == 0); \
5216 has_checked_delegation_entitlement = TRUE; \
5218 if (!has_delegation_entitlement) { \
5219 NECPLOG(LOG_ERR, "%s(%d) does not hold the necessary entitlement to delegate network traffic for other processes by %s", \
5220 proc_name_address(_p), proc_pid(_p), _d); \
5225 necp_application_find_policy_match_internal(proc_t proc
,
5226 u_int8_t
*parameters
,
5227 u_int32_t parameters_size
,
5228 struct necp_aggregate_result
*returned_result
,
5230 u_int required_interface_index
)
5235 struct necp_kernel_socket_policy
*matched_policy
= NULL
;
5236 struct necp_socket_info info
;
5237 necp_kernel_policy_filter filter_control_unit
= 0;
5238 u_int32_t route_rule_id
= 0;
5239 necp_kernel_policy_result service_action
= 0;
5240 necp_kernel_policy_service service
= { 0, 0 };
5242 u_int16_t protocol
= 0;
5243 u_int32_t bound_interface_index
= required_interface_index
;
5244 u_int32_t traffic_class
= 0;
5245 union necp_sockaddr_union local_addr
;
5246 union necp_sockaddr_union remote_addr
;
5247 bool no_remote_addr
= FALSE
;
5248 u_int8_t remote_family
= 0;
5249 bool no_local_addr
= FALSE
;
5251 memset(&local_addr
, 0, sizeof(local_addr
));
5252 memset(&remote_addr
, 0, sizeof(remote_addr
));
5254 // Initialize UID, PID, and UUIDs to the current process
5255 uid_t uid
= kauth_cred_getuid(proc_ucred(proc
));
5256 pid_t pid
= proc_pid(proc
);
5257 uuid_t application_uuid
;
5258 uuid_clear(application_uuid
);
5259 uuid_t real_application_uuid
;
5260 uuid_clear(real_application_uuid
);
5261 proc_getexecutableuuid(proc
, real_application_uuid
, sizeof(real_application_uuid
));
5262 uuid_copy(application_uuid
, real_application_uuid
);
5264 char *domain
= NULL
;
5265 char *account
= NULL
;
5267 u_int32_t netagent_ids
[NECP_MAX_NETAGENTS
];
5268 memset(&netagent_ids
, 0, sizeof(netagent_ids
));
5269 int netagent_cursor
;
5271 bool has_checked_delegation_entitlement
= FALSE
;
5272 bool has_delegation_entitlement
= FALSE
;
5274 if (returned_result
== NULL
) {
5278 memset(returned_result
, 0, sizeof(struct necp_aggregate_result
));
5280 lck_rw_lock_shared(&necp_kernel_policy_lock
);
5281 if (necp_kernel_application_policies_count
== 0) {
5282 if (necp_drop_all_order
> 0) {
5283 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
5284 lck_rw_done(&necp_kernel_policy_lock
);
5288 lck_rw_done(&necp_kernel_policy_lock
);
5290 while ((offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)) <= parameters_size
) {
5291 u_int8_t type
= necp_buffer_get_tlv_type(parameters
, offset
);
5292 u_int32_t length
= necp_buffer_get_tlv_length(parameters
, offset
);
5294 if (length
> 0 && (offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
) <= parameters_size
) {
5295 u_int8_t
*value
= necp_buffer_get_tlv_value(parameters
, offset
, NULL
);
5296 if (value
!= NULL
) {
5298 case NECP_CLIENT_PARAMETER_APPLICATION
: {
5299 if (length
>= sizeof(uuid_t
)) {
5300 if (uuid_compare(application_uuid
, value
) == 0) {
5305 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc
, "euuid");
5307 uuid_copy(application_uuid
, value
);
5311 case NECP_CLIENT_PARAMETER_REAL_APPLICATION
: {
5312 if (length
>= sizeof(uuid_t
)) {
5313 if (uuid_compare(real_application_uuid
, value
) == 0) {
5318 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc
, "uuid");
5320 uuid_copy(real_application_uuid
, value
);
5324 case NECP_CLIENT_PARAMETER_PID
: {
5325 if (length
>= sizeof(pid_t
)) {
5326 if (memcmp(&pid
, value
, sizeof(pid_t
)) == 0) {
5331 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc
, "pid");
5333 memcpy(&pid
, value
, sizeof(pid_t
));
5337 case NECP_CLIENT_PARAMETER_UID
: {
5338 if (length
>= sizeof(uid_t
)) {
5339 if (memcmp(&uid
, value
, sizeof(uid_t
)) == 0) {
5344 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc
, "uid");
5346 memcpy(&uid
, value
, sizeof(uid_t
));
5350 case NECP_CLIENT_PARAMETER_DOMAIN
: {
5351 domain
= (char *)value
;
5352 domain
[length
- 1] = 0;
5355 case NECP_CLIENT_PARAMETER_ACCOUNT
: {
5356 account
= (char *)value
;
5357 account
[length
- 1] = 0;
5360 case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS
: {
5361 if (length
>= sizeof(u_int32_t
)) {
5362 memcpy(&traffic_class
, value
, sizeof(u_int32_t
));
5366 case NECP_CLIENT_PARAMETER_IP_PROTOCOL
: {
5367 if (length
>= sizeof(u_int16_t
)) {
5368 memcpy(&protocol
, value
, sizeof(u_int16_t
));
5372 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE
: {
5373 if (length
<= IFXNAMSIZ
&& length
> 0) {
5374 ifnet_t bound_interface
= NULL
;
5375 char interface_name
[IFXNAMSIZ
];
5376 memcpy(interface_name
, value
, length
);
5377 interface_name
[length
- 1] = 0; // Make sure the string is NULL terminated
5378 if (ifnet_find_by_name(interface_name
, &bound_interface
) == 0) {
5379 bound_interface_index
= bound_interface
->if_index
;
5380 ifnet_release(bound_interface
);
5385 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS
: {
5386 if (length
>= sizeof(struct necp_policy_condition_addr
)) {
5387 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)value
;
5388 if (necp_address_is_valid(&address_struct
->address
.sa
)) {
5389 memcpy(&local_addr
, &address_struct
->address
, sizeof(address_struct
->address
));
5394 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS
: {
5395 if (length
>= sizeof(struct necp_policy_condition_addr
)) {
5396 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)value
;
5397 if (necp_address_is_valid(&address_struct
->address
.sa
)) {
5398 memcpy(&remote_addr
, &address_struct
->address
, sizeof(address_struct
->address
));
5410 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
5414 lck_rw_lock_shared(&necp_kernel_policy_lock
);
5416 necp_application_fillout_info_locked(application_uuid
, real_application_uuid
, account
, domain
, pid
, uid
, protocol
, bound_interface_index
, traffic_class
, &local_addr
, &remote_addr
, proc
, &info
);
5417 matched_policy
= necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_app_layer_map
, &info
, &filter_control_unit
, &route_rule_id
, &service_action
, &service
, netagent_ids
, NECP_MAX_NETAGENTS
, proc
);
5418 if (matched_policy
) {
5419 returned_result
->policy_id
= matched_policy
->id
;
5420 returned_result
->routing_result
= matched_policy
->result
;
5421 memcpy(&returned_result
->routing_result_parameter
, &matched_policy
->result_parameter
, sizeof(returned_result
->routing_result_parameter
));
5423 returned_result
->policy_id
= 0;
5424 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_NONE
;
5426 returned_result
->filter_control_unit
= filter_control_unit
;
5427 returned_result
->service_action
= service_action
;
5429 // Handle trigger service
5430 if (service
.identifier
!= 0) {
5431 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(service
.identifier
);
5432 if (mapping
!= NULL
) {
5433 struct necp_service_registration
*service_registration
= NULL
;
5434 uuid_copy(returned_result
->service_uuid
, mapping
->uuid
);
5435 returned_result
->service_data
= service
.data
;
5436 if (service
.identifier
== NECP_NULL_SERVICE_ID
) {
5437 // NULL service is always 'registered'
5438 returned_result
->service_flags
|= NECP_SERVICE_FLAGS_REGISTERED
;
5440 LIST_FOREACH(service_registration
, &necp_registered_service_list
, kernel_chain
) {
5441 if (service
.identifier
== service_registration
->service_id
) {
5442 returned_result
->service_flags
|= NECP_SERVICE_FLAGS_REGISTERED
;
5451 for (netagent_cursor
= 0; netagent_cursor
< NECP_MAX_NETAGENTS
; netagent_cursor
++) {
5452 struct necp_uuid_id_mapping
*mapping
= NULL
;
5453 u_int32_t netagent_id
= netagent_ids
[netagent_cursor
];
5454 if (netagent_id
== 0) {
5457 mapping
= necp_uuid_lookup_uuid_with_service_id_locked(netagent_id
);
5458 if (mapping
!= NULL
) {
5459 uuid_copy(returned_result
->netagents
[netagent_cursor
], mapping
->uuid
);
5460 returned_result
->netagent_flags
[netagent_cursor
] = netagent_get_flags(mapping
->uuid
);
5464 // Do routing evaluation
5465 u_int output_bound_interface
= bound_interface_index
;
5466 if (returned_result
->routing_result
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
) {
5467 output_bound_interface
= returned_result
->routing_result_parameter
.scoped_interface_index
;
5468 } else if (returned_result
->routing_result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
) {
5469 output_bound_interface
= returned_result
->routing_result_parameter
.tunnel_interface_index
;
5472 if (local_addr
.sa
.sa_len
== 0 ||
5473 (local_addr
.sa
.sa_family
== AF_INET
&& local_addr
.sin
.sin_addr
.s_addr
== 0) ||
5474 (local_addr
.sa
.sa_family
== AF_INET6
&& IN6_IS_ADDR_UNSPECIFIED(&local_addr
.sin6
.sin6_addr
))) {
5475 no_local_addr
= TRUE
;
5478 if (remote_addr
.sa
.sa_len
== 0 ||
5479 (remote_addr
.sa
.sa_family
== AF_INET
&& remote_addr
.sin
.sin_addr
.s_addr
== 0) ||
5480 (remote_addr
.sa
.sa_family
== AF_INET6
&& IN6_IS_ADDR_UNSPECIFIED(&remote_addr
.sin6
.sin6_addr
))) {
5481 no_remote_addr
= TRUE
;
5482 remote_family
= remote_addr
.sa
.sa_family
;
5485 if (no_remote_addr
) {
5486 memset(&remote_addr
, 0, sizeof(remote_addr
));
5487 if (remote_family
== AF_INET6
) {
5488 // Reset address to ::
5489 remote_addr
.sa
.sa_family
= AF_INET6
;
5490 remote_addr
.sa
.sa_len
= sizeof(struct sockaddr_in6
);
5492 // Reset address to 0.0.0.0
5493 remote_addr
.sa
.sa_family
= AF_INET
;
5494 remote_addr
.sa
.sa_len
= sizeof(struct sockaddr_in
);
5498 struct rtentry
*rt
= NULL
;
5499 rt
= rtalloc1_scoped((struct sockaddr
*)&remote_addr
, 0, 0,
5500 output_bound_interface
);
5502 if (no_remote_addr
&& remote_family
== 0 &&
5503 (rt
== NULL
|| rt
->rt_ifp
== NULL
)) {
5504 // Route lookup for default IPv4 failed, try IPv6
5506 // Cleanup old route if necessary
5512 // Reset address to ::
5513 memset(&remote_addr
, 0, sizeof(remote_addr
));
5514 remote_addr
.sa
.sa_family
= AF_INET6
;
5515 remote_addr
.sa
.sa_len
= sizeof(struct sockaddr_in6
);
5518 rt
= rtalloc1_scoped((struct sockaddr
*)&remote_addr
, 0, 0,
5519 output_bound_interface
);
5522 returned_result
->routed_interface_index
= 0;
5524 rt
->rt_ifp
!= NULL
) {
5525 returned_result
->routed_interface_index
= rt
->rt_ifp
->if_index
;
5527 * For local addresses, we allow the interface scope to be
5528 * either the loopback interface or the interface hosting the
5531 if (bound_interface_index
!= IFSCOPE_NONE
&&
5532 rt
->rt_ifa
!= NULL
&& rt
->rt_ifa
->ifa_ifp
&&
5533 (output_bound_interface
== lo_ifp
->if_index
||
5534 rt
->rt_ifp
->if_index
== lo_ifp
->if_index
||
5535 rt
->rt_ifa
->ifa_ifp
->if_index
== bound_interface_index
)) {
5536 struct sockaddr_storage dst
;
5537 unsigned int ifscope
= bound_interface_index
;
5540 * Transform dst into the internal routing table form
5542 (void) sa_copy((struct sockaddr
*)&remote_addr
,
5545 if ((rt
->rt_ifp
->if_index
== lo_ifp
->if_index
) ||
5546 rt_ifa_is_dst((struct sockaddr
*)&dst
, rt
->rt_ifa
))
5547 returned_result
->routed_interface_index
=
5548 bound_interface_index
;
5552 if (returned_result
->routed_interface_index
!= 0 &&
5553 returned_result
->routed_interface_index
!= lo_ifp
->if_index
&& // Loopback can accept any local address
5556 // Transform local_addr into the ifaddr form
5557 // IPv6 Scope IDs are always embedded in the ifaddr list
5558 struct sockaddr_storage local_address_sanitized
;
5559 u_int ifscope
= IFSCOPE_NONE
;
5560 (void)sa_copy(&local_addr
.sa
, &local_address_sanitized
, &ifscope
);
5561 SIN(&local_address_sanitized
)->sin_port
= 0;
5562 if (local_address_sanitized
.ss_family
== AF_INET6
) {
5563 SIN6(&local_address_sanitized
)->sin6_scope_id
= 0;
5566 // Validate local address on routed interface
5567 struct ifaddr
*ifa
= ifa_ifwithaddr_scoped((struct sockaddr
*)&local_address_sanitized
, returned_result
->routed_interface_index
);
5569 // Interface address not found, reject route
5570 returned_result
->routed_interface_index
= 0;
5576 ifaddr_release(ifa
);
5581 if (flags
!= NULL
) {
5582 // Check for local/direct
5583 bool is_local
= FALSE
;
5584 if (rt
!= NULL
&& (rt
->rt_flags
& RTF_LOCAL
)) {
5586 } else if (returned_result
->routed_interface_index
!= 0 &&
5588 // Check if remote address is an interface address
5589 struct ifaddr
*ifa
= ifa_ifwithaddr(&remote_addr
.sa
);
5590 if (ifa
!= NULL
&& ifa
->ifa_ifp
!= NULL
) {
5591 u_int if_index_for_remote_addr
= ifa
->ifa_ifp
->if_index
;
5592 if (if_index_for_remote_addr
== returned_result
->routed_interface_index
||
5593 if_index_for_remote_addr
== lo_ifp
->if_index
) {
5598 ifaddr_release(ifa
);
5604 *flags
|= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL
| NECP_CLIENT_RESULT_FLAG_IS_DIRECT
);
5607 !(rt
->rt_flags
& RTF_GATEWAY
) &&
5608 (rt
->rt_ifa
&& rt
->rt_ifa
->ifa_ifp
&& !(rt
->rt_ifa
->ifa_ifp
->if_flags
& IFF_POINTOPOINT
))) {
5609 // Route is directly accessible
5610 *flags
|= NECP_CLIENT_RESULT_FLAG_IS_DIRECT
;
5614 if (returned_result
->routed_interface_index
!= 0) {
5615 union necp_sockaddr_union default_address
;
5616 struct rtentry
*v4Route
= NULL
;
5617 struct rtentry
*v6Route
= NULL
;
5619 memset(&default_address
, 0, sizeof(default_address
));
5621 // Reset address to 0.0.0.0
5622 default_address
.sa
.sa_family
= AF_INET
;
5623 default_address
.sa
.sa_len
= sizeof(struct sockaddr_in
);
5624 v4Route
= rtalloc1_scoped((struct sockaddr
*)&default_address
, 0, 0,
5625 returned_result
->routed_interface_index
);
5627 // Reset address to ::
5628 default_address
.sa
.sa_family
= AF_INET6
;
5629 default_address
.sa
.sa_len
= sizeof(struct sockaddr_in6
);
5630 v6Route
= rtalloc1_scoped((struct sockaddr
*)&default_address
, 0, 0,
5631 returned_result
->routed_interface_index
);
5633 if (v4Route
!= NULL
) {
5634 if (v4Route
->rt_ifp
!= NULL
) {
5635 *flags
|= NECP_CLIENT_RESULT_FLAG_HAS_IPV4
;
5641 if (v6Route
!= NULL
) {
5642 if (v6Route
->rt_ifp
!= NULL
) {
5643 *flags
|= NECP_CLIENT_RESULT_FLAG_HAS_IPV6
;
5651 u_int32_t interface_type_denied
= IFRTYPE_FUNCTIONAL_UNKNOWN
;
5652 bool route_is_allowed
= necp_route_is_allowed(rt
, NULL
, route_rule_id
, &interface_type_denied
);
5653 if (!route_is_allowed
) {
5654 // If the route is blocked, treat the lookup as a drop
5655 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
5656 memset(&returned_result
->routing_result_parameter
, 0, sizeof(returned_result
->routing_result_parameter
));
5658 if (interface_type_denied
!= IFRTYPE_FUNCTIONAL_UNKNOWN
) {
5659 necp_send_application_interface_denied_event(pid
, application_uuid
, interface_type_denied
);
5668 lck_rw_done(&necp_kernel_policy_lock
);
5674 necp_socket_check_policy(struct necp_kernel_socket_policy
*kernel_policy
, necp_app_id app_id
, necp_app_id real_app_id
, errno_t cred_result
, u_int32_t account_id
, struct substring domain
, u_int8_t domain_dot_count
, pid_t pid
, uid_t uid
, u_int32_t bound_interface_index
, u_int32_t traffic_class
, u_int16_t protocol
, union necp_sockaddr_union
*local
, union necp_sockaddr_union
*remote
, proc_t proc
)
5676 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) {
5677 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
5678 u_int32_t cond_bound_interface_index
= kernel_policy
->cond_bound_interface
? kernel_policy
->cond_bound_interface
->if_index
: 0;
5679 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
5680 if (bound_interface_index
== cond_bound_interface_index
) {
5681 // No match, matches forbidden interface
5685 if (bound_interface_index
!= cond_bound_interface_index
) {
5686 // No match, does not match required interface
5691 if (bound_interface_index
!= 0) {
5692 // No match, requires a non-bound packet
5698 if (kernel_policy
->condition_mask
== 0) {
5702 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
5703 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
5704 if (app_id
== kernel_policy
->cond_app_id
) {
5705 // No match, matches forbidden application
5709 if (app_id
!= kernel_policy
->cond_app_id
) {
5710 // No match, does not match required application
5716 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
5717 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
5718 if (real_app_id
== kernel_policy
->cond_real_app_id
) {
5719 // No match, matches forbidden application
5723 if (real_app_id
!= kernel_policy
->cond_real_app_id
) {
5724 // No match, does not match required application
5730 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
) {
5731 if (cred_result
!= 0) {
5732 // Process is missing entitlement
5737 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) {
5738 if (kernel_policy
->cond_custom_entitlement
!= NULL
) {
5740 // No process found, cannot check entitlement
5743 task_t task
= proc_task(proc
);
5745 !IOTaskHasEntitlement(task
, kernel_policy
->cond_custom_entitlement
)) {
5746 // Process is missing custom entitlement
5752 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
5753 bool domain_matches
= necp_hostname_matches_domain(domain
, domain_dot_count
, kernel_policy
->cond_domain
, kernel_policy
->cond_domain_dot_count
);
5754 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
5755 if (domain_matches
) {
5756 // No match, matches forbidden domain
5760 if (!domain_matches
) {
5761 // No match, does not match required domain
5767 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
5768 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
5769 if (account_id
== kernel_policy
->cond_account_id
) {
5770 // No match, matches forbidden account
5774 if (account_id
!= kernel_policy
->cond_account_id
) {
5775 // No match, does not match required account
5781 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PID
) {
5782 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_PID
) {
5783 if (pid
== kernel_policy
->cond_pid
) {
5784 // No match, matches forbidden pid
5788 if (pid
!= kernel_policy
->cond_pid
) {
5789 // No match, does not match required pid
5795 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_UID
) {
5796 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_UID
) {
5797 if (uid
== kernel_policy
->cond_uid
) {
5798 // No match, matches forbidden uid
5802 if (uid
!= kernel_policy
->cond_uid
) {
5803 // No match, does not match required uid
5809 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
5810 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
5811 if (traffic_class
>= kernel_policy
->cond_traffic_class
.start_tc
&&
5812 traffic_class
<= kernel_policy
->cond_traffic_class
.end_tc
) {
5813 // No match, matches forbidden traffic class
5817 if (traffic_class
< kernel_policy
->cond_traffic_class
.start_tc
||
5818 traffic_class
> kernel_policy
->cond_traffic_class
.end_tc
) {
5819 // No match, does not match required traffic class
5825 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
5826 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
5827 if (protocol
== kernel_policy
->cond_protocol
) {
5828 // No match, matches forbidden protocol
5832 if (protocol
!= kernel_policy
->cond_protocol
) {
5833 // No match, does not match required protocol
5839 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
5840 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
5841 bool inRange
= necp_is_addr_in_range((struct sockaddr
*)local
, (struct sockaddr
*)&kernel_policy
->cond_local_start
, (struct sockaddr
*)&kernel_policy
->cond_local_end
);
5842 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
5851 } else if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
5852 bool inSubnet
= necp_is_addr_in_subnet((struct sockaddr
*)local
, (struct sockaddr
*)&kernel_policy
->cond_local_start
, kernel_policy
->cond_local_prefix
);
5853 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
5865 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
5866 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
5867 bool inRange
= necp_is_addr_in_range((struct sockaddr
*)remote
, (struct sockaddr
*)&kernel_policy
->cond_remote_start
, (struct sockaddr
*)&kernel_policy
->cond_remote_end
);
5868 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
5877 } else if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
5878 bool inSubnet
= necp_is_addr_in_subnet((struct sockaddr
*)remote
, (struct sockaddr
*)&kernel_policy
->cond_remote_start
, kernel_policy
->cond_remote_prefix
);
5879 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
5894 static inline u_int32_t
5895 necp_socket_calc_flowhash_locked(struct necp_socket_info
*info
)
5897 return (net_flowhash(info
, sizeof(*info
), necp_kernel_socket_policies_gencount
));
5901 necp_socket_fillout_info_locked(struct inpcb
*inp
, struct sockaddr
*override_local_addr
, struct sockaddr
*override_remote_addr
, u_int32_t override_bound_interface
, struct necp_socket_info
*info
)
5903 struct socket
*so
= NULL
;
5905 memset(info
, 0, sizeof(struct necp_socket_info
));
5907 so
= inp
->inp_socket
;
5909 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_PID
) {
5910 info
->pid
= ((so
->so_flags
& SOF_DELEGATED
) ? so
->e_pid
: so
->last_pid
);
5913 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_UID
) {
5914 info
->uid
= kauth_cred_getuid(so
->so_cred
);
5917 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
5918 info
->traffic_class
= so
->so_traffic_class
;
5921 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
5922 if (inp
->inp_ip_p
) {
5923 info
->protocol
= inp
->inp_ip_p
;
5925 info
->protocol
= SOCK_PROTO(so
);
5929 if (inp
->inp_flags2
& INP2_WANT_APP_POLICY
&& necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
5930 struct necp_uuid_id_mapping
*existing_mapping
= necp_uuid_lookup_app_id_locked(((so
->so_flags
& SOF_DELEGATED
) ? so
->e_uuid
: so
->last_uuid
));
5931 if (existing_mapping
) {
5932 info
->application_id
= existing_mapping
->id
;
5935 if (!(so
->so_flags
& SOF_DELEGATED
)) {
5936 info
->real_application_id
= info
->application_id
;
5937 } else if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
5938 struct necp_uuid_id_mapping
*real_existing_mapping
= necp_uuid_lookup_app_id_locked(so
->last_uuid
);
5939 if (real_existing_mapping
) {
5940 info
->real_application_id
= real_existing_mapping
->id
;
5944 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
) {
5945 info
->cred_result
= priv_check_cred(so
->so_cred
, PRIV_NET_PRIVILEGED_NECP_MATCH
, 0);
5949 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
&& inp
->inp_necp_attributes
.inp_account
!= NULL
) {
5950 struct necp_string_id_mapping
*existing_mapping
= necp_lookup_string_to_id_locked(&necp_account_id_list
, inp
->inp_necp_attributes
.inp_account
);
5951 if (existing_mapping
) {
5952 info
->account_id
= existing_mapping
->id
;
5956 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
5957 info
->domain
= inp
->inp_necp_attributes
.inp_domain
;
5960 if (override_bound_interface
) {
5961 info
->bound_interface_index
= override_bound_interface
;
5963 if ((inp
->inp_flags
& INP_BOUND_IF
) && inp
->inp_boundifp
) {
5964 info
->bound_interface_index
= inp
->inp_boundifp
->if_index
;
5968 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_ADDRESS_TYPE_CONDITIONS
) {
5969 if (inp
->inp_vflag
& INP_IPV4
) {
5970 if (override_local_addr
) {
5971 if (override_local_addr
->sa_len
<= sizeof(struct sockaddr_in
)) {
5972 memcpy(&info
->local_addr
, override_local_addr
, override_local_addr
->sa_len
);
5975 ((struct sockaddr_in
*)&info
->local_addr
)->sin_family
= AF_INET
;
5976 ((struct sockaddr_in
*)&info
->local_addr
)->sin_len
= sizeof(struct sockaddr_in
);
5977 ((struct sockaddr_in
*)&info
->local_addr
)->sin_port
= inp
->inp_lport
;
5978 memcpy(&((struct sockaddr_in
*)&info
->local_addr
)->sin_addr
, &inp
->inp_laddr
, sizeof(struct in_addr
));
5981 if (override_remote_addr
) {
5982 if (override_remote_addr
->sa_len
<= sizeof(struct sockaddr_in
)) {
5983 memcpy(&info
->remote_addr
, override_remote_addr
, override_remote_addr
->sa_len
);
5986 ((struct sockaddr_in
*)&info
->remote_addr
)->sin_family
= AF_INET
;
5987 ((struct sockaddr_in
*)&info
->remote_addr
)->sin_len
= sizeof(struct sockaddr_in
);
5988 ((struct sockaddr_in
*)&info
->remote_addr
)->sin_port
= inp
->inp_fport
;
5989 memcpy(&((struct sockaddr_in
*)&info
->remote_addr
)->sin_addr
, &inp
->inp_faddr
, sizeof(struct in_addr
));
5991 } else if (inp
->inp_vflag
& INP_IPV6
) {
5992 if (override_local_addr
) {
5993 if (override_local_addr
->sa_len
<= sizeof(struct sockaddr_in6
)) {
5994 memcpy(&info
->local_addr
, override_local_addr
, override_local_addr
->sa_len
);
5997 ((struct sockaddr_in6
*)&info
->local_addr
)->sin6_family
= AF_INET6
;
5998 ((struct sockaddr_in6
*)&info
->local_addr
)->sin6_len
= sizeof(struct sockaddr_in6
);
5999 ((struct sockaddr_in6
*)&info
->local_addr
)->sin6_port
= inp
->inp_lport
;
6000 memcpy(&((struct sockaddr_in6
*)&info
->local_addr
)->sin6_addr
, &inp
->in6p_laddr
, sizeof(struct in6_addr
));
6003 if (override_remote_addr
) {
6004 if (override_remote_addr
->sa_len
<= sizeof(struct sockaddr_in6
)) {
6005 memcpy(&info
->remote_addr
, override_remote_addr
, override_remote_addr
->sa_len
);
6008 ((struct sockaddr_in6
*)&info
->remote_addr
)->sin6_family
= AF_INET6
;
6009 ((struct sockaddr_in6
*)&info
->remote_addr
)->sin6_len
= sizeof(struct sockaddr_in6
);
6010 ((struct sockaddr_in6
*)&info
->remote_addr
)->sin6_port
= inp
->inp_fport
;
6011 memcpy(&((struct sockaddr_in6
*)&info
->remote_addr
)->sin6_addr
, &inp
->in6p_faddr
, sizeof(struct in6_addr
));
6017 static inline struct necp_kernel_socket_policy
*
6018 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
, necp_kernel_policy_result
*return_service_action
, necp_kernel_policy_service
*return_service
, u_int32_t
*return_netagent_array
, size_t netagent_array_count
, proc_t proc
)
6020 struct necp_kernel_socket_policy
*matched_policy
= NULL
;
6021 u_int32_t skip_order
= 0;
6022 u_int32_t skip_session_order
= 0;
6023 u_int32_t route_rule_id_array
[MAX_AGGREGATE_ROUTE_RULES
];
6024 size_t route_rule_id_count
= 0;
6026 size_t netagent_cursor
= 0;
6028 // Pre-process domain for quick matching
6029 struct substring domain_substring
= necp_trim_dots_and_stars(info
->domain
, info
->domain
? strlen(info
->domain
) : 0);
6030 u_int8_t domain_dot_count
= necp_count_dots(domain_substring
.string
, domain_substring
.length
);
6032 if (return_filter
) {
6036 if (return_route_rule_id
) {
6037 *return_route_rule_id
= 0;
6040 if (return_service_action
) {
6041 *return_service_action
= 0;
6044 if (return_service
) {
6045 return_service
->identifier
= 0;
6046 return_service
->data
= 0;
6049 if (policy_search_array
!= NULL
) {
6050 for (i
= 0; policy_search_array
[i
] != NULL
; i
++) {
6051 if (necp_drop_all_order
!= 0 && policy_search_array
[i
]->session_order
>= necp_drop_all_order
) {
6052 // We've hit a drop all rule
6055 if (skip_session_order
&& policy_search_array
[i
]->session_order
>= skip_session_order
) {
6058 skip_session_order
= 0;
6061 if (policy_search_array
[i
]->order
< skip_order
) {
6067 skip_session_order
= 0;
6069 } else if (skip_session_order
) {
6073 if (necp_socket_check_policy(policy_search_array
[i
], info
->application_id
, info
->real_application_id
, info
->cred_result
, info
->account_id
, domain_substring
, domain_dot_count
, info
->pid
, info
->uid
, info
->bound_interface_index
, info
->traffic_class
, info
->protocol
, &info
->local_addr
, &info
->remote_addr
, proc
)) {
6074 if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER
) {
6075 if (return_filter
&& *return_filter
== 0) {
6076 *return_filter
= policy_search_array
[i
]->result_parameter
.filter_control_unit
;
6077 if (necp_debug
> 1) {
6078 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
);
6082 } else if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_ROUTE_RULES
) {
6083 if (return_route_rule_id
&& route_rule_id_count
< MAX_AGGREGATE_ROUTE_RULES
) {
6084 route_rule_id_array
[route_rule_id_count
++] = policy_search_array
[i
]->result_parameter
.route_rule_id
;
6085 if (necp_debug
> 1) {
6086 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
);
6090 } else if (necp_kernel_socket_result_is_trigger_service_type(policy_search_array
[i
])) {
6091 if (return_service_action
&& *return_service_action
== 0) {
6092 *return_service_action
= policy_search_array
[i
]->result
;
6093 if (necp_debug
> 1) {
6094 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
);
6097 if (return_service
&& return_service
->identifier
== 0) {
6098 return_service
->identifier
= policy_search_array
[i
]->result_parameter
.service
.identifier
;
6099 return_service
->data
= policy_search_array
[i
]->result_parameter
.service
.data
;
6100 if (necp_debug
> 1) {
6101 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
);
6105 } else if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_USE_NETAGENT
) {
6106 if (return_netagent_array
!= NULL
&&
6107 netagent_cursor
< netagent_array_count
) {
6108 return_netagent_array
[netagent_cursor
] = policy_search_array
[i
]->result_parameter
.netagent_id
;
6110 if (necp_debug
> 1) {
6111 NECPLOG(LOG_DEBUG
, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) Use Netagent %d", info
->application_id
, info
->real_application_id
, info
->bound_interface_index
, info
->protocol
, policy_search_array
[i
]->result_parameter
.netagent_id
);
6117 // Matched policy is a skip. Do skip and continue.
6118 if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
6119 skip_order
= policy_search_array
[i
]->result_parameter
.skip_policy_order
;
6120 skip_session_order
= policy_search_array
[i
]->session_order
+ 1;
6124 // Passed all tests, found a match
6125 matched_policy
= policy_search_array
[i
];
6131 if (route_rule_id_count
== 1) {
6132 *return_route_rule_id
= route_rule_id_array
[0];
6133 } else if (route_rule_id_count
> 1) {
6134 *return_route_rule_id
= necp_create_aggregate_route_rule(route_rule_id_array
);
6136 return (matched_policy
);
6140 necp_socket_uses_interface(struct inpcb
*inp
, u_int32_t interface_index
)
6142 bool found_match
= FALSE
;
6144 ifaddr_t
*addresses
= NULL
;
6145 union necp_sockaddr_union address_storage
;
6147 int family
= AF_INET
;
6148 ifnet_t interface
= ifindex2ifnet
[interface_index
];
6150 if (inp
== NULL
|| interface
== NULL
) {
6154 if (inp
->inp_vflag
& INP_IPV4
) {
6156 } else if (inp
->inp_vflag
& INP_IPV6
) {
6160 result
= ifnet_get_address_list_family(interface
, &addresses
, family
);
6162 NECPLOG(LOG_ERR
, "Failed to get address list for %s%d", ifnet_name(interface
), ifnet_unit(interface
));
6166 for (i
= 0; addresses
[i
] != NULL
; i
++) {
6167 if (ifaddr_address(addresses
[i
], &address_storage
.sa
, sizeof(address_storage
)) == 0) {
6168 if (family
== AF_INET
) {
6169 if (memcmp(&address_storage
.sin
.sin_addr
, &inp
->inp_laddr
, sizeof(inp
->inp_laddr
)) == 0) {
6173 } else if (family
== AF_INET6
) {
6174 if (memcmp(&address_storage
.sin6
.sin6_addr
, &inp
->in6p_laddr
, sizeof(inp
->in6p_laddr
)) == 0) {
6183 ifnet_free_address_list(addresses
);
6185 return (found_match
);
6189 necp_socket_is_connected(struct inpcb
*inp
)
6191 return (inp
->inp_socket
->so_state
& (SS_ISCONNECTING
| SS_ISCONNECTED
| SS_ISDISCONNECTING
));
6195 necp_socket_bypass(struct sockaddr
*override_local_addr
, struct sockaddr
*override_remote_addr
, struct inpcb
*inp
)
6198 if (necp_pass_loopback
> 0 && necp_is_loopback(override_local_addr
, override_remote_addr
, inp
, NULL
)) {
6200 } else if (necp_is_intcoproc(inp
, NULL
)) {
6207 necp_kernel_policy_id
6208 necp_socket_find_policy_match(struct inpcb
*inp
, struct sockaddr
*override_local_addr
, struct sockaddr
*override_remote_addr
, u_int32_t override_bound_interface
)
6210 struct socket
*so
= NULL
;
6211 necp_kernel_policy_filter filter_control_unit
= 0;
6212 u_int32_t route_rule_id
= 0;
6213 struct necp_kernel_socket_policy
*matched_policy
= NULL
;
6214 necp_kernel_policy_id matched_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
6215 necp_kernel_policy_result service_action
= 0;
6216 necp_kernel_policy_service service
= { 0, 0 };
6218 u_int32_t netagent_ids
[NECP_MAX_NETAGENTS
];
6219 memset(&netagent_ids
, 0, sizeof(netagent_ids
));
6220 int netagent_cursor
;
6222 struct necp_socket_info info
;
6225 return (NECP_KERNEL_POLICY_ID_NONE
);
6228 // Ignore invalid addresses
6229 if (override_local_addr
!= NULL
&&
6230 !necp_address_is_valid(override_local_addr
)) {
6231 override_local_addr
= NULL
;
6233 if (override_remote_addr
!= NULL
&&
6234 !necp_address_is_valid(override_remote_addr
)) {
6235 override_remote_addr
= NULL
;
6238 so
= inp
->inp_socket
;
6240 // Don't lock. Possible race condition, but we don't want the performance hit.
6241 if (necp_kernel_socket_policies_count
== 0 ||
6242 (!(inp
->inp_flags2
& INP2_WANT_APP_POLICY
) && necp_kernel_socket_policies_non_app_count
== 0)) {
6243 if (necp_drop_all_order
> 0) {
6244 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6245 inp
->inp_policyresult
.policy_gencount
= 0;
6246 inp
->inp_policyresult
.app_id
= 0;
6247 inp
->inp_policyresult
.flowhash
= 0;
6248 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
6249 inp
->inp_policyresult
.results
.route_rule_id
= 0;
6250 if (necp_socket_bypass(override_local_addr
, override_remote_addr
, inp
)) {
6251 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_PASS
;
6253 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6256 return (NECP_KERNEL_POLICY_ID_NONE
);
6259 // Check for loopback exception
6260 if (necp_socket_bypass(override_local_addr
, override_remote_addr
, inp
)) {
6261 // Mark socket as a pass
6262 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6263 inp
->inp_policyresult
.policy_gencount
= 0;
6264 inp
->inp_policyresult
.app_id
= 0;
6265 inp
->inp_policyresult
.flowhash
= 0;
6266 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
6267 inp
->inp_policyresult
.results
.route_rule_id
= 0;
6268 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_PASS
;
6269 return (NECP_KERNEL_POLICY_ID_NONE
);
6273 lck_rw_lock_shared(&necp_kernel_policy_lock
);
6275 necp_socket_fillout_info_locked(inp
, override_local_addr
, override_remote_addr
, override_bound_interface
, &info
);
6276 inp
->inp_policyresult
.app_id
= info
.application_id
;
6279 u_int32_t flowhash
= necp_socket_calc_flowhash_locked(&info
);
6280 if (inp
->inp_policyresult
.policy_id
!= NECP_KERNEL_POLICY_ID_NONE
&&
6281 inp
->inp_policyresult
.policy_gencount
== necp_kernel_socket_policies_gencount
&&
6282 inp
->inp_policyresult
.flowhash
== flowhash
) {
6283 // If already matched this socket on this generation of table, skip
6286 lck_rw_done(&necp_kernel_policy_lock
);
6288 return (inp
->inp_policyresult
.policy_id
);
6291 // Match socket to policy
6292 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
, &service_action
, &service
, netagent_ids
, NECP_MAX_NETAGENTS
, current_proc());
6293 // If the socket matched a scoped service policy, mark as Drop if not registered.
6294 // This covers the cases in which a service is required (on demand) but hasn't started yet.
6295 if ((service_action
== NECP_KERNEL_POLICY_RESULT_TRIGGER_SCOPED
||
6296 service_action
== NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED
) &&
6297 service
.identifier
!= 0 &&
6298 service
.identifier
!= NECP_NULL_SERVICE_ID
) {
6299 bool service_is_registered
= FALSE
;
6300 struct necp_service_registration
*service_registration
= NULL
;
6301 LIST_FOREACH(service_registration
, &necp_registered_service_list
, kernel_chain
) {
6302 if (service
.identifier
== service_registration
->service_id
) {
6303 service_is_registered
= TRUE
;
6307 if (!service_is_registered
) {
6308 // Mark socket as a drop if service is not registered
6309 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6310 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
6311 inp
->inp_policyresult
.flowhash
= flowhash
;
6312 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
6313 inp
->inp_policyresult
.results
.route_rule_id
= 0;
6314 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6316 if (necp_debug
> 1) {
6317 NECPLOG(LOG_DEBUG
, "Socket Policy: (BoundInterface %d Proto %d) Dropping packet because service is not registered", info
.bound_interface_index
, info
.protocol
);
6321 lck_rw_done(&necp_kernel_policy_lock
);
6322 return (NECP_KERNEL_POLICY_ID_NONE
);
6326 for (netagent_cursor
= 0; netagent_cursor
< NECP_MAX_NETAGENTS
; netagent_cursor
++) {
6327 struct necp_uuid_id_mapping
*mapping
= NULL
;
6328 u_int32_t netagent_id
= netagent_ids
[netagent_cursor
];
6329 if (netagent_id
== 0) {
6332 mapping
= necp_uuid_lookup_uuid_with_service_id_locked(netagent_id
);
6333 if (mapping
!= NULL
) {
6334 u_int32_t agent_flags
= 0;
6335 agent_flags
= netagent_get_flags(mapping
->uuid
);
6336 if (agent_flags
& NETAGENT_FLAG_REGISTERED
) {
6337 if (agent_flags
& NETAGENT_FLAG_ACTIVE
) {
6339 } else if ((agent_flags
& NETAGENT_FLAG_VOLUNTARY
) == 0) {
6340 if (agent_flags
& NETAGENT_FLAG_KERNEL_ACTIVATED
) {
6341 int trigger_error
= 0;
6342 trigger_error
= netagent_kernel_trigger(mapping
->uuid
);
6343 if (necp_debug
> 1) {
6344 NECPLOG(LOG_DEBUG
, "Socket Policy: Triggering inactive agent, error %d", trigger_error
);
6348 // Mark socket as a drop if required agent is not active
6349 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6350 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
6351 inp
->inp_policyresult
.flowhash
= flowhash
;
6352 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
6353 inp
->inp_policyresult
.results
.route_rule_id
= 0;
6354 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6356 if (necp_debug
> 1) {
6357 NECPLOG(LOG_DEBUG
, "Socket Policy: (BoundInterface %d Proto %d) Dropping packet because agent is not active", info
.bound_interface_index
, info
.protocol
);
6361 lck_rw_done(&necp_kernel_policy_lock
);
6362 return (NECP_KERNEL_POLICY_ID_NONE
);
6367 if (matched_policy
) {
6368 matched_policy_id
= matched_policy
->id
;
6369 inp
->inp_policyresult
.policy_id
= matched_policy
->id
;
6370 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
6371 inp
->inp_policyresult
.flowhash
= flowhash
;
6372 inp
->inp_policyresult
.results
.filter_control_unit
= filter_control_unit
;
6373 inp
->inp_policyresult
.results
.route_rule_id
= route_rule_id
;
6374 inp
->inp_policyresult
.results
.result
= matched_policy
->result
;
6375 memcpy(&inp
->inp_policyresult
.results
.result_parameter
, &matched_policy
->result_parameter
, sizeof(matched_policy
->result_parameter
));
6377 if (necp_socket_is_connected(inp
) &&
6378 (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_DROP
||
6379 (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&& !necp_socket_uses_interface(inp
, matched_policy
->result_parameter
.tunnel_interface_index
)))) {
6381 NECPLOG(LOG_DEBUG
, "Marking socket in state %d as defunct", so
->so_state
);
6383 sosetdefunct(current_proc(), so
, SHUTDOWN_SOCKET_LEVEL_NECP
| SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL
, TRUE
);
6384 } else if (necp_socket_is_connected(inp
) &&
6385 matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&&
6386 info
.protocol
== IPPROTO_TCP
) {
6387 // Reset MSS on TCP socket if tunnel policy changes
6388 tcp_mtudisc(inp
, 0);
6391 if (necp_debug
> 1) {
6392 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
);
6394 } else if (necp_drop_all_order
> 0) {
6395 // Mark socket as a drop if set
6396 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6397 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
6398 inp
->inp_policyresult
.flowhash
= flowhash
;
6399 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
6400 inp
->inp_policyresult
.results
.route_rule_id
= 0;
6401 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6403 // Mark non-matching socket so we don't re-check it
6404 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6405 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
6406 inp
->inp_policyresult
.flowhash
= flowhash
;
6407 inp
->inp_policyresult
.results
.filter_control_unit
= filter_control_unit
; // We may have matched a filter, so mark it!
6408 inp
->inp_policyresult
.results
.route_rule_id
= route_rule_id
; // We may have matched a route rule, so mark it!
6409 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_NONE
;
6413 lck_rw_done(&necp_kernel_policy_lock
);
6415 return (matched_policy_id
);
6419 necp_ip_output_check_policy(struct necp_kernel_ip_output_policy
*kernel_policy
, necp_kernel_policy_id socket_policy_id
, u_int32_t bound_interface_index
, u_int32_t last_interface_index
, u_int16_t protocol
, union necp_sockaddr_union
*local
, union necp_sockaddr_union
*remote
)
6421 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) {
6422 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
6423 u_int32_t cond_bound_interface_index
= kernel_policy
->cond_bound_interface
? kernel_policy
->cond_bound_interface
->if_index
: 0;
6424 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
6425 if (bound_interface_index
== cond_bound_interface_index
) {
6426 // No match, matches forbidden interface
6430 if (bound_interface_index
!= cond_bound_interface_index
) {
6431 // No match, does not match required interface
6436 if (bound_interface_index
!= 0) {
6437 // No match, requires a non-bound packet
6443 if (kernel_policy
->condition_mask
== 0) {
6447 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
) {
6448 if (socket_policy_id
!= kernel_policy
->cond_policy_id
) {
6449 // No match, does not match required id
6454 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LAST_INTERFACE
) {
6455 if (last_interface_index
!= kernel_policy
->cond_last_interface_index
) {
6460 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
6461 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
6462 if (protocol
== kernel_policy
->cond_protocol
) {
6463 // No match, matches forbidden protocol
6467 if (protocol
!= kernel_policy
->cond_protocol
) {
6468 // No match, does not match required protocol
6474 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
6475 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
6476 bool inRange
= necp_is_addr_in_range((struct sockaddr
*)local
, (struct sockaddr
*)&kernel_policy
->cond_local_start
, (struct sockaddr
*)&kernel_policy
->cond_local_end
);
6477 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
6486 } else if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
6487 bool inSubnet
= necp_is_addr_in_subnet((struct sockaddr
*)local
, (struct sockaddr
*)&kernel_policy
->cond_local_start
, kernel_policy
->cond_local_prefix
);
6488 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
6500 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
6501 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
6502 bool inRange
= necp_is_addr_in_range((struct sockaddr
*)remote
, (struct sockaddr
*)&kernel_policy
->cond_remote_start
, (struct sockaddr
*)&kernel_policy
->cond_remote_end
);
6503 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
6512 } else if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
6513 bool inSubnet
= necp_is_addr_in_subnet((struct sockaddr
*)remote
, (struct sockaddr
*)&kernel_policy
->cond_remote_start
, kernel_policy
->cond_remote_prefix
);
6514 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
6529 static inline struct necp_kernel_ip_output_policy
*
6530 necp_ip_output_find_policy_match_locked(necp_kernel_policy_id socket_policy_id
, u_int32_t bound_interface_index
, u_int32_t last_interface_index
, u_int16_t protocol
, union necp_sockaddr_union
*local_addr
, union necp_sockaddr_union
*remote_addr
)
6532 u_int32_t skip_order
= 0;
6533 u_int32_t skip_session_order
= 0;
6535 struct necp_kernel_ip_output_policy
*matched_policy
= NULL
;
6536 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
)];
6537 if (policy_search_array
!= NULL
) {
6538 for (i
= 0; policy_search_array
[i
] != NULL
; i
++) {
6539 if (necp_drop_all_order
!= 0 && policy_search_array
[i
]->session_order
>= necp_drop_all_order
) {
6540 // We've hit a drop all rule
6543 if (skip_session_order
&& policy_search_array
[i
]->session_order
>= skip_session_order
) {
6546 skip_session_order
= 0;
6549 if (policy_search_array
[i
]->order
< skip_order
) {
6555 skip_session_order
= 0;
6557 } else if (skip_session_order
) {
6561 if (necp_ip_output_check_policy(policy_search_array
[i
], socket_policy_id
, bound_interface_index
, last_interface_index
, protocol
, local_addr
, remote_addr
)) {
6562 // Passed all tests, found a match
6563 matched_policy
= policy_search_array
[i
];
6565 if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
6566 skip_order
= policy_search_array
[i
]->result_parameter
.skip_policy_order
;
6567 skip_session_order
= policy_search_array
[i
]->session_order
+ 1;
6576 return (matched_policy
);
6580 necp_output_bypass(struct mbuf
*packet
)
6582 if (necp_pass_loopback
> 0 && necp_is_loopback(NULL
, NULL
, NULL
, packet
)) {
6585 if (necp_pass_keepalives
> 0 && necp_get_is_keepalive_from_packet(packet
)) {
6588 if (necp_is_intcoproc(NULL
, packet
)) {
6594 necp_kernel_policy_id
6595 necp_ip_output_find_policy_match(struct mbuf
*packet
, int flags
, struct ip_out_args
*ipoa
, necp_kernel_policy_result
*result
, necp_kernel_policy_result_parameter
*result_parameter
)
6597 struct ip
*ip
= NULL
;
6598 int hlen
= sizeof(struct ip
);
6599 necp_kernel_policy_id socket_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
6600 necp_kernel_policy_id matched_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
6601 struct necp_kernel_ip_output_policy
*matched_policy
= NULL
;
6602 u_int16_t protocol
= 0;
6603 u_int32_t bound_interface_index
= 0;
6604 u_int32_t last_interface_index
= 0;
6605 union necp_sockaddr_union local_addr
;
6606 union necp_sockaddr_union remote_addr
;
6612 if (result_parameter
) {
6613 memset(result_parameter
, 0, sizeof(*result_parameter
));
6616 if (packet
== NULL
) {
6617 return (NECP_KERNEL_POLICY_ID_NONE
);
6620 socket_policy_id
= necp_get_policy_id_from_packet(packet
);
6622 // Exit early for an empty list
6623 // Don't lock. Possible race condition, but we don't want the performance hit.
6624 if (necp_kernel_ip_output_policies_count
== 0 ||
6625 ((socket_policy_id
== NECP_KERNEL_POLICY_ID_NONE
) && necp_kernel_ip_output_policies_non_id_count
== 0)) {
6626 if (necp_drop_all_order
> 0) {
6627 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6629 if (necp_output_bypass(packet
)) {
6630 *result
= NECP_KERNEL_POLICY_RESULT_PASS
;
6632 *result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6637 return (matched_policy_id
);
6640 // Check for loopback exception
6641 if (necp_output_bypass(packet
)) {
6642 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6644 *result
= NECP_KERNEL_POLICY_RESULT_PASS
;
6646 return (matched_policy_id
);
6649 last_interface_index
= necp_get_last_interface_index_from_packet(packet
);
6651 // Process packet to get relevant fields
6652 ip
= mtod(packet
, struct ip
*);
6654 hlen
= _IP_VHL_HL(ip
->ip_vhl
) << 2;
6656 hlen
= ip
->ip_hl
<< 2;
6659 protocol
= ip
->ip_p
;
6661 if ((flags
& IP_OUTARGS
) && (ipoa
!= NULL
) &&
6662 (ipoa
->ipoa_flags
& IPOAF_BOUND_IF
) &&
6663 ipoa
->ipoa_boundif
!= IFSCOPE_NONE
) {
6664 bound_interface_index
= ipoa
->ipoa_boundif
;
6667 local_addr
.sin
.sin_family
= AF_INET
;
6668 local_addr
.sin
.sin_len
= sizeof(struct sockaddr_in
);
6669 memcpy(&local_addr
.sin
.sin_addr
, &ip
->ip_src
, sizeof(ip
->ip_src
));
6671 remote_addr
.sin
.sin_family
= AF_INET
;
6672 remote_addr
.sin
.sin_len
= sizeof(struct sockaddr_in
);
6673 memcpy(&((struct sockaddr_in
*)&remote_addr
)->sin_addr
, &ip
->ip_dst
, sizeof(ip
->ip_dst
));
6678 if ((int)(hlen
+ sizeof(th
)) <= packet
->m_pkthdr
.len
) {
6679 m_copydata(packet
, hlen
, sizeof(th
), (u_int8_t
*)&th
);
6680 ((struct sockaddr_in
*)&local_addr
)->sin_port
= th
.th_sport
;
6681 ((struct sockaddr_in
*)&remote_addr
)->sin_port
= th
.th_dport
;
6687 if ((int)(hlen
+ sizeof(uh
)) <= packet
->m_pkthdr
.len
) {
6688 m_copydata(packet
, hlen
, sizeof(uh
), (u_int8_t
*)&uh
);
6689 ((struct sockaddr_in
*)&local_addr
)->sin_port
= uh
.uh_sport
;
6690 ((struct sockaddr_in
*)&remote_addr
)->sin_port
= uh
.uh_dport
;
6695 ((struct sockaddr_in
*)&local_addr
)->sin_port
= 0;
6696 ((struct sockaddr_in
*)&remote_addr
)->sin_port
= 0;
6701 // Match packet to policy
6702 lck_rw_lock_shared(&necp_kernel_policy_lock
);
6703 matched_policy
= necp_ip_output_find_policy_match_locked(socket_policy_id
, bound_interface_index
, last_interface_index
, protocol
, &local_addr
, &remote_addr
);
6704 if (matched_policy
) {
6705 matched_policy_id
= matched_policy
->id
;
6707 *result
= matched_policy
->result
;
6710 if (result_parameter
) {
6711 memcpy(result_parameter
, &matched_policy
->result_parameter
, sizeof(matched_policy
->result_parameter
));
6714 if (necp_debug
> 1) {
6715 NECPLOG(LOG_DEBUG
, "IP Output: (ID %d BoundInterface %d LastInterface %d Proto %d) Policy %d Result %d Parameter %d", socket_policy_id
, bound_interface_index
, last_interface_index
, protocol
, matched_policy
->id
, matched_policy
->result
, matched_policy
->result_parameter
.tunnel_interface_index
);
6717 } else if (necp_drop_all_order
> 0) {
6718 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6720 *result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6724 lck_rw_done(&necp_kernel_policy_lock
);
6726 return (matched_policy_id
);
6729 necp_kernel_policy_id
6730 necp_ip6_output_find_policy_match(struct mbuf
*packet
, int flags
, struct ip6_out_args
*ip6oa
, necp_kernel_policy_result
*result
, necp_kernel_policy_result_parameter
*result_parameter
)
6732 struct ip6_hdr
*ip6
= NULL
;
6735 necp_kernel_policy_id socket_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
6736 necp_kernel_policy_id matched_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
6737 struct necp_kernel_ip_output_policy
*matched_policy
= NULL
;
6738 u_int16_t protocol
= 0;
6739 u_int32_t bound_interface_index
= 0;
6740 u_int32_t last_interface_index
= 0;
6741 union necp_sockaddr_union local_addr
;
6742 union necp_sockaddr_union remote_addr
;
6748 if (result_parameter
) {
6749 memset(result_parameter
, 0, sizeof(*result_parameter
));
6752 if (packet
== NULL
) {
6753 return (NECP_KERNEL_POLICY_ID_NONE
);
6756 socket_policy_id
= necp_get_policy_id_from_packet(packet
);
6758 // Exit early for an empty list
6759 // Don't lock. Possible race condition, but we don't want the performance hit.
6760 if (necp_kernel_ip_output_policies_count
== 0 ||
6761 ((socket_policy_id
== NECP_KERNEL_POLICY_ID_NONE
) && necp_kernel_ip_output_policies_non_id_count
== 0)) {
6762 if (necp_drop_all_order
> 0) {
6763 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6765 if (necp_output_bypass(packet
)) {
6766 *result
= NECP_KERNEL_POLICY_RESULT_PASS
;
6768 *result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6773 return (matched_policy_id
);
6776 // Check for loopback exception
6777 if (necp_output_bypass(packet
)) {
6778 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6780 *result
= NECP_KERNEL_POLICY_RESULT_PASS
;
6782 return (matched_policy_id
);
6785 last_interface_index
= necp_get_last_interface_index_from_packet(packet
);
6787 // Process packet to get relevant fields
6788 ip6
= mtod(packet
, struct ip6_hdr
*);
6790 if ((flags
& IPV6_OUTARGS
) && (ip6oa
!= NULL
) &&
6791 (ip6oa
->ip6oa_flags
& IP6OAF_BOUND_IF
) &&
6792 ip6oa
->ip6oa_boundif
!= IFSCOPE_NONE
) {
6793 bound_interface_index
= ip6oa
->ip6oa_boundif
;
6796 ((struct sockaddr_in6
*)&local_addr
)->sin6_family
= AF_INET6
;
6797 ((struct sockaddr_in6
*)&local_addr
)->sin6_len
= sizeof(struct sockaddr_in6
);
6798 memcpy(&((struct sockaddr_in6
*)&local_addr
)->sin6_addr
, &ip6
->ip6_src
, sizeof(ip6
->ip6_src
));
6800 ((struct sockaddr_in6
*)&remote_addr
)->sin6_family
= AF_INET6
;
6801 ((struct sockaddr_in6
*)&remote_addr
)->sin6_len
= sizeof(struct sockaddr_in6
);
6802 memcpy(&((struct sockaddr_in6
*)&remote_addr
)->sin6_addr
, &ip6
->ip6_dst
, sizeof(ip6
->ip6_dst
));
6804 offset
= ip6_lasthdr(packet
, 0, IPPROTO_IPV6
, &next
);
6805 if (offset
>= 0 && packet
->m_pkthdr
.len
>= offset
) {
6810 if ((int)(offset
+ sizeof(th
)) <= packet
->m_pkthdr
.len
) {
6811 m_copydata(packet
, offset
, sizeof(th
), (u_int8_t
*)&th
);
6812 ((struct sockaddr_in6
*)&local_addr
)->sin6_port
= th
.th_sport
;
6813 ((struct sockaddr_in6
*)&remote_addr
)->sin6_port
= th
.th_dport
;
6819 if ((int)(offset
+ sizeof(uh
)) <= packet
->m_pkthdr
.len
) {
6820 m_copydata(packet
, offset
, sizeof(uh
), (u_int8_t
*)&uh
);
6821 ((struct sockaddr_in6
*)&local_addr
)->sin6_port
= uh
.uh_sport
;
6822 ((struct sockaddr_in6
*)&remote_addr
)->sin6_port
= uh
.uh_dport
;
6827 ((struct sockaddr_in6
*)&local_addr
)->sin6_port
= 0;
6828 ((struct sockaddr_in6
*)&remote_addr
)->sin6_port
= 0;
6834 // Match packet to policy
6835 lck_rw_lock_shared(&necp_kernel_policy_lock
);
6836 matched_policy
= necp_ip_output_find_policy_match_locked(socket_policy_id
, bound_interface_index
, last_interface_index
, protocol
, &local_addr
, &remote_addr
);
6837 if (matched_policy
) {
6838 matched_policy_id
= matched_policy
->id
;
6840 *result
= matched_policy
->result
;
6843 if (result_parameter
) {
6844 memcpy(result_parameter
, &matched_policy
->result_parameter
, sizeof(matched_policy
->result_parameter
));
6847 if (necp_debug
> 1) {
6848 NECPLOG(LOG_DEBUG
, "IP6 Output: (ID %d BoundInterface %d LastInterface %d Proto %d) Policy %d Result %d Parameter %d", socket_policy_id
, bound_interface_index
, last_interface_index
, protocol
, matched_policy
->id
, matched_policy
->result
, matched_policy
->result_parameter
.tunnel_interface_index
);
6850 } else if (necp_drop_all_order
> 0) {
6851 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6853 *result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6857 lck_rw_done(&necp_kernel_policy_lock
);
6859 return (matched_policy_id
);
6864 necp_is_addr_in_range(struct sockaddr
*addr
, struct sockaddr
*range_start
, struct sockaddr
*range_end
)
6868 if (addr
== NULL
|| range_start
== NULL
|| range_end
== NULL
) {
6872 /* Must be greater than or equal to start */
6873 cmp
= necp_addr_compare(addr
, range_start
, 1);
6874 if (cmp
!= 0 && cmp
!= 1) {
6878 /* Must be less than or equal to end */
6879 cmp
= necp_addr_compare(addr
, range_end
, 1);
6880 if (cmp
!= 0 && cmp
!= -1) {
6888 necp_is_range_in_range(struct sockaddr
*inner_range_start
, struct sockaddr
*inner_range_end
, struct sockaddr
*range_start
, struct sockaddr
*range_end
)
6892 if (inner_range_start
== NULL
|| inner_range_end
== NULL
|| range_start
== NULL
|| range_end
== NULL
) {
6896 /* Must be greater than or equal to start */
6897 cmp
= necp_addr_compare(inner_range_start
, range_start
, 1);
6898 if (cmp
!= 0 && cmp
!= 1) {
6902 /* Must be less than or equal to end */
6903 cmp
= necp_addr_compare(inner_range_end
, range_end
, 1);
6904 if (cmp
!= 0 && cmp
!= -1) {
6912 necp_is_addr_in_subnet(struct sockaddr
*addr
, struct sockaddr
*subnet_addr
, u_int8_t subnet_prefix
)
6914 if (addr
== NULL
|| subnet_addr
== NULL
) {
6918 if (addr
->sa_family
!= subnet_addr
->sa_family
|| addr
->sa_len
!= subnet_addr
->sa_len
) {
6922 switch (addr
->sa_family
) {
6924 if (satosin(subnet_addr
)->sin_port
!= 0 &&
6925 satosin(addr
)->sin_port
!= satosin(subnet_addr
)->sin_port
) {
6928 return (necp_buffer_compare_with_bit_prefix((u_int8_t
*)&satosin(addr
)->sin_addr
, (u_int8_t
*)&satosin(subnet_addr
)->sin_addr
, subnet_prefix
));
6931 if (satosin6(subnet_addr
)->sin6_port
!= 0 &&
6932 satosin6(addr
)->sin6_port
!= satosin6(subnet_addr
)->sin6_port
) {
6935 if (satosin6(addr
)->sin6_scope_id
&&
6936 satosin6(subnet_addr
)->sin6_scope_id
&&
6937 satosin6(addr
)->sin6_scope_id
!= satosin6(subnet_addr
)->sin6_scope_id
) {
6940 return (necp_buffer_compare_with_bit_prefix((u_int8_t
*)&satosin6(addr
)->sin6_addr
, (u_int8_t
*)&satosin6(subnet_addr
)->sin6_addr
, subnet_prefix
));
6955 * 2: Not comparable or error
6958 necp_addr_compare(struct sockaddr
*sa1
, struct sockaddr
*sa2
, int check_port
)
6961 int port_result
= 0;
6963 if (sa1
->sa_family
!= sa2
->sa_family
|| sa1
->sa_len
!= sa2
->sa_len
) {
6967 if (sa1
->sa_len
== 0) {
6971 switch (sa1
->sa_family
) {
6973 if (sa1
->sa_len
!= sizeof(struct sockaddr_in
)) {
6977 result
= memcmp(&satosin(sa1
)->sin_addr
.s_addr
, &satosin(sa2
)->sin_addr
.s_addr
, sizeof(satosin(sa1
)->sin_addr
.s_addr
));
6980 if (satosin(sa1
)->sin_port
< satosin(sa2
)->sin_port
) {
6982 } else if (satosin(sa1
)->sin_port
> satosin(sa2
)->sin_port
) {
6987 result
= port_result
;
6988 } else if ((result
> 0 && port_result
< 0) || (result
< 0 && port_result
> 0)) {
6996 if (sa1
->sa_len
!= sizeof(struct sockaddr_in6
)) {
7000 if (satosin6(sa1
)->sin6_scope_id
!= satosin6(sa2
)->sin6_scope_id
) {
7004 result
= memcmp(&satosin6(sa1
)->sin6_addr
.s6_addr
[0], &satosin6(sa2
)->sin6_addr
.s6_addr
[0], sizeof(struct in6_addr
));
7007 if (satosin6(sa1
)->sin6_port
< satosin6(sa2
)->sin6_port
) {
7009 } else if (satosin6(sa1
)->sin6_port
> satosin6(sa2
)->sin6_port
) {
7014 result
= port_result
;
7015 } else if ((result
> 0 && port_result
< 0) || (result
< 0 && port_result
> 0)) {
7023 result
= memcmp(sa1
, sa2
, sa1
->sa_len
);
7030 } else if (result
> 0) {
7038 necp_buffer_compare_with_bit_prefix(u_int8_t
*p1
, u_int8_t
*p2
, u_int32_t bits
)
7042 /* Handle null pointers */
7043 if (p1
== NULL
|| p2
== NULL
) {
7048 if (*p1
++ != *p2
++) {
7055 mask
= ~((1<<(8-bits
))-1);
7056 if ((*p1
& mask
) != (*p2
& mask
)) {
7064 necp_socket_update_qos_marking_inner(struct ifnet
*ifp
, u_int32_t route_rule_id
)
7066 bool qos_marking
= FALSE
;
7067 int exception_index
= 0;
7068 struct necp_route_rule
*route_rule
= NULL
;
7070 route_rule
= necp_lookup_route_rule_locked(&necp_route_rules
, route_rule_id
);
7071 if (route_rule
== NULL
) {
7072 qos_marking
= FALSE
;
7076 qos_marking
= (route_rule
->default_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? TRUE
: FALSE
;
7082 for (exception_index
= 0; exception_index
< MAX_ROUTE_RULE_INTERFACES
; exception_index
++) {
7083 if (route_rule
->exception_if_indices
[exception_index
] == 0) {
7086 if (route_rule
->exception_if_actions
[exception_index
] != NECP_ROUTE_RULE_QOS_MARKING
) {
7089 if (route_rule
->exception_if_indices
[exception_index
] == ifp
->if_index
) {
7091 if (necp_debug
> 2) {
7092 NECPLOG(LOG_DEBUG
, "QoS Marking : Interface match %d for Rule %d Allowed %d",
7093 route_rule
->exception_if_indices
[exception_index
], route_rule_id
, qos_marking
);
7099 if ((route_rule
->cellular_action
== NECP_ROUTE_RULE_QOS_MARKING
&& IFNET_IS_CELLULAR(ifp
)) ||
7100 (route_rule
->wifi_action
== NECP_ROUTE_RULE_QOS_MARKING
&& IFNET_IS_WIFI(ifp
)) ||
7101 (route_rule
->wired_action
== NECP_ROUTE_RULE_QOS_MARKING
&& IFNET_IS_WIRED(ifp
)) ||
7102 (route_rule
->expensive_action
== NECP_ROUTE_RULE_QOS_MARKING
&& IFNET_IS_EXPENSIVE(ifp
))) {
7104 if (necp_debug
> 2) {
7105 NECPLOG(LOG_DEBUG
, "QoS Marking: C:%d WF:%d W:%d E:%d for Rule %d Allowed %d",
7106 route_rule
->cellular_action
, route_rule
->wifi_action
, route_rule
->wired_action
,
7107 route_rule
->expensive_action
, route_rule_id
, qos_marking
);
7112 if (necp_debug
> 1) {
7113 NECPLOG(LOG_DEBUG
, "QoS Marking: Rule %d ifp %s Allowed %d",
7114 route_rule_id
, ifp
? ifp
->if_xname
: "", qos_marking
);
7116 return (qos_marking
);
7120 necp_socket_update_qos_marking(struct inpcb
*inp
, struct rtentry
*route
, struct ifnet
*interface
, u_int32_t route_rule_id
)
7122 bool qos_marking
= FALSE
;
7123 struct ifnet
*ifp
= interface
= NULL
;
7125 ASSERT(net_qos_policy_restricted
!= 0);
7127 if (inp
->inp_socket
== NULL
) {
7130 if ((inp
->inp_socket
->so_flags1
& SOF1_QOSMARKING_POLICY_OVERRIDE
)) {
7134 * This is racy but we do not need the performance hit of taking necp_kernel_policy_lock
7136 if (inp
->inp_policyresult
.results
.qos_marking_gencount
== necp_kernel_socket_policies_gencount
) {
7140 lck_rw_lock_shared(&necp_kernel_policy_lock
);
7142 if (ifp
== NULL
&& route
!= NULL
) {
7143 ifp
= route
->rt_ifp
;
7146 * By default, until we have a interface, do not mark and reevaluate the Qos marking policy
7148 if (ifp
== NULL
|| route_rule_id
== 0) {
7149 qos_marking
= FALSE
;
7153 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id
)) {
7154 struct necp_aggregate_route_rule
*aggregate_route_rule
= necp_lookup_aggregate_route_rule_locked(route_rule_id
);
7155 if (aggregate_route_rule
!= NULL
) {
7157 for (index
= 0; index
< MAX_AGGREGATE_ROUTE_RULES
; index
++) {
7158 u_int32_t sub_route_rule_id
= aggregate_route_rule
->rule_ids
[index
];
7159 if (sub_route_rule_id
== 0) {
7162 qos_marking
= necp_socket_update_qos_marking_inner(ifp
, sub_route_rule_id
);
7163 if (qos_marking
== TRUE
) {
7169 qos_marking
= necp_socket_update_qos_marking_inner(ifp
, route_rule_id
);
7172 * Now that we have an interface we remember the gencount
7174 inp
->inp_policyresult
.results
.qos_marking_gencount
= necp_kernel_socket_policies_gencount
;
7177 lck_rw_done(&necp_kernel_policy_lock
);
7179 if (qos_marking
== TRUE
) {
7180 inp
->inp_socket
->so_flags1
|= SOF1_QOSMARKING_ALLOWED
;
7182 inp
->inp_socket
->so_flags1
&= ~SOF1_QOSMARKING_ALLOWED
;
7187 necp_route_is_allowed_inner(struct rtentry
*route
, struct ifnet
*ifp
, u_int32_t route_rule_id
, u_int32_t
*interface_type_denied
)
7189 bool default_is_allowed
= TRUE
;
7190 u_int8_t type_aggregate_action
= NECP_ROUTE_RULE_NONE
;
7191 int exception_index
= 0;
7192 struct ifnet
*delegated_ifp
= NULL
;
7193 struct necp_route_rule
*route_rule
= NULL
;
7195 route_rule
= necp_lookup_route_rule_locked(&necp_route_rules
, route_rule_id
);
7196 if (route_rule
== NULL
) {
7200 default_is_allowed
= (route_rule
->default_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? FALSE
: TRUE
;
7202 ifp
= route
->rt_ifp
;
7205 if (necp_debug
> 1 && !default_is_allowed
) {
7206 NECPLOG(LOG_DEBUG
, "Route Allowed: No interface for route, using default for Rule %d Allowed %d", route_rule_id
, default_is_allowed
);
7208 return (default_is_allowed
);
7211 delegated_ifp
= ifp
->if_delegated
.ifp
;
7212 for (exception_index
= 0; exception_index
< MAX_ROUTE_RULE_INTERFACES
; exception_index
++) {
7213 if (route_rule
->exception_if_indices
[exception_index
] == 0) {
7216 if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->exception_if_actions
[exception_index
]) == FALSE
) {
7219 if (route_rule
->exception_if_indices
[exception_index
] == ifp
->if_index
||
7220 (delegated_ifp
!= NULL
&& route_rule
->exception_if_indices
[exception_index
] == delegated_ifp
->if_index
)) {
7221 if (necp_debug
> 1) {
7222 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
));
7224 return ((route_rule
->exception_if_actions
[exception_index
] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? FALSE
: TRUE
);
7228 if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->cellular_action
) &&
7229 IFNET_IS_CELLULAR(ifp
)) {
7230 if (interface_type_denied
!= NULL
) {
7231 *interface_type_denied
= IFRTYPE_FUNCTIONAL_CELLULAR
;
7233 if (type_aggregate_action
== NECP_ROUTE_RULE_NONE
||
7234 (type_aggregate_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
&&
7235 route_rule
->cellular_action
== NECP_ROUTE_RULE_DENY_INTERFACE
)) {
7236 // Deny wins if there is a conflict
7237 type_aggregate_action
= route_rule
->cellular_action
;
7241 if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->wifi_action
) &&
7242 IFNET_IS_WIFI(ifp
)) {
7243 if (interface_type_denied
!= NULL
) {
7244 *interface_type_denied
= IFRTYPE_FUNCTIONAL_WIFI_INFRA
;
7246 if (type_aggregate_action
== NECP_ROUTE_RULE_NONE
||
7247 (type_aggregate_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
&&
7248 route_rule
->wifi_action
== NECP_ROUTE_RULE_DENY_INTERFACE
)) {
7249 // Deny wins if there is a conflict
7250 type_aggregate_action
= route_rule
->wifi_action
;
7254 if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->wired_action
) &&
7255 IFNET_IS_WIRED(ifp
)) {
7256 if (interface_type_denied
!= NULL
) {
7257 *interface_type_denied
= IFRTYPE_FUNCTIONAL_WIRED
;
7259 if (type_aggregate_action
== NECP_ROUTE_RULE_NONE
||
7260 (type_aggregate_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
&&
7261 route_rule
->wired_action
== NECP_ROUTE_RULE_DENY_INTERFACE
)) {
7262 // Deny wins if there is a conflict
7263 type_aggregate_action
= route_rule
->wired_action
;
7267 if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->expensive_action
) &&
7268 IFNET_IS_EXPENSIVE(ifp
)) {
7269 if (type_aggregate_action
== NECP_ROUTE_RULE_NONE
||
7270 (type_aggregate_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
&&
7271 route_rule
->expensive_action
== NECP_ROUTE_RULE_DENY_INTERFACE
)) {
7272 // Deny wins if there is a conflict
7273 type_aggregate_action
= route_rule
->expensive_action
;
7277 if (type_aggregate_action
!= NECP_ROUTE_RULE_NONE
) {
7278 if (necp_debug
> 1) {
7279 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
));
7281 return ((type_aggregate_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? FALSE
: TRUE
);
7284 if (necp_debug
> 1 && !default_is_allowed
) {
7285 NECPLOG(LOG_DEBUG
, "Route Allowed: Using default for Rule %d Allowed %d", route_rule_id
, default_is_allowed
);
7287 return (default_is_allowed
);
7291 necp_route_is_allowed(struct rtentry
*route
, struct ifnet
*interface
, u_int32_t route_rule_id
, u_int32_t
*interface_type_denied
)
7293 if ((route
== NULL
&& interface
== NULL
) || route_rule_id
== 0) {
7294 if (necp_debug
> 1) {
7295 NECPLOG(LOG_DEBUG
, "Route Allowed: no route or interface, Rule %d Allowed %d", route_rule_id
, TRUE
);
7300 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id
)) {
7301 struct necp_aggregate_route_rule
*aggregate_route_rule
= necp_lookup_aggregate_route_rule_locked(route_rule_id
);
7302 if (aggregate_route_rule
!= NULL
) {
7304 for (index
= 0; index
< MAX_AGGREGATE_ROUTE_RULES
; index
++) {
7305 u_int32_t sub_route_rule_id
= aggregate_route_rule
->rule_ids
[index
];
7306 if (sub_route_rule_id
== 0) {
7309 if (!necp_route_is_allowed_inner(route
, interface
, sub_route_rule_id
, interface_type_denied
)) {
7315 return (necp_route_is_allowed_inner(route
, interface
, route_rule_id
, interface_type_denied
));
7322 necp_packet_is_allowed_over_interface(struct mbuf
*packet
, struct ifnet
*interface
)
7324 bool is_allowed
= TRUE
;
7325 u_int32_t route_rule_id
= necp_get_route_rule_id_from_packet(packet
);
7326 if (route_rule_id
!= 0 &&
7327 interface
!= NULL
) {
7328 lck_rw_lock_shared(&necp_kernel_policy_lock
);
7329 is_allowed
= necp_route_is_allowed(NULL
, interface
, necp_get_route_rule_id_from_packet(packet
), NULL
);
7330 lck_rw_done(&necp_kernel_policy_lock
);
7332 return (is_allowed
);
7336 necp_netagents_allow_traffic(u_int32_t
*netagent_ids
, size_t netagent_id_count
)
7338 size_t netagent_cursor
;
7339 for (netagent_cursor
= 0; netagent_cursor
< netagent_id_count
; netagent_cursor
++) {
7340 struct necp_uuid_id_mapping
*mapping
= NULL
;
7341 u_int32_t netagent_id
= netagent_ids
[netagent_cursor
];
7342 if (netagent_id
== 0) {
7345 mapping
= necp_uuid_lookup_uuid_with_service_id_locked(netagent_id
);
7346 if (mapping
!= NULL
) {
7347 u_int32_t agent_flags
= 0;
7348 agent_flags
= netagent_get_flags(mapping
->uuid
);
7349 if (agent_flags
& NETAGENT_FLAG_REGISTERED
) {
7350 if (agent_flags
& NETAGENT_FLAG_ACTIVE
) {
7352 } else if ((agent_flags
& NETAGENT_FLAG_VOLUNTARY
) == 0) {
7362 necp_socket_is_allowed_to_send_recv_internal(struct inpcb
*inp
, struct sockaddr
*override_local_addr
, struct sockaddr
*override_remote_addr
, ifnet_t interface
, necp_kernel_policy_id
*return_policy_id
, u_int32_t
*return_route_rule_id
)
7364 u_int32_t verifyifindex
= interface
? interface
->if_index
: 0;
7365 bool allowed_to_receive
= TRUE
;
7366 struct necp_socket_info info
;
7367 u_int32_t flowhash
= 0;
7368 necp_kernel_policy_result service_action
= 0;
7369 necp_kernel_policy_service service
= { 0, 0 };
7370 u_int32_t route_rule_id
= 0;
7371 struct rtentry
*route
= NULL
;
7372 u_int32_t interface_type_denied
= IFRTYPE_FUNCTIONAL_UNKNOWN
;
7374 u_int32_t netagent_ids
[NECP_MAX_NETAGENTS
];
7375 memset(&netagent_ids
, 0, sizeof(netagent_ids
));
7377 if (return_policy_id
) {
7378 *return_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
7380 if (return_route_rule_id
) {
7381 *return_route_rule_id
= 0;
7388 route
= inp
->inp_route
.ro_rt
;
7390 // Don't lock. Possible race condition, but we don't want the performance hit.
7391 if (necp_kernel_socket_policies_count
== 0 ||
7392 (!(inp
->inp_flags2
& INP2_WANT_APP_POLICY
) && necp_kernel_socket_policies_non_app_count
== 0)) {
7393 if (necp_drop_all_order
> 0) {
7394 if (necp_socket_bypass(override_local_addr
, override_remote_addr
, inp
)) {
7395 allowed_to_receive
= TRUE
;
7397 allowed_to_receive
= FALSE
;
7403 // If this socket is connected, or we are not taking addresses into account, try to reuse last result
7404 if ((necp_socket_is_connected(inp
) || (override_local_addr
== NULL
&& override_remote_addr
== NULL
)) && inp
->inp_policyresult
.policy_id
!= NECP_KERNEL_POLICY_ID_NONE
) {
7405 bool policies_have_changed
= FALSE
;
7406 bool route_allowed
= TRUE
;
7407 lck_rw_lock_shared(&necp_kernel_policy_lock
);
7408 if (inp
->inp_policyresult
.policy_gencount
!= necp_kernel_socket_policies_gencount
) {
7409 policies_have_changed
= TRUE
;
7411 if (inp
->inp_policyresult
.results
.route_rule_id
!= 0 &&
7412 !necp_route_is_allowed(route
, interface
, inp
->inp_policyresult
.results
.route_rule_id
, &interface_type_denied
)) {
7413 route_allowed
= FALSE
;
7416 lck_rw_done(&necp_kernel_policy_lock
);
7418 if (!policies_have_changed
) {
7419 if (!route_allowed
||
7420 inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_DROP
||
7421 inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
||
7422 (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&& interface
&&
7423 inp
->inp_policyresult
.results
.result_parameter
.tunnel_interface_index
!= verifyifindex
)) {
7424 allowed_to_receive
= FALSE
;
7426 if (return_policy_id
) {
7427 *return_policy_id
= inp
->inp_policyresult
.policy_id
;
7429 if (return_route_rule_id
) {
7430 *return_route_rule_id
= inp
->inp_policyresult
.results
.route_rule_id
;
7437 // Check for loopback exception
7438 if (necp_socket_bypass(override_local_addr
, override_remote_addr
, inp
)) {
7439 allowed_to_receive
= TRUE
;
7443 // Actually calculate policy result
7444 lck_rw_lock_shared(&necp_kernel_policy_lock
);
7445 necp_socket_fillout_info_locked(inp
, override_local_addr
, override_remote_addr
, 0, &info
);
7447 flowhash
= necp_socket_calc_flowhash_locked(&info
);
7448 if (inp
->inp_policyresult
.policy_id
!= NECP_KERNEL_POLICY_ID_NONE
&&
7449 inp
->inp_policyresult
.policy_gencount
== necp_kernel_socket_policies_gencount
&&
7450 inp
->inp_policyresult
.flowhash
== flowhash
) {
7451 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_DROP
||
7452 inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
||
7453 (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&& interface
&&
7454 inp
->inp_policyresult
.results
.result_parameter
.tunnel_interface_index
!= verifyifindex
) ||
7455 (inp
->inp_policyresult
.results
.route_rule_id
!= 0 &&
7456 !necp_route_is_allowed(route
, interface
, inp
->inp_policyresult
.results
.route_rule_id
, &interface_type_denied
))) {
7457 allowed_to_receive
= FALSE
;
7459 if (return_policy_id
) {
7460 *return_policy_id
= inp
->inp_policyresult
.policy_id
;
7462 if (return_route_rule_id
) {
7463 *return_route_rule_id
= inp
->inp_policyresult
.results
.route_rule_id
;
7466 lck_rw_done(&necp_kernel_policy_lock
);
7470 struct necp_kernel_socket_policy
*matched_policy
= necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map
[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info
.application_id
)], &info
, NULL
, &route_rule_id
, &service_action
, &service
, netagent_ids
, NECP_MAX_NETAGENTS
, current_proc());
7471 if (matched_policy
!= NULL
) {
7472 if (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_DROP
||
7473 matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
||
7474 (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&& interface
&&
7475 matched_policy
->result_parameter
.tunnel_interface_index
!= verifyifindex
) ||
7476 ((service_action
== NECP_KERNEL_POLICY_RESULT_TRIGGER_SCOPED
||
7477 service_action
== NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED
) &&
7478 service
.identifier
!= 0 && service
.identifier
!= NECP_NULL_SERVICE_ID
) ||
7479 (route_rule_id
!= 0 &&
7480 !necp_route_is_allowed(route
, interface
, route_rule_id
, &interface_type_denied
)) ||
7481 !necp_netagents_allow_traffic(netagent_ids
, NECP_MAX_NETAGENTS
)) {
7482 allowed_to_receive
= FALSE
;
7484 if (return_policy_id
) {
7485 *return_policy_id
= matched_policy
->id
;
7487 if (return_route_rule_id
) {
7488 *return_route_rule_id
= route_rule_id
;
7491 lck_rw_done(&necp_kernel_policy_lock
);
7493 if (necp_debug
> 1 && matched_policy
->id
!= inp
->inp_policyresult
.policy_id
) {
7494 NECPLOG(LOG_DEBUG
, "Socket Send/Recv Policy: Policy %d Allowed %d", return_policy_id
? *return_policy_id
: 0, allowed_to_receive
);
7497 } else if (necp_drop_all_order
> 0) {
7498 allowed_to_receive
= FALSE
;
7500 if (return_policy_id
) {
7501 *return_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
7503 if (return_route_rule_id
) {
7504 *return_route_rule_id
= route_rule_id
;
7508 lck_rw_done(&necp_kernel_policy_lock
);
7511 if (!allowed_to_receive
&& interface_type_denied
!= IFRTYPE_FUNCTIONAL_UNKNOWN
) {
7512 soevent(inp
->inp_socket
, (SO_FILT_HINT_LOCKED
| SO_FILT_HINT_IFDENIED
));
7515 return (allowed_to_receive
);
7519 necp_socket_is_allowed_to_send_recv_v4(struct inpcb
*inp
, u_int16_t local_port
, u_int16_t remote_port
, struct in_addr
*local_addr
, struct in_addr
*remote_addr
, ifnet_t interface
, necp_kernel_policy_id
*return_policy_id
, u_int32_t
*return_route_rule_id
)
7521 struct sockaddr_in local
;
7522 struct sockaddr_in remote
;
7523 local
.sin_family
= remote
.sin_family
= AF_INET
;
7524 local
.sin_len
= remote
.sin_len
= sizeof(struct sockaddr_in
);
7525 local
.sin_port
= local_port
;
7526 remote
.sin_port
= remote_port
;
7527 memcpy(&local
.sin_addr
, local_addr
, sizeof(local
.sin_addr
));
7528 memcpy(&remote
.sin_addr
, remote_addr
, sizeof(remote
.sin_addr
));
7530 return (necp_socket_is_allowed_to_send_recv_internal(inp
, (struct sockaddr
*)&local
, (struct sockaddr
*)&remote
, interface
, return_policy_id
, return_route_rule_id
));
7534 necp_socket_is_allowed_to_send_recv_v6(struct inpcb
*inp
, u_int16_t local_port
, u_int16_t remote_port
, struct in6_addr
*local_addr
, struct in6_addr
*remote_addr
, ifnet_t interface
, necp_kernel_policy_id
*return_policy_id
, u_int32_t
*return_route_rule_id
)
7536 struct sockaddr_in6 local
;
7537 struct sockaddr_in6 remote
;
7538 local
.sin6_family
= remote
.sin6_family
= AF_INET6
;
7539 local
.sin6_len
= remote
.sin6_len
= sizeof(struct sockaddr_in6
);
7540 local
.sin6_port
= local_port
;
7541 remote
.sin6_port
= remote_port
;
7542 memcpy(&local
.sin6_addr
, local_addr
, sizeof(local
.sin6_addr
));
7543 memcpy(&remote
.sin6_addr
, remote_addr
, sizeof(remote
.sin6_addr
));
7545 return (necp_socket_is_allowed_to_send_recv_internal(inp
, (struct sockaddr
*)&local
, (struct sockaddr
*)&remote
, interface
, return_policy_id
, return_route_rule_id
));
7549 necp_socket_is_allowed_to_send_recv(struct inpcb
*inp
, necp_kernel_policy_id
*return_policy_id
, u_int32_t
*return_route_rule_id
)
7551 return (necp_socket_is_allowed_to_send_recv_internal(inp
, NULL
, NULL
, NULL
, return_policy_id
, return_route_rule_id
));
7555 necp_mark_packet_from_socket(struct mbuf
*packet
, struct inpcb
*inp
, necp_kernel_policy_id policy_id
, u_int32_t route_rule_id
)
7557 if (packet
== NULL
|| inp
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
7561 // Mark ID for Pass and IP Tunnel
7562 if (policy_id
!= NECP_KERNEL_POLICY_ID_NONE
) {
7563 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= policy_id
;
7564 } else if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_PASS
||
7565 inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
) {
7566 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= inp
->inp_policyresult
.policy_id
;
7568 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
7570 packet
->m_pkthdr
.necp_mtag
.necp_last_interface_index
= 0;
7571 if (route_rule_id
!= 0) {
7572 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
= route_rule_id
;
7574 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
= inp
->inp_policyresult
.results
.route_rule_id
;
7576 packet
->m_pkthdr
.necp_mtag
.necp_app_id
= inp
->inp_policyresult
.app_id
;
7582 necp_mark_packet_from_ip(struct mbuf
*packet
, necp_kernel_policy_id policy_id
)
7584 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
7588 // Mark ID for Pass and IP Tunnel
7589 if (policy_id
!= NECP_KERNEL_POLICY_ID_NONE
) {
7590 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= policy_id
;
7592 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
7599 necp_mark_packet_from_interface(struct mbuf
*packet
, ifnet_t interface
)
7601 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
7605 // Mark ID for Pass and IP Tunnel
7606 if (interface
!= NULL
) {
7607 packet
->m_pkthdr
.necp_mtag
.necp_last_interface_index
= interface
->if_index
;
7614 necp_mark_packet_as_keepalive(struct mbuf
*packet
, bool is_keepalive
)
7616 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
7621 packet
->m_pkthdr
.pkt_flags
|= PKTF_KEEPALIVE
;
7623 packet
->m_pkthdr
.pkt_flags
&= ~PKTF_KEEPALIVE
;
7629 necp_kernel_policy_id
7630 necp_get_policy_id_from_packet(struct mbuf
*packet
)
7632 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
7633 return (NECP_KERNEL_POLICY_ID_NONE
);
7636 return (packet
->m_pkthdr
.necp_mtag
.necp_policy_id
);
7640 necp_get_last_interface_index_from_packet(struct mbuf
*packet
)
7642 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
7646 return (packet
->m_pkthdr
.necp_mtag
.necp_last_interface_index
);
7650 necp_get_route_rule_id_from_packet(struct mbuf
*packet
)
7652 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
7656 return (packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
);
7660 necp_get_app_uuid_from_packet(struct mbuf
*packet
,
7663 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
7667 bool found_mapping
= FALSE
;
7668 if (packet
->m_pkthdr
.necp_mtag
.necp_app_id
!= 0) {
7669 lck_rw_lock_shared(&necp_kernel_policy_lock
);
7670 struct necp_uuid_id_mapping
*entry
= necp_uuid_lookup_uuid_with_app_id_locked(packet
->m_pkthdr
.necp_mtag
.necp_app_id
);
7671 if (entry
!= NULL
) {
7672 uuid_copy(app_uuid
, entry
->uuid
);
7673 found_mapping
= true;
7675 lck_rw_done(&necp_kernel_policy_lock
);
7677 if (!found_mapping
) {
7678 uuid_clear(app_uuid
);
7684 necp_get_is_keepalive_from_packet(struct mbuf
*packet
)
7686 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
7690 return (packet
->m_pkthdr
.pkt_flags
& PKTF_KEEPALIVE
);
7694 necp_socket_get_content_filter_control_unit(struct socket
*so
)
7696 struct inpcb
*inp
= sotoinpcb(so
);
7701 return (inp
->inp_policyresult
.results
.filter_control_unit
);
7705 necp_socket_should_use_flow_divert(struct inpcb
*inp
)
7711 return (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
);
7715 necp_socket_get_flow_divert_control_unit(struct inpcb
*inp
)
7721 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
) {
7722 return (inp
->inp_policyresult
.results
.result_parameter
.flow_divert_control_unit
);
7729 necp_socket_should_rescope(struct inpcb
*inp
)
7735 return (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
);
7739 necp_socket_get_rescope_if_index(struct inpcb
*inp
)
7745 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
) {
7746 return (inp
->inp_policyresult
.results
.result_parameter
.scoped_interface_index
);
7753 necp_socket_get_effective_mtu(struct inpcb
*inp
, u_int32_t current_mtu
)
7756 return (current_mtu
);
7759 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&&
7760 (inp
->inp_flags
& INP_BOUND_IF
) &&
7761 inp
->inp_boundifp
) {
7763 u_int bound_interface_index
= inp
->inp_boundifp
->if_index
;
7764 u_int tunnel_interface_index
= inp
->inp_policyresult
.results
.result_parameter
.tunnel_interface_index
;
7766 // The result is IP Tunnel, and is rescoping from one interface to another. Recalculate MTU.
7767 if (bound_interface_index
!= tunnel_interface_index
) {
7768 ifnet_t tunnel_interface
= NULL
;
7770 ifnet_head_lock_shared();
7771 tunnel_interface
= ifindex2ifnet
[tunnel_interface_index
];
7774 if (tunnel_interface
!= NULL
) {
7775 u_int32_t direct_tunnel_mtu
= tunnel_interface
->if_mtu
;
7776 u_int32_t delegate_tunnel_mtu
= (tunnel_interface
->if_delegated
.ifp
!= NULL
) ? tunnel_interface
->if_delegated
.ifp
->if_mtu
: 0;
7777 if (delegate_tunnel_mtu
!= 0 &&
7778 strncmp(tunnel_interface
->if_name
, "ipsec", strlen("ipsec")) == 0) {
7779 // For ipsec interfaces, calculate the overhead from the delegate interface
7780 u_int32_t tunnel_overhead
= (u_int32_t
)(esp_hdrsiz(NULL
) + sizeof(struct ip6_hdr
));
7781 if (delegate_tunnel_mtu
> tunnel_overhead
) {
7782 delegate_tunnel_mtu
-= tunnel_overhead
;
7785 if (delegate_tunnel_mtu
< direct_tunnel_mtu
) {
7786 // If the (delegate - overhead) < direct, return (delegate - overhead)
7787 return (delegate_tunnel_mtu
);
7789 // Otherwise return direct
7790 return (direct_tunnel_mtu
);
7793 // For non-ipsec interfaces, just return the tunnel MTU
7794 return (direct_tunnel_mtu
);
7800 // By default, just return the MTU passed in
7801 return (current_mtu
);
7805 necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter
*result_parameter
)
7807 if (result_parameter
== NULL
) {
7811 return (ifindex2ifnet
[result_parameter
->tunnel_interface_index
]);
7815 necp_packet_can_rebind_to_ifnet(struct mbuf
*packet
, struct ifnet
*interface
, struct route
*new_route
, int family
)
7817 bool found_match
= FALSE
;
7819 ifaddr_t
*addresses
= NULL
;
7820 union necp_sockaddr_union address_storage
;
7823 if (packet
== NULL
|| interface
== NULL
|| new_route
== NULL
|| (family
!= AF_INET
&& family
!= AF_INET6
)) {
7827 result
= ifnet_get_address_list_family(interface
, &addresses
, family
);
7829 NECPLOG(LOG_ERR
, "Failed to get address list for %s%d", ifnet_name(interface
), ifnet_unit(interface
));
7833 for (i
= 0; addresses
[i
] != NULL
; i
++) {
7834 ROUTE_RELEASE(new_route
);
7835 if (ifaddr_address(addresses
[i
], &address_storage
.sa
, sizeof(address_storage
)) == 0) {
7836 if (family
== AF_INET
) {
7837 struct ip
*ip
= mtod(packet
, struct ip
*);
7838 if (memcmp(&address_storage
.sin
.sin_addr
, &ip
->ip_src
, sizeof(ip
->ip_src
)) == 0) {
7839 struct sockaddr_in
*dst4
= (struct sockaddr_in
*)(void *)&new_route
->ro_dst
;
7840 dst4
->sin_family
= AF_INET
;
7841 dst4
->sin_len
= sizeof(struct sockaddr_in
);
7842 dst4
->sin_addr
= ip
->ip_dst
;
7843 rtalloc_scoped(new_route
, interface
->if_index
);
7844 if (!ROUTE_UNUSABLE(new_route
)) {
7849 } else if (family
== AF_INET6
) {
7850 struct ip6_hdr
*ip6
= mtod(packet
, struct ip6_hdr
*);
7851 if (memcmp(&address_storage
.sin6
.sin6_addr
, &ip6
->ip6_src
, sizeof(ip6
->ip6_src
)) == 0) {
7852 struct sockaddr_in6
*dst6
= (struct sockaddr_in6
*)(void *)&new_route
->ro_dst
;
7853 dst6
->sin6_family
= AF_INET6
;
7854 dst6
->sin6_len
= sizeof(struct sockaddr_in6
);
7855 dst6
->sin6_addr
= ip6
->ip6_dst
;
7856 rtalloc_scoped(new_route
, interface
->if_index
);
7857 if (!ROUTE_UNUSABLE(new_route
)) {
7867 ifnet_free_address_list(addresses
);
7869 return (found_match
);
7873 necp_addr_is_loopback(struct sockaddr
*address
)
7875 if (address
== NULL
) {
7879 if (address
->sa_family
== AF_INET
) {
7880 return (ntohl(((struct sockaddr_in
*)(void *)address
)->sin_addr
.s_addr
) == INADDR_LOOPBACK
);
7881 } else if (address
->sa_family
== AF_INET6
) {
7882 return IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6
*)(void *)address
)->sin6_addr
);
7889 necp_is_loopback(struct sockaddr
*local_addr
, struct sockaddr
*remote_addr
, struct inpcb
*inp
, struct mbuf
*packet
)
7891 // Note: This function only checks for the loopback addresses.
7892 // In the future, we may want to expand to also allow any traffic
7893 // going through the loopback interface, but until then, this
7894 // check is cheaper.
7896 if (local_addr
!= NULL
&& necp_addr_is_loopback(local_addr
)) {
7900 if (remote_addr
!= NULL
&& necp_addr_is_loopback(remote_addr
)) {
7905 if ((inp
->inp_flags
& INP_BOUND_IF
) && inp
->inp_boundifp
&& (inp
->inp_boundifp
->if_flags
& IFF_LOOPBACK
)) {
7908 if (inp
->inp_vflag
& INP_IPV4
) {
7909 if (ntohl(inp
->inp_laddr
.s_addr
) == INADDR_LOOPBACK
||
7910 ntohl(inp
->inp_faddr
.s_addr
) == INADDR_LOOPBACK
) {
7913 } else if (inp
->inp_vflag
& INP_IPV6
) {
7914 if (IN6_IS_ADDR_LOOPBACK(&inp
->in6p_laddr
) ||
7915 IN6_IS_ADDR_LOOPBACK(&inp
->in6p_faddr
)) {
7921 if (packet
!= NULL
) {
7922 struct ip
*ip
= mtod(packet
, struct ip
*);
7923 if (ip
->ip_v
== 4) {
7924 if (ntohl(ip
->ip_src
.s_addr
) == INADDR_LOOPBACK
) {
7927 if (ntohl(ip
->ip_dst
.s_addr
) == INADDR_LOOPBACK
) {
7930 } else if (ip
->ip_v
== 6) {
7931 struct ip6_hdr
*ip6
= mtod(packet
, struct ip6_hdr
*);
7932 if (IN6_IS_ADDR_LOOPBACK(&ip6
->ip6_src
)) {
7935 if (IN6_IS_ADDR_LOOPBACK(&ip6
->ip6_dst
)) {
7945 necp_is_intcoproc(struct inpcb
*inp
, struct mbuf
*packet
)
7949 return (sflt_permission_check(inp
) ? true : false);
7951 if (packet
!= NULL
) {
7952 struct ip6_hdr
*ip6
= mtod(packet
, struct ip6_hdr
*);
7953 if ((ip6
->ip6_vfc
& IPV6_VERSION_MASK
) == IPV6_VERSION
&&
7954 IN6_IS_ADDR_LINKLOCAL(&ip6
->ip6_dst
) &&
7955 ip6
->ip6_dst
.s6_addr32
[2] == ntohl(0xaede48ff) &&
7956 ip6
->ip6_dst
.s6_addr32
[3] == ntohl(0xfe334455)) {