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 if (curr_length
> buffer_length
- ((u_int32_t
)cursor
+ sizeof(curr_type
) + sizeof(curr_length
))) {
895 next_cursor
= (cursor
+ sizeof(curr_type
) + sizeof(curr_length
) + curr_length
);
896 if (curr_type
== type
) {
897 // check if entire TLV fits inside buffer
898 if (((u_int32_t
)next_cursor
) <= buffer_length
) {
904 cursor
= next_cursor
;
909 necp_send_ctl_data(struct necp_session
*session
, u_int8_t
*buffer
, size_t buffer_size
)
913 if (necp_kctlref
== NULL
|| session
== NULL
|| buffer
== NULL
|| buffer_size
== 0) {
917 error
= ctl_enqueuedata(necp_kctlref
, session
->control_unit
, buffer
, buffer_size
, CTL_DATA_EOR
);
923 necp_send_success_response(struct necp_session
*session
, u_int8_t packet_type
, u_int32_t message_id
)
926 u_int8_t
*response
= NULL
;
927 u_int8_t
*cursor
= NULL
;
928 size_t response_size
= sizeof(struct necp_packet_header
) + sizeof(u_int8_t
) + sizeof(u_int32_t
);
929 MALLOC(response
, u_int8_t
*, response_size
, M_NECP
, M_WAITOK
);
930 if (response
== NULL
) {
934 cursor
= necp_buffer_write_packet_header(cursor
, packet_type
, NECP_PACKET_FLAGS_RESPONSE
, message_id
);
935 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_NIL
, 0, NULL
);
937 if (!(success
= necp_send_ctl_data(session
, (u_int8_t
*)response
, response_size
))) {
938 NECPLOG0(LOG_ERR
, "Failed to send response");
941 FREE(response
, M_NECP
);
946 necp_send_error_response(struct necp_session
*session
, u_int8_t packet_type
, u_int32_t message_id
, u_int32_t error
)
949 u_int8_t
*response
= NULL
;
950 u_int8_t
*cursor
= NULL
;
951 size_t response_size
= sizeof(struct necp_packet_header
) + sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(u_int32_t
);
952 MALLOC(response
, u_int8_t
*, response_size
, M_NECP
, M_WAITOK
);
953 if (response
== NULL
) {
957 cursor
= necp_buffer_write_packet_header(cursor
, packet_type
, NECP_PACKET_FLAGS_RESPONSE
, message_id
);
958 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_ERROR
, sizeof(error
), &error
);
960 if (!(success
= necp_send_ctl_data(session
, (u_int8_t
*)response
, response_size
))) {
961 NECPLOG0(LOG_ERR
, "Failed to send response");
964 FREE(response
, M_NECP
);
969 necp_send_policy_id_response(struct necp_session
*session
, u_int8_t packet_type
, u_int32_t message_id
, necp_policy_id policy_id
)
972 u_int8_t
*response
= NULL
;
973 u_int8_t
*cursor
= NULL
;
974 size_t response_size
= sizeof(struct necp_packet_header
) + sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(u_int32_t
);
975 MALLOC(response
, u_int8_t
*, response_size
, M_NECP
, M_WAITOK
);
976 if (response
== NULL
) {
980 cursor
= necp_buffer_write_packet_header(cursor
, packet_type
, NECP_PACKET_FLAGS_RESPONSE
, message_id
);
981 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ID
, sizeof(policy_id
), &policy_id
);
983 if (!(success
= necp_send_ctl_data(session
, (u_int8_t
*)response
, response_size
))) {
984 NECPLOG0(LOG_ERR
, "Failed to send response");
987 FREE(response
, M_NECP
);
992 necp_ctl_send(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, mbuf_t packet
, int flags
)
994 #pragma unused(kctlref, unit, flags)
995 struct necp_session
*session
= (struct necp_session
*)unitinfo
;
996 struct necp_packet_header header
;
999 if (session
== NULL
) {
1000 NECPLOG0(LOG_ERR
, "Got a NULL session");
1005 if (mbuf_pkthdr_len(packet
) < sizeof(header
)) {
1006 NECPLOG(LOG_ERR
, "Got a bad packet, length (%lu) < sizeof header (%lu)", mbuf_pkthdr_len(packet
), sizeof(header
));
1011 error
= mbuf_copydata(packet
, 0, sizeof(header
), &header
);
1013 NECPLOG(LOG_ERR
, "mbuf_copydata failed for the header: %d", error
);
1018 if (session
->proc_locked
) {
1019 // Verify that the calling process is allowed to send messages
1021 proc_getexecutableuuid(current_proc(), proc_uuid
, sizeof(proc_uuid
));
1022 if (uuid_compare(proc_uuid
, session
->proc_uuid
) != 0) {
1023 necp_send_error_response(session
, header
.packet_type
, header
.message_id
, NECP_ERROR_INVALID_PROCESS
);
1027 // If not locked, update the proc_uuid and proc_pid of the session
1028 proc_getexecutableuuid(current_proc(), session
->proc_uuid
, sizeof(session
->proc_uuid
));
1029 session
->proc_pid
= proc_pid(current_proc());
1032 switch (header
.packet_type
) {
1033 case NECP_PACKET_TYPE_POLICY_ADD
: {
1034 necp_handle_policy_add(session
, header
.message_id
, packet
, sizeof(header
));
1037 case NECP_PACKET_TYPE_POLICY_GET
: {
1038 necp_handle_policy_get(session
, header
.message_id
, packet
, sizeof(header
));
1041 case NECP_PACKET_TYPE_POLICY_DELETE
: {
1042 necp_handle_policy_delete(session
, header
.message_id
, packet
, sizeof(header
));
1045 case NECP_PACKET_TYPE_POLICY_APPLY_ALL
: {
1046 necp_handle_policy_apply_all(session
, header
.message_id
, packet
, sizeof(header
));
1049 case NECP_PACKET_TYPE_POLICY_LIST_ALL
: {
1050 necp_handle_policy_list_all(session
, header
.message_id
, packet
, sizeof(header
));
1053 case NECP_PACKET_TYPE_POLICY_DELETE_ALL
: {
1054 necp_handle_policy_delete_all(session
, header
.message_id
, packet
, sizeof(header
));
1057 case NECP_PACKET_TYPE_POLICY_DUMP_ALL
: {
1058 necp_handle_policy_dump_all(session
, header
.message_id
, packet
, sizeof(header
));
1061 case NECP_PACKET_TYPE_SET_SESSION_PRIORITY
: {
1062 necp_handle_set_session_priority(session
, header
.message_id
, packet
, sizeof(header
));
1065 case NECP_PACKET_TYPE_LOCK_SESSION_TO_PROC
: {
1066 necp_handle_lock_session_to_proc(session
, header
.message_id
, packet
, sizeof(header
));
1069 case NECP_PACKET_TYPE_REGISTER_SERVICE
: {
1070 necp_handle_register_service(session
, header
.message_id
, packet
, sizeof(header
));
1073 case NECP_PACKET_TYPE_UNREGISTER_SERVICE
: {
1074 necp_handle_unregister_service(session
, header
.message_id
, packet
, sizeof(header
));
1078 NECPLOG(LOG_ERR
, "Received unknown message type %d", header
.packet_type
);
1079 necp_send_error_response(session
, header
.packet_type
, header
.message_id
, NECP_ERROR_UNKNOWN_PACKET_TYPE
);
1090 necp_ctl_rcvd(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, int flags
)
1092 #pragma unused(kctlref, unit, unitinfo, flags)
1097 necp_ctl_getopt(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, int opt
, void *data
, size_t *len
)
1099 #pragma unused(kctlref, unit, unitinfo, opt, data, len)
1104 necp_ctl_setopt(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, int opt
, void *data
, size_t len
)
1106 #pragma unused(kctlref, unit, unitinfo, opt, data, len)
1110 // Session Management
1111 static struct necp_session
*
1112 necp_create_session(u_int32_t control_unit
)
1114 struct necp_session
*new_session
= NULL
;
1116 MALLOC(new_session
, struct necp_session
*, sizeof(*new_session
), M_NECP
, M_WAITOK
);
1117 if (new_session
== NULL
) {
1121 NECPLOG(LOG_DEBUG
, "Create NECP session, control unit %d", control_unit
);
1123 memset(new_session
, 0, sizeof(*new_session
));
1124 new_session
->session_priority
= NECP_SESSION_PRIORITY_UNKNOWN
;
1125 new_session
->session_order
= necp_allocate_new_session_order(new_session
->session_priority
, control_unit
);
1126 new_session
->control_unit
= control_unit
;
1127 new_session
->dirty
= FALSE
;
1128 LIST_INIT(&new_session
->policies
);
1130 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1131 necp_session_count
++;
1132 lck_rw_done(&necp_kernel_policy_lock
);
1135 return (new_session
);
1139 necp_delete_session(struct necp_session
*session
)
1141 if (session
!= NULL
) {
1142 struct necp_service_registration
*service
= NULL
;
1143 struct necp_service_registration
*temp_service
= NULL
;
1144 LIST_FOREACH_SAFE(service
, &session
->services
, session_chain
, temp_service
) {
1145 LIST_REMOVE(service
, session_chain
);
1146 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1147 LIST_REMOVE(service
, kernel_chain
);
1148 lck_rw_done(&necp_kernel_policy_lock
);
1149 FREE(service
, M_NECP
);
1152 NECPLOG0(LOG_DEBUG
, "Deleted NECP session");
1154 FREE(session
, M_NECP
);
1156 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1157 necp_session_count
--;
1158 lck_rw_done(&necp_kernel_policy_lock
);
1162 // Session Policy Management
1164 static inline u_int8_t
1165 necp_policy_result_get_type_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1167 return ((buffer
&& length
>= sizeof(u_int8_t
)) ? buffer
[0] : 0);
1170 static inline u_int32_t
1171 necp_policy_result_get_parameter_length_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1173 return ((buffer
&& length
> sizeof(u_int8_t
)) ? (length
- sizeof(u_int8_t
)) : 0);
1176 static inline u_int8_t
*
1177 necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1179 return ((buffer
&& length
> sizeof(u_int8_t
)) ? (buffer
+ sizeof(u_int8_t
)) : NULL
);
1183 necp_policy_result_requires_route_rules(u_int8_t
*buffer
, u_int32_t length
)
1185 u_int8_t type
= necp_policy_result_get_type_from_buffer(buffer
, length
);
1186 if (type
== NECP_POLICY_RESULT_ROUTE_RULES
) {
1193 necp_address_is_valid(struct sockaddr
*address
)
1195 if (address
->sa_family
== AF_INET
) {
1196 return (address
->sa_len
== sizeof(struct sockaddr_in
));
1197 } else if (address
->sa_family
== AF_INET6
) {
1198 return (address
->sa_len
== sizeof(struct sockaddr_in6
));
1205 necp_policy_result_is_valid(u_int8_t
*buffer
, u_int32_t length
)
1207 bool validated
= FALSE
;
1208 u_int8_t type
= necp_policy_result_get_type_from_buffer(buffer
, length
);
1209 u_int32_t parameter_length
= necp_policy_result_get_parameter_length_from_buffer(buffer
, length
);
1211 case NECP_POLICY_RESULT_PASS
: {
1215 case NECP_POLICY_RESULT_SKIP
: {
1216 if (parameter_length
>= sizeof(u_int32_t
)) {
1221 case NECP_POLICY_RESULT_DROP
: {
1225 case NECP_POLICY_RESULT_SOCKET_DIVERT
: {
1226 if (parameter_length
>= sizeof(u_int32_t
)) {
1231 case NECP_POLICY_RESULT_SOCKET_SCOPED
: {
1232 if (parameter_length
> 0) {
1237 case NECP_POLICY_RESULT_IP_TUNNEL
: {
1238 if (parameter_length
> sizeof(u_int32_t
)) {
1243 case NECP_POLICY_RESULT_SOCKET_FILTER
: {
1244 if (parameter_length
>= sizeof(u_int32_t
)) {
1249 case NECP_POLICY_RESULT_ROUTE_RULES
: {
1253 case NECP_POLICY_RESULT_TRIGGER
:
1254 case NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
:
1255 case NECP_POLICY_RESULT_TRIGGER_SCOPED
:
1256 case NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
:
1257 case NECP_POLICY_RESULT_USE_NETAGENT
: {
1258 if (parameter_length
>= sizeof(uuid_t
)) {
1270 NECPLOG(LOG_DEBUG
, "Policy result type %d, valid %d", type
, validated
);
1276 static inline u_int8_t
1277 necp_policy_condition_get_type_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1279 return ((buffer
&& length
>= sizeof(u_int8_t
)) ? buffer
[0] : 0);
1282 static inline u_int8_t
1283 necp_policy_condition_get_flags_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1285 return ((buffer
&& length
>= (2 * sizeof(u_int8_t
))) ? buffer
[1] : 0);
1288 static inline u_int32_t
1289 necp_policy_condition_get_value_length_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1291 return ((buffer
&& length
>= (2 * sizeof(u_int8_t
))) ? (length
- (2 * sizeof(u_int8_t
))) : 0);
1294 static inline u_int8_t
*
1295 necp_policy_condition_get_value_pointer_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1297 return ((buffer
&& length
> (2 * sizeof(u_int8_t
))) ? (buffer
+ (2 * sizeof(u_int8_t
))) : NULL
);
1301 necp_policy_condition_is_default(u_int8_t
*buffer
, u_int32_t length
)
1303 return (necp_policy_condition_get_type_from_buffer(buffer
, length
) == NECP_POLICY_CONDITION_DEFAULT
);
1307 necp_policy_condition_is_application(u_int8_t
*buffer
, u_int32_t length
)
1309 return (necp_policy_condition_get_type_from_buffer(buffer
, length
) == NECP_POLICY_CONDITION_APPLICATION
);
1313 necp_policy_condition_is_real_application(u_int8_t
*buffer
, u_int32_t length
)
1315 return (necp_policy_condition_get_type_from_buffer(buffer
, length
) == NECP_POLICY_CONDITION_REAL_APPLICATION
);
1319 necp_policy_condition_requires_application(u_int8_t
*buffer
, u_int32_t length
)
1321 u_int8_t type
= necp_policy_condition_get_type_from_buffer(buffer
, length
);
1322 return (type
== NECP_POLICY_CONDITION_REAL_APPLICATION
);
1326 necp_policy_condition_requires_real_application(u_int8_t
*buffer
, u_int32_t length
)
1328 u_int8_t type
= necp_policy_condition_get_type_from_buffer(buffer
, length
);
1329 return (type
== NECP_POLICY_CONDITION_ENTITLEMENT
);
1333 necp_policy_condition_is_valid(u_int8_t
*buffer
, u_int32_t length
, u_int8_t policy_result_type
)
1335 bool validated
= FALSE
;
1336 bool result_cannot_have_ip_layer
= (policy_result_type
== NECP_POLICY_RESULT_SOCKET_DIVERT
||
1337 policy_result_type
== NECP_POLICY_RESULT_SOCKET_FILTER
||
1338 policy_result_type
== NECP_POLICY_RESULT_TRIGGER
||
1339 policy_result_type
== NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
||
1340 policy_result_type
== NECP_POLICY_RESULT_TRIGGER_SCOPED
||
1341 policy_result_type
== NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
||
1342 policy_result_type
== NECP_POLICY_RESULT_SOCKET_SCOPED
||
1343 policy_result_type
== NECP_POLICY_RESULT_ROUTE_RULES
||
1344 policy_result_type
== NECP_POLICY_RESULT_USE_NETAGENT
) ? TRUE
: FALSE
;
1345 u_int32_t condition_length
= necp_policy_condition_get_value_length_from_buffer(buffer
, length
);
1346 u_int8_t
*condition_value
= necp_policy_condition_get_value_pointer_from_buffer(buffer
, length
);
1347 u_int8_t type
= necp_policy_condition_get_type_from_buffer(buffer
, length
);
1348 u_int8_t flags
= necp_policy_condition_get_flags_from_buffer(buffer
, length
);
1350 case NECP_POLICY_CONDITION_APPLICATION
:
1351 case NECP_POLICY_CONDITION_REAL_APPLICATION
: {
1352 if (!(flags
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
) &&
1353 condition_length
>= sizeof(uuid_t
) &&
1354 condition_value
!= NULL
&&
1355 !uuid_is_null(condition_value
)) {
1360 case NECP_POLICY_CONDITION_DOMAIN
:
1361 case NECP_POLICY_CONDITION_ACCOUNT
:
1362 case NECP_POLICY_CONDITION_BOUND_INTERFACE
: {
1363 if (condition_length
> 0) {
1368 case NECP_POLICY_CONDITION_TRAFFIC_CLASS
: {
1369 if (condition_length
>= sizeof(struct necp_policy_condition_tc_range
)) {
1374 case NECP_POLICY_CONDITION_DEFAULT
:
1375 case NECP_POLICY_CONDITION_ALL_INTERFACES
:
1376 case NECP_POLICY_CONDITION_ENTITLEMENT
: {
1377 if (!(flags
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
)) {
1382 case NECP_POLICY_CONDITION_IP_PROTOCOL
: {
1383 if (condition_length
>= sizeof(u_int16_t
)) {
1388 case NECP_POLICY_CONDITION_PID
: {
1389 if (condition_length
>= sizeof(pid_t
) &&
1390 condition_value
!= NULL
&&
1391 *((pid_t
*)(void *)condition_value
) != 0) {
1396 case NECP_POLICY_CONDITION_UID
: {
1397 if (condition_length
>= sizeof(uid_t
)) {
1402 case NECP_POLICY_CONDITION_LOCAL_ADDR
:
1403 case NECP_POLICY_CONDITION_REMOTE_ADDR
: {
1404 if (!result_cannot_have_ip_layer
&& condition_length
>= sizeof(struct necp_policy_condition_addr
) &&
1405 necp_address_is_valid(&((struct necp_policy_condition_addr
*)(void *)condition_value
)->address
.sa
)) {
1410 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE
:
1411 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE
: {
1412 if (!result_cannot_have_ip_layer
&& condition_length
>= sizeof(struct necp_policy_condition_addr_range
) &&
1413 necp_address_is_valid(&((struct necp_policy_condition_addr_range
*)(void *)condition_value
)->start_address
.sa
) &&
1414 necp_address_is_valid(&((struct necp_policy_condition_addr_range
*)(void *)condition_value
)->end_address
.sa
)) {
1426 NECPLOG(LOG_DEBUG
, "Policy condition type %d, valid %d", type
, validated
);
1433 necp_policy_route_rule_is_default(u_int8_t
*buffer
, u_int32_t length
)
1435 return (necp_policy_condition_get_value_length_from_buffer(buffer
, length
) == 0 &&
1436 necp_policy_condition_get_flags_from_buffer(buffer
, length
) == 0);
1440 necp_policy_route_rule_is_valid(u_int8_t
*buffer
, u_int32_t length
)
1442 bool validated
= FALSE
;
1443 u_int8_t type
= necp_policy_condition_get_type_from_buffer(buffer
, length
);
1445 case NECP_ROUTE_RULE_ALLOW_INTERFACE
: {
1449 case NECP_ROUTE_RULE_DENY_INTERFACE
: {
1453 case NECP_ROUTE_RULE_QOS_MARKING
: {
1464 NECPLOG(LOG_DEBUG
, "Policy route rule type %d, valid %d", type
, validated
);
1471 necp_handle_set_session_priority(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1474 struct necp_session_policy
*policy
= NULL
;
1475 struct necp_session_policy
*temp_policy
= NULL
;
1476 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
1477 u_int32_t requested_session_priority
= NECP_SESSION_PRIORITY_UNKNOWN
;
1480 error
= necp_packet_get_tlv(packet
, offset
, NECP_TLV_SESSION_PRIORITY
, sizeof(requested_session_priority
), &requested_session_priority
, NULL
);
1482 NECPLOG(LOG_ERR
, "Failed to get session priority: %d", error
);
1483 response_error
= NECP_ERROR_INVALID_TLV
;
1487 if (session
== NULL
) {
1488 NECPLOG0(LOG_ERR
, "Failed to find session");
1489 response_error
= NECP_ERROR_INTERNAL
;
1493 // Enforce special session priorities with entitlements
1494 if (requested_session_priority
== NECP_SESSION_PRIORITY_CONTROL
||
1495 requested_session_priority
== NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL
) {
1496 errno_t cred_result
= priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES
, 0);
1497 if (cred_result
!= 0) {
1498 NECPLOG(LOG_ERR
, "Session does not hold necessary entitlement to claim priority level %d", requested_session_priority
);
1503 if (session
->session_priority
!= requested_session_priority
) {
1504 session
->session_priority
= requested_session_priority
;
1505 session
->session_order
= necp_allocate_new_session_order(session
->session_priority
, session
->control_unit
);
1506 session
->dirty
= TRUE
;
1508 // Mark all policies as needing updates
1509 LIST_FOREACH_SAFE(policy
, &session
->policies
, chain
, temp_policy
) {
1510 policy
->pending_update
= TRUE
;
1514 necp_send_success_response(session
, NECP_PACKET_TYPE_SET_SESSION_PRIORITY
, message_id
);
1518 necp_send_error_response(session
, NECP_PACKET_TYPE_SET_SESSION_PRIORITY
, message_id
, response_error
);
1522 necp_handle_lock_session_to_proc(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1524 #pragma unused(packet, offset)
1525 // proc_uuid already filled out
1526 session
->proc_locked
= TRUE
;
1527 necp_send_success_response(session
, NECP_PACKET_TYPE_LOCK_SESSION_TO_PROC
, message_id
);
1531 necp_handle_register_service(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1534 struct necp_service_registration
*new_service
= NULL
;
1535 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
1536 uuid_t service_uuid
;
1537 uuid_clear(service_uuid
);
1539 if (session
== NULL
) {
1540 NECPLOG0(LOG_ERR
, "Failed to find session");
1541 response_error
= NECP_ERROR_INTERNAL
;
1545 // Enforce entitlements
1546 errno_t cred_result
= priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES
, 0);
1547 if (cred_result
!= 0) {
1548 NECPLOG0(LOG_ERR
, "Session does not hold necessary entitlement to register service");
1552 // Read service uuid
1553 error
= necp_packet_get_tlv(packet
, offset
, NECP_TLV_SERVICE_UUID
, sizeof(uuid_t
), service_uuid
, NULL
);
1555 NECPLOG(LOG_ERR
, "Failed to get service UUID: %d", error
);
1556 response_error
= NECP_ERROR_INVALID_TLV
;
1560 MALLOC(new_service
, struct necp_service_registration
*, sizeof(*new_service
), M_NECP
, M_WAITOK
);
1561 if (new_service
== NULL
) {
1562 NECPLOG0(LOG_ERR
, "Failed to allocate service registration");
1563 response_error
= NECP_ERROR_INTERNAL
;
1567 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1568 memset(new_service
, 0, sizeof(*new_service
));
1569 new_service
->service_id
= necp_create_uuid_service_id_mapping(service_uuid
);
1570 LIST_INSERT_HEAD(&session
->services
, new_service
, session_chain
);
1571 LIST_INSERT_HEAD(&necp_registered_service_list
, new_service
, kernel_chain
);
1572 lck_rw_done(&necp_kernel_policy_lock
);
1574 necp_send_success_response(session
, NECP_PACKET_TYPE_REGISTER_SERVICE
, message_id
);
1577 necp_send_error_response(session
, NECP_PACKET_TYPE_REGISTER_SERVICE
, message_id
, response_error
);
1581 necp_handle_unregister_service(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1584 struct necp_service_registration
*service
= NULL
;
1585 struct necp_service_registration
*temp_service
= NULL
;
1586 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
1587 struct necp_uuid_id_mapping
*mapping
= NULL
;
1588 uuid_t service_uuid
;
1589 uuid_clear(service_uuid
);
1591 if (session
== NULL
) {
1592 NECPLOG0(LOG_ERR
, "Failed to find session");
1593 response_error
= NECP_ERROR_INTERNAL
;
1597 // Read service uuid
1598 error
= necp_packet_get_tlv(packet
, offset
, NECP_TLV_SERVICE_UUID
, sizeof(uuid_t
), service_uuid
, NULL
);
1600 NECPLOG(LOG_ERR
, "Failed to get service UUID: %d", error
);
1601 response_error
= NECP_ERROR_INVALID_TLV
;
1605 // Mark remove all matching services for this session
1606 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1607 mapping
= necp_uuid_lookup_service_id_locked(service_uuid
);
1608 if (mapping
!= NULL
) {
1609 LIST_FOREACH_SAFE(service
, &session
->services
, session_chain
, temp_service
) {
1610 if (service
->service_id
== mapping
->id
) {
1611 LIST_REMOVE(service
, session_chain
);
1612 LIST_REMOVE(service
, kernel_chain
);
1613 FREE(service
, M_NECP
);
1616 necp_remove_uuid_service_id_mapping(service_uuid
);
1618 lck_rw_done(&necp_kernel_policy_lock
);
1620 necp_send_success_response(session
, NECP_PACKET_TYPE_UNREGISTER_SERVICE
, message_id
);
1623 necp_send_error_response(session
, NECP_PACKET_TYPE_UNREGISTER_SERVICE
, message_id
, response_error
);
1627 necp_handle_policy_add(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1629 bool has_default_condition
= FALSE
;
1630 bool has_non_default_condition
= FALSE
;
1631 bool has_application_condition
= FALSE
;
1632 bool has_real_application_condition
= FALSE
;
1633 bool requires_application_condition
= FALSE
;
1634 bool requires_real_application_condition
= FALSE
;
1635 u_int8_t
*conditions_array
= NULL
;
1636 u_int32_t conditions_array_size
= 0;
1637 int conditions_array_cursor
;
1639 bool has_default_route_rule
= FALSE
;
1640 u_int8_t
*route_rules_array
= NULL
;
1641 u_int32_t route_rules_array_size
= 0;
1642 int route_rules_array_cursor
;
1646 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
1648 necp_policy_order order
= 0;
1649 struct necp_session_policy
*policy
= NULL
;
1650 u_int8_t
*policy_result
= NULL
;
1651 u_int32_t policy_result_size
= 0;
1653 // Read policy order
1654 error
= necp_packet_get_tlv(packet
, offset
, NECP_TLV_POLICY_ORDER
, sizeof(order
), &order
, NULL
);
1656 NECPLOG(LOG_ERR
, "Failed to get policy order: %d", error
);
1657 response_error
= NECP_ERROR_INVALID_TLV
;
1661 // Read policy result
1662 cursor
= necp_packet_find_tlv(packet
, offset
, NECP_TLV_POLICY_RESULT
, &error
, 0);
1663 error
= necp_packet_get_tlv_at_offset(packet
, cursor
, 0, NULL
, &policy_result_size
);
1664 if (error
|| policy_result_size
== 0) {
1665 NECPLOG(LOG_ERR
, "Failed to get policy result length: %d", error
);
1666 response_error
= NECP_ERROR_INVALID_TLV
;
1669 if (policy_result_size
> NECP_MAX_POLICY_RESULT_SIZE
) {
1670 NECPLOG(LOG_ERR
, "Policy result length too large: %u", policy_result_size
);
1671 response_error
= NECP_ERROR_INVALID_TLV
;
1674 MALLOC(policy_result
, u_int8_t
*, policy_result_size
, M_NECP
, M_WAITOK
);
1675 if (policy_result
== NULL
) {
1676 NECPLOG(LOG_ERR
, "Failed to allocate a policy result buffer (size %d)", policy_result_size
);
1677 response_error
= NECP_ERROR_INTERNAL
;
1680 error
= necp_packet_get_tlv_at_offset(packet
, cursor
, policy_result_size
, policy_result
, NULL
);
1682 NECPLOG(LOG_ERR
, "Failed to get policy result: %d", error
);
1683 response_error
= NECP_ERROR_POLICY_RESULT_INVALID
;
1686 if (!necp_policy_result_is_valid(policy_result
, policy_result_size
)) {
1687 NECPLOG0(LOG_ERR
, "Failed to validate policy result");
1688 response_error
= NECP_ERROR_POLICY_RESULT_INVALID
;
1692 if (necp_policy_result_requires_route_rules(policy_result
, policy_result_size
)) {
1693 // Read route rules conditions
1694 for (cursor
= necp_packet_find_tlv(packet
, offset
, NECP_TLV_ROUTE_RULE
, &error
, 0);
1696 cursor
= necp_packet_find_tlv(packet
, cursor
, NECP_TLV_ROUTE_RULE
, &error
, 1)) {
1697 u_int32_t route_rule_size
= 0;
1698 necp_packet_get_tlv_at_offset(packet
, cursor
, 0, NULL
, &route_rule_size
);
1699 if (route_rule_size
> 0) {
1700 route_rules_array_size
+= (sizeof(u_int8_t
) + sizeof(u_int32_t
) + route_rule_size
);
1704 if (route_rules_array_size
== 0) {
1705 NECPLOG0(LOG_ERR
, "Failed to get policy route rules");
1706 response_error
= NECP_ERROR_INVALID_TLV
;
1709 if (route_rules_array_size
> NECP_MAX_ROUTE_RULES_ARRAY_SIZE
) {
1710 NECPLOG(LOG_ERR
, "Route rules length too large: %u", route_rules_array_size
);
1711 response_error
= NECP_ERROR_INVALID_TLV
;
1714 MALLOC(route_rules_array
, u_int8_t
*, route_rules_array_size
, M_NECP
, M_WAITOK
);
1715 if (route_rules_array
== NULL
) {
1716 NECPLOG(LOG_ERR
, "Failed to allocate a policy route rules array (size %d)", route_rules_array_size
);
1717 response_error
= NECP_ERROR_INTERNAL
;
1721 route_rules_array_cursor
= 0;
1722 for (cursor
= necp_packet_find_tlv(packet
, offset
, NECP_TLV_ROUTE_RULE
, &error
, 0);
1724 cursor
= necp_packet_find_tlv(packet
, cursor
, NECP_TLV_ROUTE_RULE
, &error
, 1)) {
1725 u_int8_t route_rule_type
= NECP_TLV_ROUTE_RULE
;
1726 u_int32_t route_rule_size
= 0;
1727 necp_packet_get_tlv_at_offset(packet
, cursor
, 0, NULL
, &route_rule_size
);
1728 if (route_rule_size
> 0 && route_rule_size
<= (route_rules_array_size
- route_rules_array_cursor
)) {
1730 memcpy((route_rules_array
+ route_rules_array_cursor
), &route_rule_type
, sizeof(route_rule_type
));
1731 route_rules_array_cursor
+= sizeof(route_rule_type
);
1734 memcpy((route_rules_array
+ route_rules_array_cursor
), &route_rule_size
, sizeof(route_rule_size
));
1735 route_rules_array_cursor
+= sizeof(route_rule_size
);
1738 necp_packet_get_tlv_at_offset(packet
, cursor
, route_rule_size
, (route_rules_array
+ route_rules_array_cursor
), NULL
);
1740 if (!necp_policy_route_rule_is_valid((route_rules_array
+ route_rules_array_cursor
), route_rule_size
)) {
1741 NECPLOG0(LOG_ERR
, "Failed to validate policy route rule");
1742 response_error
= NECP_ERROR_ROUTE_RULES_INVALID
;
1746 if (necp_policy_route_rule_is_default((route_rules_array
+ route_rules_array_cursor
), route_rule_size
)) {
1747 if (has_default_route_rule
) {
1748 NECPLOG0(LOG_ERR
, "Failed to validate route rule; contained multiple default route rules");
1749 response_error
= NECP_ERROR_ROUTE_RULES_INVALID
;
1752 has_default_route_rule
= TRUE
;
1755 route_rules_array_cursor
+= route_rule_size
;
1760 // Read policy conditions
1761 for (cursor
= necp_packet_find_tlv(packet
, offset
, NECP_TLV_POLICY_CONDITION
, &error
, 0);
1763 cursor
= necp_packet_find_tlv(packet
, cursor
, NECP_TLV_POLICY_CONDITION
, &error
, 1)) {
1764 u_int32_t condition_size
= 0;
1765 necp_packet_get_tlv_at_offset(packet
, cursor
, 0, NULL
, &condition_size
);
1767 if (condition_size
> 0) {
1768 conditions_array_size
+= (sizeof(u_int8_t
) + sizeof(u_int32_t
) + condition_size
);
1772 if (conditions_array_size
== 0) {
1773 NECPLOG0(LOG_ERR
, "Failed to get policy conditions");
1774 response_error
= NECP_ERROR_INVALID_TLV
;
1777 if (conditions_array_size
> NECP_MAX_CONDITIONS_ARRAY_SIZE
) {
1778 NECPLOG(LOG_ERR
, "Conditions length too large: %u", conditions_array_size
);
1779 response_error
= NECP_ERROR_INVALID_TLV
;
1782 MALLOC(conditions_array
, u_int8_t
*, conditions_array_size
, M_NECP
, M_WAITOK
);
1783 if (conditions_array
== NULL
) {
1784 NECPLOG(LOG_ERR
, "Failed to allocate a policy conditions array (size %d)", conditions_array_size
);
1785 response_error
= NECP_ERROR_INTERNAL
;
1789 conditions_array_cursor
= 0;
1790 for (cursor
= necp_packet_find_tlv(packet
, offset
, NECP_TLV_POLICY_CONDITION
, &error
, 0);
1792 cursor
= necp_packet_find_tlv(packet
, cursor
, NECP_TLV_POLICY_CONDITION
, &error
, 1)) {
1793 u_int8_t condition_type
= NECP_TLV_POLICY_CONDITION
;
1794 u_int32_t condition_size
= 0;
1795 necp_packet_get_tlv_at_offset(packet
, cursor
, 0, NULL
, &condition_size
);
1796 if (condition_size
> 0 && condition_size
<= (conditions_array_size
- conditions_array_cursor
)) {
1798 memcpy((conditions_array
+ conditions_array_cursor
), &condition_type
, sizeof(condition_type
));
1799 conditions_array_cursor
+= sizeof(condition_type
);
1802 memcpy((conditions_array
+ conditions_array_cursor
), &condition_size
, sizeof(condition_size
));
1803 conditions_array_cursor
+= sizeof(condition_size
);
1806 necp_packet_get_tlv_at_offset(packet
, cursor
, condition_size
, (conditions_array
+ conditions_array_cursor
), NULL
);
1807 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
))) {
1808 NECPLOG0(LOG_ERR
, "Failed to validate policy condition");
1809 response_error
= NECP_ERROR_POLICY_CONDITIONS_INVALID
;
1813 if (necp_policy_condition_is_default((conditions_array
+ conditions_array_cursor
), condition_size
)) {
1814 has_default_condition
= TRUE
;
1816 has_non_default_condition
= TRUE
;
1818 if (has_default_condition
&& has_non_default_condition
) {
1819 NECPLOG0(LOG_ERR
, "Failed to validate conditions; contained default and non-default conditions");
1820 response_error
= NECP_ERROR_POLICY_CONDITIONS_INVALID
;
1824 if (necp_policy_condition_is_application((conditions_array
+ conditions_array_cursor
), condition_size
)) {
1825 has_application_condition
= TRUE
;
1828 if (necp_policy_condition_is_real_application((conditions_array
+ conditions_array_cursor
), condition_size
)) {
1829 has_real_application_condition
= TRUE
;
1832 if (necp_policy_condition_requires_application((conditions_array
+ conditions_array_cursor
), condition_size
)) {
1833 requires_application_condition
= TRUE
;
1836 if (necp_policy_condition_requires_real_application((conditions_array
+ conditions_array_cursor
), condition_size
)) {
1837 requires_real_application_condition
= TRUE
;
1840 conditions_array_cursor
+= condition_size
;
1844 if (requires_application_condition
&& !has_application_condition
) {
1845 NECPLOG0(LOG_ERR
, "Failed to validate conditions; did not contain application condition");
1846 response_error
= NECP_ERROR_POLICY_CONDITIONS_INVALID
;
1850 if (requires_real_application_condition
&& !has_real_application_condition
) {
1851 NECPLOG0(LOG_ERR
, "Failed to validate conditions; did not contain real application condition");
1852 response_error
= NECP_ERROR_POLICY_CONDITIONS_INVALID
;
1856 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
) {
1857 response_error
= NECP_ERROR_INTERNAL
;
1861 necp_send_policy_id_response(session
, NECP_PACKET_TYPE_POLICY_ADD
, message_id
, policy
->id
);
1865 if (policy_result
!= NULL
) {
1866 FREE(policy_result
, M_NECP
);
1868 if (conditions_array
!= NULL
) {
1869 FREE(conditions_array
, M_NECP
);
1871 if (route_rules_array
!= NULL
) {
1872 FREE(route_rules_array
, M_NECP
);
1875 necp_send_error_response(session
, NECP_PACKET_TYPE_POLICY_ADD
, message_id
, response_error
);
1879 necp_handle_policy_get(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1881 #pragma unused(offset)
1883 u_int8_t
*response
= NULL
;
1884 u_int8_t
*cursor
= NULL
;
1885 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
1886 necp_policy_id policy_id
= 0;
1887 u_int32_t order_tlv_size
= 0;
1888 u_int32_t result_tlv_size
= 0;
1889 u_int32_t response_size
= 0;
1891 struct necp_session_policy
*policy
= NULL
;
1894 error
= necp_packet_get_tlv(packet
, offset
, NECP_TLV_POLICY_ID
, sizeof(policy_id
), &policy_id
, NULL
);
1896 NECPLOG(LOG_ERR
, "Failed to get policy id: %d", error
);
1897 response_error
= NECP_ERROR_INVALID_TLV
;
1901 policy
= necp_policy_find(session
, policy_id
);
1902 if (policy
== NULL
|| policy
->pending_deletion
) {
1903 NECPLOG(LOG_ERR
, "Failed to find policy with id %d", policy_id
);
1904 response_error
= NECP_ERROR_POLICY_ID_NOT_FOUND
;
1908 order_tlv_size
= sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(necp_policy_order
);
1909 result_tlv_size
= (policy
->result_size
? (sizeof(u_int8_t
) + sizeof(u_int32_t
) + policy
->result_size
) : 0);
1910 response_size
= sizeof(struct necp_packet_header
) + order_tlv_size
+ result_tlv_size
+ policy
->conditions_size
;
1911 MALLOC(response
, u_int8_t
*, response_size
, M_NECP
, M_WAITOK
);
1912 if (response
== NULL
) {
1913 necp_send_error_response(session
, NECP_PACKET_TYPE_POLICY_LIST_ALL
, message_id
, NECP_ERROR_INTERNAL
);
1918 cursor
= necp_buffer_write_packet_header(cursor
, NECP_PACKET_TYPE_POLICY_GET
, NECP_PACKET_FLAGS_RESPONSE
, message_id
);
1919 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ORDER
, sizeof(necp_policy_order
), &policy
->order
);
1921 if (result_tlv_size
) {
1922 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_RESULT
, policy
->result_size
, &policy
->result
);
1924 if (policy
->conditions_size
) {
1925 memcpy(((u_int8_t
*)(void *)(cursor
)), policy
->conditions
, policy
->conditions_size
);
1928 if (!necp_send_ctl_data(session
, (u_int8_t
*)response
, response_size
)) {
1929 NECPLOG0(LOG_ERR
, "Failed to send response");
1932 FREE(response
, M_NECP
);
1936 necp_send_error_response(session
, NECP_PACKET_TYPE_POLICY_GET
, message_id
, response_error
);
1940 necp_handle_policy_delete(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1943 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
1944 necp_policy_id policy_id
= 0;
1946 struct necp_session_policy
*policy
= NULL
;
1949 error
= necp_packet_get_tlv(packet
, offset
, NECP_TLV_POLICY_ID
, sizeof(policy_id
), &policy_id
, NULL
);
1951 NECPLOG(LOG_ERR
, "Failed to get policy id: %d", error
);
1952 response_error
= NECP_ERROR_INVALID_TLV
;
1956 policy
= necp_policy_find(session
, policy_id
);
1957 if (policy
== NULL
|| policy
->pending_deletion
) {
1958 NECPLOG(LOG_ERR
, "Failed to find policy with id %d", policy_id
);
1959 response_error
= NECP_ERROR_POLICY_ID_NOT_FOUND
;
1963 necp_policy_mark_for_deletion(session
, policy
);
1965 necp_send_success_response(session
, NECP_PACKET_TYPE_POLICY_DELETE
, message_id
);
1969 necp_send_error_response(session
, NECP_PACKET_TYPE_POLICY_DELETE
, message_id
, response_error
);
1973 necp_handle_policy_apply_all(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1975 #pragma unused(packet, offset)
1976 necp_policy_apply_all(session
);
1977 necp_send_success_response(session
, NECP_PACKET_TYPE_POLICY_APPLY_ALL
, message_id
);
1981 necp_handle_policy_list_all(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
1983 #pragma unused(packet, offset)
1984 u_int32_t tlv_size
= (sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(u_int32_t
));
1985 u_int32_t response_size
= 0;
1986 u_int8_t
*response
= NULL
;
1987 u_int8_t
*cursor
= NULL
;
1988 int num_policies
= 0;
1989 int cur_policy_index
= 0;
1990 struct necp_session_policy
*policy
;
1992 LIST_FOREACH(policy
, &session
->policies
, chain
) {
1993 if (!policy
->pending_deletion
) {
1998 // Create a response with one Policy ID TLV for each policy
1999 response_size
= sizeof(struct necp_packet_header
) + num_policies
* tlv_size
;
2000 MALLOC(response
, u_int8_t
*, response_size
, M_NECP
, M_WAITOK
);
2001 if (response
== NULL
) {
2002 necp_send_error_response(session
, NECP_PACKET_TYPE_POLICY_LIST_ALL
, message_id
, NECP_ERROR_INTERNAL
);
2007 cursor
= necp_buffer_write_packet_header(cursor
, NECP_PACKET_TYPE_POLICY_LIST_ALL
, NECP_PACKET_FLAGS_RESPONSE
, message_id
);
2009 LIST_FOREACH(policy
, &session
->policies
, chain
) {
2010 if (!policy
->pending_deletion
&& cur_policy_index
< num_policies
) {
2011 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ID
, sizeof(u_int32_t
), &policy
->id
);
2016 if (!necp_send_ctl_data(session
, (u_int8_t
*)response
, response_size
)) {
2017 NECPLOG0(LOG_ERR
, "Failed to send response");
2020 FREE(response
, M_NECP
);
2024 necp_handle_policy_delete_all(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
2026 #pragma unused(packet, offset)
2027 necp_policy_mark_all_for_deletion(session
);
2028 necp_send_success_response(session
, NECP_PACKET_TYPE_POLICY_DELETE_ALL
, message_id
);
2031 static necp_policy_id
2032 necp_policy_get_new_id(void)
2034 necp_policy_id newid
= 0;
2036 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
2038 necp_last_policy_id
++;
2039 if (necp_last_policy_id
< 1) {
2040 necp_last_policy_id
= 1;
2043 newid
= necp_last_policy_id
;
2044 lck_rw_done(&necp_kernel_policy_lock
);
2047 NECPLOG0(LOG_DEBUG
, "Allocate policy id failed.\n");
2055 * For the policy dump response this is the structure:
2057 * <NECP_PACKET_HEADER>
2059 * type : NECP_TLV_POLICY_DUMP
2064 * type : NECP_TLV_POLICY_ID
2069 * type : NECP_TLV_POLICY_ORDER
2074 * type : NECP_TLV_POLICY_RESULT_STRING
2079 * type : NECP_TLV_POLICY_OWNER
2084 * type : NECP_TLV_POLICY_CONDITION
2089 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
2094 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
2104 * type : NECP_TLV_POLICY_DUMP
2109 * type : NECP_TLV_POLICY_ID
2114 * type : NECP_TLV_POLICY_ORDER
2119 * type : NECP_TLV_POLICY_RESULT_STRING
2124 * type : NECP_TLV_POLICY_OWNER
2129 * type : NECP_TLV_POLICY_CONDITION
2134 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
2139 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
2151 necp_handle_policy_dump_all(struct necp_session
*session
, u_int32_t message_id
, mbuf_t packet
, int offset
)
2153 #pragma unused(packet, offset)
2154 struct necp_kernel_socket_policy
*policy
= NULL
;
2156 int policy_count
= 0;
2157 u_int8_t
**tlv_buffer_pointers
= NULL
;
2158 u_int32_t
*tlv_buffer_lengths
= NULL
;
2159 int total_tlv_len
= 0;
2160 u_int8_t
*result_buf
= NULL
;
2161 u_int8_t
*result_buf_cursor
= result_buf
;
2162 char result_string
[MAX_RESULT_STRING_LEN
];
2163 char proc_name_string
[MAXCOMLEN
+ 1];
2165 bool error_occured
= false;
2166 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
2168 #define REPORT_ERROR(error) error_occured = true; \
2169 response_error = error; \
2172 #define UNLOCK_AND_REPORT_ERROR(lock, error) lck_rw_done(lock); \
2175 errno_t cred_result
= priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES
, 0);
2176 if (cred_result
!= 0) {
2177 NECPLOG0(LOG_ERR
, "Session does not hold the necessary entitlement to get Network Extension Policy information");
2178 REPORT_ERROR(NECP_ERROR_INTERNAL
);
2182 lck_rw_lock_shared(&necp_kernel_policy_lock
);
2184 NECPLOG0(LOG_DEBUG
, "Gathering policies");
2186 policy_count
= necp_kernel_application_policies_count
;
2188 MALLOC(tlv_buffer_pointers
, u_int8_t
**, sizeof(u_int8_t
*) * policy_count
, M_NECP
, M_NOWAIT
| M_ZERO
);
2189 if (tlv_buffer_pointers
== NULL
) {
2190 NECPLOG(LOG_DEBUG
, "Failed to allocate tlv_buffer_pointers (%u bytes)", sizeof(u_int8_t
*) * policy_count
);
2191 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock
, NECP_ERROR_INTERNAL
);
2194 MALLOC(tlv_buffer_lengths
, u_int32_t
*, sizeof(u_int32_t
) * policy_count
, M_NECP
, M_NOWAIT
| M_ZERO
);
2195 if (tlv_buffer_lengths
== NULL
) {
2196 NECPLOG(LOG_DEBUG
, "Failed to allocate tlv_buffer_lengths (%u bytes)", sizeof(u_int32_t
) * policy_count
);
2197 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock
, NECP_ERROR_INTERNAL
);
2200 for (policy_i
= 0; necp_kernel_socket_policies_app_layer_map
!= NULL
&& necp_kernel_socket_policies_app_layer_map
[policy_i
] != NULL
; policy_i
++) {
2201 policy
= necp_kernel_socket_policies_app_layer_map
[policy_i
];
2203 memset(result_string
, 0, MAX_RESULT_STRING_LEN
);
2204 memset(proc_name_string
, 0, MAXCOMLEN
+ 1);
2206 necp_get_result_description(result_string
, policy
->result
, policy
->result_parameter
);
2207 proc_name(policy
->session_pid
, proc_name_string
, MAXCOMLEN
);
2209 u_int16_t proc_name_len
= strlen(proc_name_string
) + 1;
2210 u_int16_t result_string_len
= strlen(result_string
) + 1;
2212 NECPLOG(LOG_DEBUG
, "Policy: process: %s, result: %s", proc_name_string
, result_string
);
2214 u_int32_t total_allocated_bytes
= sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(policy
->id
) + // NECP_TLV_POLICY_ID
2215 sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(policy
->order
) + // NECP_TLV_POLICY_ORDER
2216 sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(policy
->session_order
) + // NECP_TLV_POLICY_SESSION_ORDER
2217 sizeof(u_int8_t
) + sizeof(u_int32_t
) + result_string_len
+ // NECP_TLV_POLICY_RESULT_STRING
2218 sizeof(u_int8_t
) + sizeof(u_int32_t
) + proc_name_len
+ // NECP_TLV_POLICY_OWNER
2219 sizeof(u_int8_t
) + sizeof(u_int32_t
); // NECP_TLV_POLICY_CONDITION
2221 // We now traverse the condition_mask to see how much space we need to allocate
2222 u_int32_t condition_mask
= policy
->condition_mask
;
2223 u_int8_t num_conditions
= 0;
2224 struct necp_string_id_mapping
*account_id_entry
= NULL
;
2225 char if_name
[IFXNAMSIZ
];
2226 u_int32_t condition_tlv_length
= 0;
2227 memset(if_name
, 0, sizeof(if_name
));
2229 if (condition_mask
== NECP_POLICY_CONDITION_DEFAULT
) {
2232 if (condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) {
2235 if (condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
2236 snprintf(if_name
, IFXNAMSIZ
, "%s%d", ifnet_name(policy
->cond_bound_interface
), ifnet_unit(policy
->cond_bound_interface
));
2237 condition_tlv_length
+= strlen(if_name
) + 1;
2240 if (condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
2241 condition_tlv_length
+= sizeof(policy
->cond_protocol
);
2244 if (condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
2245 condition_tlv_length
+= sizeof(uuid_t
);
2248 if (condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
2249 condition_tlv_length
+= sizeof(uuid_t
);
2252 if (condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
2253 u_int32_t domain_len
= strlen(policy
->cond_domain
) + 1;
2254 condition_tlv_length
+= domain_len
;
2257 if (condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
2258 account_id_entry
= necp_lookup_string_with_id_locked(&necp_account_id_list
, policy
->cond_account_id
);
2259 u_int32_t account_id_len
= 0;
2260 if (account_id_entry
) {
2261 account_id_len
= account_id_entry
->string
? strlen(account_id_entry
->string
) + 1 : 0;
2263 condition_tlv_length
+= account_id_len
;
2266 if (condition_mask
& NECP_KERNEL_CONDITION_PID
) {
2267 condition_tlv_length
+= sizeof(pid_t
);
2270 if (condition_mask
& NECP_KERNEL_CONDITION_UID
) {
2271 condition_tlv_length
+= sizeof(uid_t
);
2274 if (condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
2275 condition_tlv_length
+= sizeof(struct necp_policy_condition_tc_range
);
2278 if (condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
) {
2281 if (condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) {
2282 u_int32_t entitlement_len
= strlen(policy
->cond_custom_entitlement
) + 1;
2283 condition_tlv_length
+= entitlement_len
;
2286 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
2287 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
2288 condition_tlv_length
+= sizeof(struct necp_policy_condition_addr_range
);
2290 condition_tlv_length
+= sizeof(struct necp_policy_condition_addr
);
2294 if (condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
2295 if (condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
2296 condition_tlv_length
+= sizeof(struct necp_policy_condition_addr_range
);
2298 condition_tlv_length
+= sizeof(struct necp_policy_condition_addr
);
2304 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.
2305 total_allocated_bytes
+= condition_tlv_length
;
2307 u_int8_t
*tlv_buffer
;
2308 MALLOC(tlv_buffer
, u_int8_t
*, total_allocated_bytes
, M_NECP
, M_NOWAIT
| M_ZERO
);
2309 if (tlv_buffer
== NULL
) {
2310 NECPLOG(LOG_DEBUG
, "Failed to allocate tlv_buffer (%u bytes)", total_allocated_bytes
);
2314 u_int8_t
*cursor
= tlv_buffer
;
2315 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ID
, sizeof(policy
->id
), &policy
->id
);
2316 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ORDER
, sizeof(necp_policy_order
), &policy
->order
);
2317 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_SESSION_ORDER
, sizeof(policy
->session_order
), &policy
->session_order
);
2318 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_RESULT_STRING
, result_string_len
, result_string
);
2319 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_OWNER
, proc_name_len
, proc_name_string
);
2322 u_int8_t q_cond_buf
[N_QUICK
]; // Minor optimization
2324 u_int8_t
*cond_buf
; // To be used for condition TLVs
2325 if (condition_tlv_length
<= N_QUICK
) {
2326 cond_buf
= q_cond_buf
;
2328 MALLOC(cond_buf
, u_int8_t
*, condition_tlv_length
, M_NECP
, M_NOWAIT
);
2329 if (cond_buf
== NULL
) {
2330 NECPLOG(LOG_DEBUG
, "Failed to allocate cond_buffer (%u bytes)", condition_tlv_length
);
2331 FREE(tlv_buffer
, M_NECP
);
2336 memset(cond_buf
, 0, condition_tlv_length
);
2337 u_int8_t
*cond_buf_cursor
= cond_buf
;
2338 if (condition_mask
== NECP_POLICY_CONDITION_DEFAULT
) {
2339 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_DEFAULT
, 0, "");
2341 if (condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) {
2342 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_ALL_INTERFACES
, 0, "");
2344 if (condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
2345 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_BOUND_INTERFACE
, strlen(if_name
) + 1, if_name
);
2347 if (condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
2348 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_IP_PROTOCOL
, sizeof(policy
->cond_protocol
), &policy
->cond_protocol
);
2350 if (condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
2351 struct necp_uuid_id_mapping
*entry
= necp_uuid_lookup_uuid_with_app_id_locked(policy
->cond_app_id
);
2352 if (entry
!= NULL
) {
2353 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_APPLICATION
, sizeof(entry
->uuid
), entry
->uuid
);
2356 if (condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
2357 struct necp_uuid_id_mapping
*entry
= necp_uuid_lookup_uuid_with_app_id_locked(policy
->cond_real_app_id
);
2358 if (entry
!= NULL
) {
2359 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_REAL_APPLICATION
, sizeof(entry
->uuid
), entry
->uuid
);
2362 if (condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
2363 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_DOMAIN
, strlen(policy
->cond_domain
) + 1, policy
->cond_domain
);
2365 if (condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
2366 if (account_id_entry
!= NULL
) {
2367 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_ACCOUNT
, strlen(account_id_entry
->string
) + 1, account_id_entry
->string
);
2370 if (condition_mask
& NECP_KERNEL_CONDITION_PID
) {
2371 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_PID
, sizeof(policy
->cond_pid
), &policy
->cond_pid
);
2373 if (condition_mask
& NECP_KERNEL_CONDITION_UID
) {
2374 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_UID
, sizeof(policy
->cond_uid
), &policy
->cond_uid
);
2376 if (condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
2377 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_TRAFFIC_CLASS
, sizeof(policy
->cond_traffic_class
), &policy
->cond_traffic_class
);
2379 if (condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
) {
2380 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_ENTITLEMENT
, 0, "");
2382 if (condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) {
2383 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_ENTITLEMENT
, strlen(policy
->cond_custom_entitlement
) + 1, policy
->cond_custom_entitlement
);
2385 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
2386 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
2387 struct necp_policy_condition_addr_range range
;
2388 memcpy(&range
.start_address
, &policy
->cond_local_start
, sizeof(policy
->cond_local_start
));
2389 memcpy(&range
.end_address
, &policy
->cond_local_end
, sizeof(policy
->cond_local_end
));
2390 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE
, sizeof(range
), &range
);
2392 struct necp_policy_condition_addr addr
;
2393 addr
.prefix
= policy
->cond_local_prefix
;
2394 memcpy(&addr
.address
, &policy
->cond_local_start
, sizeof(policy
->cond_local_start
));
2395 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_LOCAL_ADDR
, sizeof(addr
), &addr
);
2398 if (condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
2399 if (condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
2400 struct necp_policy_condition_addr_range range
;
2401 memcpy(&range
.start_address
, &policy
->cond_remote_start
, sizeof(policy
->cond_remote_start
));
2402 memcpy(&range
.end_address
, &policy
->cond_remote_end
, sizeof(policy
->cond_remote_end
));
2403 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE
, sizeof(range
), &range
);
2405 struct necp_policy_condition_addr addr
;
2406 addr
.prefix
= policy
->cond_remote_prefix
;
2407 memcpy(&addr
.address
, &policy
->cond_remote_start
, sizeof(policy
->cond_remote_start
));
2408 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_REMOTE_ADDR
, sizeof(addr
), &addr
);
2413 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_CONDITION
, cond_buf_cursor
- cond_buf
, cond_buf
);
2414 if (cond_buf
!= q_cond_buf
) {
2415 FREE(cond_buf
, M_NECP
);
2418 tlv_buffer_pointers
[policy_i
] = tlv_buffer
;
2419 tlv_buffer_lengths
[policy_i
] = (cursor
- tlv_buffer
);
2421 // This is the length of the TLV for NECP_TLV_POLICY_DUMP
2422 total_tlv_len
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + (cursor
- tlv_buffer
);
2426 lck_rw_done(&necp_kernel_policy_lock
);
2428 u_int32_t total_result_length
= sizeof(struct necp_packet_header
) + total_tlv_len
;
2429 MALLOC(result_buf
, u_int8_t
*, total_result_length
, M_NECP
, M_NOWAIT
| M_ZERO
);
2430 if (result_buf
== NULL
) {
2431 NECPLOG(LOG_DEBUG
, "Failed to allocate result_buffer (%u bytes)", total_result_length
);
2432 REPORT_ERROR(NECP_ERROR_INTERNAL
);
2435 result_buf_cursor
= result_buf
;
2436 result_buf_cursor
= necp_buffer_write_packet_header(result_buf_cursor
, NECP_PACKET_TYPE_POLICY_DUMP_ALL
, NECP_PACKET_FLAGS_RESPONSE
, message_id
);
2438 for (int i
= 0; i
< policy_count
; i
++) {
2439 if (tlv_buffer_pointers
[i
] != NULL
) {
2440 result_buf_cursor
= necp_buffer_write_tlv(result_buf_cursor
, NECP_TLV_POLICY_DUMP
, tlv_buffer_lengths
[i
], tlv_buffer_pointers
[i
]);
2444 if (!necp_send_ctl_data(session
, result_buf
, result_buf_cursor
- result_buf
)) {
2445 NECPLOG(LOG_ERR
, "Failed to send response (%u bytes)", result_buf_cursor
- result_buf
);
2447 NECPLOG(LOG_ERR
, "Sent data worth %u bytes. Total result buffer length was %u bytes", result_buf_cursor
- result_buf
, total_result_length
);
2452 if (error_occured
) {
2453 if(!necp_send_error_response(session
, NECP_PACKET_TYPE_POLICY_DUMP_ALL
, message_id
, response_error
)) {
2454 NECPLOG0(LOG_ERR
, "Failed to send error response");
2456 NECPLOG0(LOG_ERR
, "Sent error response");
2460 if (result_buf
!= NULL
) {
2461 FREE(result_buf
, M_NECP
);
2464 if (tlv_buffer_pointers
!= NULL
) {
2465 for (int i
= 0; i
< policy_count
; i
++) {
2466 if (tlv_buffer_pointers
[i
] != NULL
) {
2467 FREE(tlv_buffer_pointers
[i
], M_NECP
);
2468 tlv_buffer_pointers
[i
] = NULL
;
2471 FREE(tlv_buffer_pointers
, M_NECP
);
2474 if (tlv_buffer_lengths
!= NULL
) {
2475 FREE(tlv_buffer_lengths
, M_NECP
);
2478 #undef RESET_COND_BUF
2480 #undef UNLOCK_AND_REPORT_ERROR
2483 static struct necp_session_policy
*
2484 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
)
2486 struct necp_session_policy
*new_policy
= NULL
;
2487 struct necp_session_policy
*tmp_policy
= NULL
;
2489 if (session
== NULL
|| conditions_array
== NULL
|| result
== NULL
|| result_size
== 0) {
2493 MALLOC_ZONE(new_policy
, struct necp_session_policy
*, sizeof(*new_policy
), M_NECP_SESSION_POLICY
, M_WAITOK
);
2494 if (new_policy
== NULL
) {
2498 memset(new_policy
, 0, sizeof(*new_policy
));
2499 new_policy
->applied
= FALSE
;
2500 new_policy
->pending_deletion
= FALSE
;
2501 new_policy
->pending_update
= FALSE
;
2502 new_policy
->order
= order
;
2503 new_policy
->conditions
= conditions_array
;
2504 new_policy
->conditions_size
= conditions_array_size
;
2505 new_policy
->route_rules
= route_rules_array
;
2506 new_policy
->route_rules_size
= route_rules_array_size
;
2507 new_policy
->result
= result
;
2508 new_policy
->result_size
= result_size
;
2509 new_policy
->id
= necp_policy_get_new_id();
2511 LIST_INSERT_SORTED_ASCENDING(&session
->policies
, new_policy
, chain
, order
, tmp_policy
);
2513 session
->dirty
= TRUE
;
2516 NECPLOG(LOG_DEBUG
, "Created NECP policy, order %d", order
);
2519 return (new_policy
);
2522 static struct necp_session_policy
*
2523 necp_policy_find(struct necp_session
*session
, necp_policy_id policy_id
)
2525 struct necp_session_policy
*policy
= NULL
;
2526 if (policy_id
== 0) {
2530 LIST_FOREACH(policy
, &session
->policies
, chain
) {
2531 if (policy
->id
== policy_id
) {
2539 static inline u_int8_t
2540 necp_policy_get_result_type(struct necp_session_policy
*policy
)
2542 return (policy
? necp_policy_result_get_type_from_buffer(policy
->result
, policy
->result_size
) : 0);
2545 static inline u_int32_t
2546 necp_policy_get_result_parameter_length(struct necp_session_policy
*policy
)
2548 return (policy
? necp_policy_result_get_parameter_length_from_buffer(policy
->result
, policy
->result_size
) : 0);
2552 necp_policy_get_result_parameter(struct necp_session_policy
*policy
, u_int8_t
*parameter_buffer
, u_int32_t parameter_buffer_length
)
2555 u_int32_t parameter_length
= necp_policy_result_get_parameter_length_from_buffer(policy
->result
, policy
->result_size
);
2556 if (parameter_buffer_length
>= parameter_length
) {
2557 u_int8_t
*parameter
= necp_policy_result_get_parameter_pointer_from_buffer(policy
->result
, policy
->result_size
);
2558 if (parameter
&& parameter_buffer
) {
2559 memcpy(parameter_buffer
, parameter
, parameter_length
);
2569 necp_policy_mark_for_deletion(struct necp_session
*session
, struct necp_session_policy
*policy
)
2571 if (session
== NULL
|| policy
== NULL
) {
2575 policy
->pending_deletion
= TRUE
;
2576 session
->dirty
= TRUE
;
2579 NECPLOG0(LOG_DEBUG
, "Marked NECP policy for removal");
2585 necp_policy_mark_all_for_deletion(struct necp_session
*session
)
2587 struct necp_session_policy
*policy
= NULL
;
2588 struct necp_session_policy
*temp_policy
= NULL
;
2590 LIST_FOREACH_SAFE(policy
, &session
->policies
, chain
, temp_policy
) {
2591 necp_policy_mark_for_deletion(session
, policy
);
2598 necp_policy_delete(struct necp_session
*session
, struct necp_session_policy
*policy
)
2600 if (session
== NULL
|| policy
== NULL
) {
2604 LIST_REMOVE(policy
, chain
);
2606 if (policy
->result
) {
2607 FREE(policy
->result
, M_NECP
);
2608 policy
->result
= NULL
;
2611 if (policy
->conditions
) {
2612 FREE(policy
->conditions
, M_NECP
);
2613 policy
->conditions
= NULL
;
2616 if (policy
->route_rules
) {
2617 FREE(policy
->route_rules
, M_NECP
);
2618 policy
->route_rules
= NULL
;
2621 FREE_ZONE(policy
, sizeof(*policy
), M_NECP_SESSION_POLICY
);
2624 NECPLOG0(LOG_DEBUG
, "Removed NECP policy");
2630 necp_policy_unapply(struct necp_session_policy
*policy
)
2633 if (policy
== NULL
) {
2637 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
2639 // Release local uuid mappings
2640 if (!uuid_is_null(policy
->applied_app_uuid
)) {
2641 bool removed_mapping
= FALSE
;
2642 if (necp_remove_uuid_app_id_mapping(policy
->applied_app_uuid
, &removed_mapping
, TRUE
) && removed_mapping
) {
2643 necp_uuid_app_id_mappings_dirty
= TRUE
;
2644 necp_num_uuid_app_id_mappings
--;
2646 uuid_clear(policy
->applied_app_uuid
);
2648 if (!uuid_is_null(policy
->applied_real_app_uuid
)) {
2649 necp_remove_uuid_app_id_mapping(policy
->applied_real_app_uuid
, NULL
, FALSE
);
2650 uuid_clear(policy
->applied_real_app_uuid
);
2652 if (!uuid_is_null(policy
->applied_result_uuid
)) {
2653 necp_remove_uuid_service_id_mapping(policy
->applied_result_uuid
);
2654 uuid_clear(policy
->applied_result_uuid
);
2657 // Release string mappings
2658 if (policy
->applied_account
!= NULL
) {
2659 necp_remove_string_to_id_mapping(&necp_account_id_list
, policy
->applied_account
);
2660 FREE(policy
->applied_account
, M_NECP
);
2661 policy
->applied_account
= NULL
;
2664 // Release route rule
2665 if (policy
->applied_route_rules_id
!= 0) {
2666 necp_remove_route_rule(&necp_route_rules
, policy
->applied_route_rules_id
);
2667 policy
->applied_route_rules_id
= 0;
2670 // Remove socket policies
2671 for (i
= 0; i
< MAX_KERNEL_SOCKET_POLICIES
; i
++) {
2672 if (policy
->kernel_socket_policies
[i
] != 0) {
2673 necp_kernel_socket_policy_delete(policy
->kernel_socket_policies
[i
]);
2674 policy
->kernel_socket_policies
[i
] = 0;
2678 // Remove IP output policies
2679 for (i
= 0; i
< MAX_KERNEL_IP_OUTPUT_POLICIES
; i
++) {
2680 if (policy
->kernel_ip_output_policies
[i
] != 0) {
2681 necp_kernel_ip_output_policy_delete(policy
->kernel_ip_output_policies
[i
]);
2682 policy
->kernel_ip_output_policies
[i
] = 0;
2686 policy
->applied
= FALSE
;
2691 #define NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION 0
2692 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION 1
2693 #define NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION 2
2694 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS 3
2695 struct necp_policy_result_ip_tunnel
{
2696 u_int32_t secondary_result
;
2697 char interface_name
[IFXNAMSIZ
];
2698 } __attribute__((__packed__
));
2700 struct necp_policy_result_service
{
2703 } __attribute__((__packed__
));
2706 necp_policy_apply(struct necp_session
*session
, struct necp_session_policy
*policy
)
2708 bool socket_only_conditions
= FALSE
;
2709 bool socket_ip_conditions
= FALSE
;
2711 bool socket_layer_non_id_conditions
= FALSE
;
2712 bool ip_output_layer_non_id_conditions
= FALSE
;
2713 bool ip_output_layer_non_id_only
= FALSE
;
2714 bool ip_output_layer_id_condition
= FALSE
;
2715 bool ip_output_layer_tunnel_condition_from_id
= FALSE
;
2716 bool ip_output_layer_tunnel_condition_from_non_id
= FALSE
;
2717 necp_kernel_policy_id cond_ip_output_layer_id
= NECP_KERNEL_POLICY_ID_NONE
;
2719 u_int32_t master_condition_mask
= 0;
2720 u_int32_t master_condition_negated_mask
= 0;
2721 ifnet_t cond_bound_interface
= NULL
;
2722 u_int32_t cond_account_id
= 0;
2723 char *cond_domain
= NULL
;
2724 char *cond_custom_entitlement
= NULL
;
2727 necp_app_id cond_app_id
= 0;
2728 necp_app_id cond_real_app_id
= 0;
2729 struct necp_policy_condition_tc_range cond_traffic_class
;
2730 cond_traffic_class
.start_tc
= 0;
2731 cond_traffic_class
.end_tc
= 0;
2732 u_int16_t cond_protocol
= 0;
2733 union necp_sockaddr_union cond_local_start
;
2734 union necp_sockaddr_union cond_local_end
;
2735 u_int8_t cond_local_prefix
= 0;
2736 union necp_sockaddr_union cond_remote_start
;
2737 union necp_sockaddr_union cond_remote_end
;
2738 u_int8_t cond_remote_prefix
= 0;
2739 u_int32_t offset
= 0;
2740 u_int8_t ultimate_result
= 0;
2741 u_int32_t secondary_result
= 0;
2742 necp_kernel_policy_result_parameter secondary_result_parameter
;
2743 memset(&secondary_result_parameter
, 0, sizeof(secondary_result_parameter
));
2744 u_int32_t cond_last_interface_index
= 0;
2745 necp_kernel_policy_result_parameter ultimate_result_parameter
;
2746 memset(&ultimate_result_parameter
, 0, sizeof(ultimate_result_parameter
));
2748 if (policy
== NULL
) {
2752 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
2754 // Process conditions
2755 while (offset
< policy
->conditions_size
) {
2756 u_int32_t length
= 0;
2757 u_int8_t
*value
= necp_buffer_get_tlv_value(policy
->conditions
, offset
, &length
);
2759 u_int8_t condition_type
= necp_policy_condition_get_type_from_buffer(value
, length
);
2760 u_int8_t condition_flags
= necp_policy_condition_get_flags_from_buffer(value
, length
);
2761 bool condition_is_negative
= condition_flags
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
;
2762 u_int32_t condition_length
= necp_policy_condition_get_value_length_from_buffer(value
, length
);
2763 u_int8_t
*condition_value
= necp_policy_condition_get_value_pointer_from_buffer(value
, length
);
2764 switch (condition_type
) {
2765 case NECP_POLICY_CONDITION_DEFAULT
: {
2766 socket_ip_conditions
= TRUE
;
2769 case NECP_POLICY_CONDITION_ALL_INTERFACES
: {
2770 master_condition_mask
|= NECP_KERNEL_CONDITION_ALL_INTERFACES
;
2771 socket_ip_conditions
= TRUE
;
2774 case NECP_POLICY_CONDITION_ENTITLEMENT
: {
2775 if (condition_length
> 0) {
2776 if (cond_custom_entitlement
== NULL
) {
2777 cond_custom_entitlement
= necp_copy_string((char *)condition_value
, condition_length
);
2778 if (cond_custom_entitlement
!= NULL
) {
2779 master_condition_mask
|= NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
;
2780 socket_only_conditions
= TRUE
;
2784 master_condition_mask
|= NECP_KERNEL_CONDITION_ENTITLEMENT
;
2785 socket_only_conditions
= TRUE
;
2789 case NECP_POLICY_CONDITION_DOMAIN
: {
2790 // Make sure there is only one such rule
2791 if (condition_length
> 0 && cond_domain
== NULL
) {
2792 cond_domain
= necp_create_trimmed_domain((char *)condition_value
, condition_length
);
2793 if (cond_domain
!= NULL
) {
2794 master_condition_mask
|= NECP_KERNEL_CONDITION_DOMAIN
;
2795 if (condition_is_negative
) {
2796 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_DOMAIN
;
2798 socket_only_conditions
= TRUE
;
2803 case NECP_POLICY_CONDITION_ACCOUNT
: {
2804 // Make sure there is only one such rule
2805 if (condition_length
> 0 && cond_account_id
== 0 && policy
->applied_account
== NULL
) {
2806 char *string
= NULL
;
2807 MALLOC(string
, char *, condition_length
+ 1, M_NECP
, M_WAITOK
);
2808 if (string
!= NULL
) {
2809 memcpy(string
, condition_value
, condition_length
);
2810 string
[condition_length
] = 0;
2811 cond_account_id
= necp_create_string_to_id_mapping(&necp_account_id_list
, string
);
2812 if (cond_account_id
!= 0) {
2813 policy
->applied_account
= string
; // Save the string in parent policy
2814 master_condition_mask
|= NECP_KERNEL_CONDITION_ACCOUNT_ID
;
2815 if (condition_is_negative
) {
2816 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_ACCOUNT_ID
;
2818 socket_only_conditions
= TRUE
;
2820 FREE(string
, M_NECP
);
2826 case NECP_POLICY_CONDITION_APPLICATION
: {
2827 // Make sure there is only one such rule, because we save the uuid in the policy
2828 if (condition_length
>= sizeof(uuid_t
) && cond_app_id
== 0) {
2829 bool allocated_mapping
= FALSE
;
2830 uuid_t application_uuid
;
2831 memcpy(application_uuid
, condition_value
, sizeof(uuid_t
));
2832 cond_app_id
= necp_create_uuid_app_id_mapping(application_uuid
, &allocated_mapping
, TRUE
);
2833 if (cond_app_id
!= 0) {
2834 if (allocated_mapping
) {
2835 necp_uuid_app_id_mappings_dirty
= TRUE
;
2836 necp_num_uuid_app_id_mappings
++;
2838 uuid_copy(policy
->applied_app_uuid
, application_uuid
);
2839 master_condition_mask
|= NECP_KERNEL_CONDITION_APP_ID
;
2840 if (condition_is_negative
) {
2841 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_APP_ID
;
2843 socket_only_conditions
= TRUE
;
2848 case NECP_POLICY_CONDITION_REAL_APPLICATION
: {
2849 // Make sure there is only one such rule, because we save the uuid in the policy
2850 if (condition_length
>= sizeof(uuid_t
) && cond_real_app_id
== 0) {
2851 uuid_t real_application_uuid
;
2852 memcpy(real_application_uuid
, condition_value
, sizeof(uuid_t
));
2853 cond_real_app_id
= necp_create_uuid_app_id_mapping(real_application_uuid
, NULL
, FALSE
);
2854 if (cond_real_app_id
!= 0) {
2855 uuid_copy(policy
->applied_real_app_uuid
, real_application_uuid
);
2856 master_condition_mask
|= NECP_KERNEL_CONDITION_REAL_APP_ID
;
2857 if (condition_is_negative
) {
2858 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REAL_APP_ID
;
2860 socket_only_conditions
= TRUE
;
2865 case NECP_POLICY_CONDITION_PID
: {
2866 if (condition_length
>= sizeof(pid_t
)) {
2867 master_condition_mask
|= NECP_KERNEL_CONDITION_PID
;
2868 if (condition_is_negative
) {
2869 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_PID
;
2871 memcpy(&cond_pid
, condition_value
, sizeof(cond_pid
));
2872 socket_only_conditions
= TRUE
;
2876 case NECP_POLICY_CONDITION_UID
: {
2877 if (condition_length
>= sizeof(uid_t
)) {
2878 master_condition_mask
|= NECP_KERNEL_CONDITION_UID
;
2879 if (condition_is_negative
) {
2880 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_UID
;
2882 memcpy(&cond_uid
, condition_value
, sizeof(cond_uid
));
2883 socket_only_conditions
= TRUE
;
2887 case NECP_POLICY_CONDITION_TRAFFIC_CLASS
: {
2888 if (condition_length
>= sizeof(struct necp_policy_condition_tc_range
)) {
2889 master_condition_mask
|= NECP_KERNEL_CONDITION_TRAFFIC_CLASS
;
2890 if (condition_is_negative
) {
2891 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_TRAFFIC_CLASS
;
2893 memcpy(&cond_traffic_class
, condition_value
, sizeof(cond_traffic_class
));
2894 socket_only_conditions
= TRUE
;
2898 case NECP_POLICY_CONDITION_BOUND_INTERFACE
: {
2899 if (condition_length
<= IFXNAMSIZ
&& condition_length
> 0) {
2900 char interface_name
[IFXNAMSIZ
];
2901 memcpy(interface_name
, condition_value
, condition_length
);
2902 interface_name
[condition_length
- 1] = 0; // Make sure the string is NULL terminated
2903 if (ifnet_find_by_name(interface_name
, &cond_bound_interface
) == 0) {
2904 master_condition_mask
|= NECP_KERNEL_CONDITION_BOUND_INTERFACE
;
2905 if (condition_is_negative
) {
2906 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_BOUND_INTERFACE
;
2909 socket_ip_conditions
= TRUE
;
2913 case NECP_POLICY_CONDITION_IP_PROTOCOL
: {
2914 if (condition_length
>= sizeof(u_int16_t
)) {
2915 master_condition_mask
|= NECP_KERNEL_CONDITION_PROTOCOL
;
2916 if (condition_is_negative
) {
2917 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_PROTOCOL
;
2919 memcpy(&cond_protocol
, condition_value
, sizeof(cond_protocol
));
2920 socket_ip_conditions
= TRUE
;
2924 case NECP_POLICY_CONDITION_LOCAL_ADDR
: {
2925 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)condition_value
;
2926 if (!necp_address_is_valid(&address_struct
->address
.sa
)) {
2930 cond_local_prefix
= address_struct
->prefix
;
2931 memcpy(&cond_local_start
, &address_struct
->address
, sizeof(address_struct
->address
));
2932 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_START
;
2933 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_PREFIX
;
2934 if (condition_is_negative
) {
2935 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_START
;
2936 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_PREFIX
;
2938 socket_ip_conditions
= TRUE
;
2941 case NECP_POLICY_CONDITION_REMOTE_ADDR
: {
2942 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)condition_value
;
2943 if (!necp_address_is_valid(&address_struct
->address
.sa
)) {
2947 cond_remote_prefix
= address_struct
->prefix
;
2948 memcpy(&cond_remote_start
, &address_struct
->address
, sizeof(address_struct
->address
));
2949 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_START
;
2950 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_PREFIX
;
2951 if (condition_is_negative
) {
2952 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_START
;
2953 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_PREFIX
;
2955 socket_ip_conditions
= TRUE
;
2958 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE
: {
2959 struct necp_policy_condition_addr_range
*address_struct
= (struct necp_policy_condition_addr_range
*)(void *)condition_value
;
2960 if (!necp_address_is_valid(&address_struct
->start_address
.sa
) ||
2961 !necp_address_is_valid(&address_struct
->end_address
.sa
)) {
2965 memcpy(&cond_local_start
, &address_struct
->start_address
, sizeof(address_struct
->start_address
));
2966 memcpy(&cond_local_end
, &address_struct
->end_address
, sizeof(address_struct
->end_address
));
2967 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_START
;
2968 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_END
;
2969 if (condition_is_negative
) {
2970 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_START
;
2971 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_END
;
2973 socket_ip_conditions
= TRUE
;
2976 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE
: {
2977 struct necp_policy_condition_addr_range
*address_struct
= (struct necp_policy_condition_addr_range
*)(void *)condition_value
;
2978 if (!necp_address_is_valid(&address_struct
->start_address
.sa
) ||
2979 !necp_address_is_valid(&address_struct
->end_address
.sa
)) {
2983 memcpy(&cond_remote_start
, &address_struct
->start_address
, sizeof(address_struct
->start_address
));
2984 memcpy(&cond_remote_end
, &address_struct
->end_address
, sizeof(address_struct
->end_address
));
2985 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_START
;
2986 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_END
;
2987 if (condition_is_negative
) {
2988 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_START
;
2989 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_END
;
2991 socket_ip_conditions
= TRUE
;
2999 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
3003 ultimate_result
= necp_policy_get_result_type(policy
);
3004 switch (ultimate_result
) {
3005 case NECP_POLICY_RESULT_PASS
: {
3006 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
3007 socket_layer_non_id_conditions
= TRUE
;
3008 ip_output_layer_id_condition
= TRUE
;
3009 } else if (socket_ip_conditions
) {
3010 socket_layer_non_id_conditions
= TRUE
;
3011 ip_output_layer_id_condition
= TRUE
;
3012 ip_output_layer_non_id_conditions
= TRUE
;
3016 case NECP_POLICY_RESULT_DROP
: {
3017 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
3018 socket_layer_non_id_conditions
= TRUE
;
3019 } else if (socket_ip_conditions
) {
3020 socket_layer_non_id_conditions
= TRUE
;
3021 ip_output_layer_non_id_conditions
= TRUE
;
3022 ip_output_layer_non_id_only
= TRUE
; // Only apply drop to packets that didn't go through socket layer
3026 case NECP_POLICY_RESULT_SKIP
: {
3027 u_int32_t skip_policy_order
= 0;
3028 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&skip_policy_order
, sizeof(skip_policy_order
))) {
3029 ultimate_result_parameter
.skip_policy_order
= skip_policy_order
;
3032 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
3033 socket_layer_non_id_conditions
= TRUE
;
3034 ip_output_layer_id_condition
= TRUE
;
3035 } else if (socket_ip_conditions
) {
3036 socket_layer_non_id_conditions
= TRUE
;
3037 ip_output_layer_non_id_conditions
= TRUE
;
3041 case NECP_POLICY_RESULT_SOCKET_DIVERT
:
3042 case NECP_POLICY_RESULT_SOCKET_FILTER
: {
3043 u_int32_t control_unit
= 0;
3044 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&control_unit
, sizeof(control_unit
))) {
3045 ultimate_result_parameter
.flow_divert_control_unit
= control_unit
;
3047 socket_layer_non_id_conditions
= TRUE
;
3050 case NECP_POLICY_RESULT_IP_TUNNEL
: {
3051 struct necp_policy_result_ip_tunnel tunnel_parameters
;
3052 u_int32_t tunnel_parameters_length
= necp_policy_get_result_parameter_length(policy
);
3053 if (tunnel_parameters_length
> sizeof(u_int32_t
) &&
3054 tunnel_parameters_length
<= sizeof(struct necp_policy_result_ip_tunnel
) &&
3055 necp_policy_get_result_parameter(policy
, (u_int8_t
*)&tunnel_parameters
, sizeof(tunnel_parameters
))) {
3056 ifnet_t tunnel_interface
= NULL
;
3057 tunnel_parameters
.interface_name
[tunnel_parameters_length
- sizeof(u_int32_t
) - 1] = 0; // Make sure the string is NULL terminated
3058 if (ifnet_find_by_name(tunnel_parameters
.interface_name
, &tunnel_interface
) == 0) {
3059 ultimate_result_parameter
.tunnel_interface_index
= tunnel_interface
->if_index
;
3060 ifnet_release(tunnel_interface
);
3063 secondary_result
= tunnel_parameters
.secondary_result
;
3064 if (secondary_result
) {
3065 cond_last_interface_index
= ultimate_result_parameter
.tunnel_interface_index
;
3069 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
3070 socket_layer_non_id_conditions
= TRUE
;
3071 ip_output_layer_id_condition
= TRUE
;
3072 if (secondary_result
) {
3073 ip_output_layer_tunnel_condition_from_id
= TRUE
;
3075 } else if (socket_ip_conditions
) {
3076 socket_layer_non_id_conditions
= TRUE
;
3077 ip_output_layer_id_condition
= TRUE
;
3078 ip_output_layer_non_id_conditions
= TRUE
;
3079 if (secondary_result
) {
3080 ip_output_layer_tunnel_condition_from_id
= TRUE
;
3081 ip_output_layer_tunnel_condition_from_non_id
= TRUE
;
3086 case NECP_POLICY_RESULT_TRIGGER
:
3087 case NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
:
3088 case NECP_POLICY_RESULT_TRIGGER_SCOPED
:
3089 case NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
: {
3090 struct necp_policy_result_service service_parameters
;
3091 u_int32_t service_result_length
= necp_policy_get_result_parameter_length(policy
);
3092 bool has_extra_service_data
= FALSE
;
3093 if (service_result_length
>= (sizeof(service_parameters
))) {
3094 has_extra_service_data
= TRUE
;
3096 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&service_parameters
, sizeof(service_parameters
))) {
3097 ultimate_result_parameter
.service
.identifier
= necp_create_uuid_service_id_mapping(service_parameters
.identifier
);
3098 if (ultimate_result_parameter
.service
.identifier
!= 0) {
3099 uuid_copy(policy
->applied_result_uuid
, service_parameters
.identifier
);
3100 socket_layer_non_id_conditions
= TRUE
;
3101 if (has_extra_service_data
) {
3102 ultimate_result_parameter
.service
.data
= service_parameters
.data
;
3104 ultimate_result_parameter
.service
.data
= 0;
3110 case NECP_POLICY_RESULT_USE_NETAGENT
: {
3111 uuid_t netagent_uuid
;
3112 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&netagent_uuid
, sizeof(netagent_uuid
))) {
3113 ultimate_result_parameter
.netagent_id
= necp_create_uuid_service_id_mapping(netagent_uuid
);
3114 if (ultimate_result_parameter
.netagent_id
!= 0) {
3115 uuid_copy(policy
->applied_result_uuid
, netagent_uuid
);
3116 socket_layer_non_id_conditions
= TRUE
;
3121 case NECP_POLICY_RESULT_SOCKET_SCOPED
: {
3122 u_int32_t interface_name_length
= necp_policy_get_result_parameter_length(policy
);
3123 if (interface_name_length
<= IFXNAMSIZ
&& interface_name_length
> 0) {
3124 char interface_name
[IFXNAMSIZ
];
3125 ifnet_t scope_interface
= NULL
;
3126 necp_policy_get_result_parameter(policy
, (u_int8_t
*)interface_name
, interface_name_length
);
3127 interface_name
[interface_name_length
- 1] = 0; // Make sure the string is NULL terminated
3128 if (ifnet_find_by_name(interface_name
, &scope_interface
) == 0) {
3129 ultimate_result_parameter
.scoped_interface_index
= scope_interface
->if_index
;
3130 socket_layer_non_id_conditions
= TRUE
;
3131 ifnet_release(scope_interface
);
3136 case NECP_POLICY_RESULT_ROUTE_RULES
: {
3137 if (policy
->route_rules
!= NULL
&& policy
->route_rules_size
> 0) {
3138 u_int32_t route_rule_id
= necp_create_route_rule(&necp_route_rules
, policy
->route_rules
, policy
->route_rules_size
);
3139 if (route_rule_id
> 0) {
3140 policy
->applied_route_rules_id
= route_rule_id
;
3141 ultimate_result_parameter
.route_rule_id
= route_rule_id
;
3142 socket_layer_non_id_conditions
= TRUE
;
3152 if (socket_layer_non_id_conditions
) {
3153 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
);
3155 if (policy_id
== 0) {
3156 NECPLOG0(LOG_DEBUG
, "Error applying socket kernel policy");
3160 cond_ip_output_layer_id
= policy_id
;
3161 policy
->kernel_socket_policies
[0] = policy_id
;
3164 if (ip_output_layer_non_id_conditions
) {
3165 u_int32_t condition_mask
= master_condition_mask
;
3166 if (ip_output_layer_non_id_only
) {
3167 condition_mask
|= NECP_KERNEL_CONDITION_POLICY_ID
;
3169 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
);
3171 if (policy_id
== 0) {
3172 NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy");
3176 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS
] = policy_id
;
3179 if (ip_output_layer_id_condition
) {
3180 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
);
3182 if (policy_id
== 0) {
3183 NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy");
3187 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION
] = policy_id
;
3190 // Extra policies for IP Output tunnels for when packets loop back
3191 if (ip_output_layer_tunnel_condition_from_id
) {
3192 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
);
3194 if (policy_id
== 0) {
3195 NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy");
3199 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION
] = policy_id
;
3202 if (ip_output_layer_tunnel_condition_from_id
) {
3203 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
);
3205 if (policy_id
== 0) {
3206 NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy");
3210 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION
] = policy_id
;
3213 policy
->applied
= TRUE
;
3214 policy
->pending_update
= FALSE
;
3222 necp_policy_apply_all(struct necp_session
*session
)
3224 struct necp_session_policy
*policy
= NULL
;
3225 struct necp_session_policy
*temp_policy
= NULL
;
3226 struct kev_necp_policies_changed_data kev_data
;
3227 kev_data
.changed_count
= 0;
3229 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
3231 // Remove exisiting applied policies
3232 if (session
->dirty
) {
3233 LIST_FOREACH_SAFE(policy
, &session
->policies
, chain
, temp_policy
) {
3234 if (policy
->pending_deletion
) {
3235 if (policy
->applied
) {
3236 necp_policy_unapply(policy
);
3238 // Delete the policy
3239 necp_policy_delete(session
, policy
);
3240 } else if (!policy
->applied
) {
3241 necp_policy_apply(session
, policy
);
3242 } else if (policy
->pending_update
) {
3243 // Must have been applied, but needs an update. Remove and re-add.
3244 necp_policy_unapply(policy
);
3245 necp_policy_apply(session
, policy
);
3249 necp_kernel_socket_policies_update_uuid_table();
3250 necp_kernel_socket_policies_reprocess();
3251 necp_kernel_ip_output_policies_reprocess();
3253 // Clear dirty bit flags
3254 session
->dirty
= FALSE
;
3257 lck_rw_done(&necp_kernel_policy_lock
);
3259 necp_update_all_clients();
3260 necp_post_change_event(&kev_data
);
3263 NECPLOG0(LOG_DEBUG
, "Applied NECP policies");
3267 // Kernel Policy Management
3268 // ---------------------
3269 // Kernel policies are derived from session policies
3270 static necp_kernel_policy_id
3271 necp_kernel_policy_get_new_id(void)
3273 necp_kernel_policy_id newid
= NECP_KERNEL_POLICY_ID_NONE
;
3275 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
3277 necp_last_kernel_policy_id
++;
3278 if (necp_last_kernel_policy_id
< NECP_KERNEL_POLICY_ID_FIRST_VALID
) {
3279 necp_last_kernel_policy_id
= NECP_KERNEL_POLICY_ID_FIRST_VALID
;
3282 newid
= necp_last_kernel_policy_id
;
3283 if (newid
== NECP_KERNEL_POLICY_ID_NONE
) {
3284 NECPLOG0(LOG_DEBUG
, "Allocate kernel policy id failed.\n");
3291 #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)
3292 static necp_kernel_policy_id
3293 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
)
3295 struct necp_kernel_socket_policy
*new_kernel_policy
= NULL
;
3296 struct necp_kernel_socket_policy
*tmp_kernel_policy
= NULL
;
3298 MALLOC_ZONE(new_kernel_policy
, struct necp_kernel_socket_policy
*, sizeof(*new_kernel_policy
), M_NECP_SOCKET_POLICY
, M_WAITOK
);
3299 if (new_kernel_policy
== NULL
) {
3303 memset(new_kernel_policy
, 0, sizeof(*new_kernel_policy
));
3304 new_kernel_policy
->parent_policy_id
= parent_policy_id
;
3305 new_kernel_policy
->id
= necp_kernel_policy_get_new_id();
3306 new_kernel_policy
->order
= order
;
3307 new_kernel_policy
->session_order
= session_order
;
3308 new_kernel_policy
->session_pid
= session_pid
;
3310 // Sanitize condition mask
3311 new_kernel_policy
->condition_mask
= (condition_mask
& NECP_KERNEL_VALID_SOCKET_CONDITIONS
);
3312 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
)) {
3313 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE
;
3315 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) && !(new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
)) {
3316 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_REAL_APP_ID
;
3318 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
) && !(new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
)) {
3319 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_ENTITLEMENT
;
3321 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
)) {
3322 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX
;
3324 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
)) {
3325 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX
;
3327 new_kernel_policy
->condition_negated_mask
= condition_negated_mask
& new_kernel_policy
->condition_mask
;
3329 // Set condition values
3330 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
3331 new_kernel_policy
->cond_app_id
= cond_app_id
;
3333 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
3334 new_kernel_policy
->cond_real_app_id
= cond_real_app_id
;
3336 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) {
3337 new_kernel_policy
->cond_custom_entitlement
= cond_custom_entitlement
;
3338 new_kernel_policy
->cond_custom_entitlement_matched
= necp_boolean_state_unknown
;
3340 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
3341 new_kernel_policy
->cond_account_id
= cond_account_id
;
3343 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
3344 new_kernel_policy
->cond_domain
= cond_domain
;
3345 new_kernel_policy
->cond_domain_dot_count
= necp_count_dots(cond_domain
, strlen(cond_domain
));
3347 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PID
) {
3348 new_kernel_policy
->cond_pid
= cond_pid
;
3350 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_UID
) {
3351 new_kernel_policy
->cond_uid
= cond_uid
;
3353 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
3354 if (cond_bound_interface
) {
3355 ifnet_reference(cond_bound_interface
);
3357 new_kernel_policy
->cond_bound_interface
= cond_bound_interface
;
3359 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
3360 new_kernel_policy
->cond_traffic_class
= cond_traffic_class
;
3362 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
3363 new_kernel_policy
->cond_protocol
= cond_protocol
;
3365 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
3366 memcpy(&new_kernel_policy
->cond_local_start
, cond_local_start
, cond_local_start
->sa
.sa_len
);
3368 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
3369 memcpy(&new_kernel_policy
->cond_local_end
, cond_local_end
, cond_local_end
->sa
.sa_len
);
3371 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
3372 new_kernel_policy
->cond_local_prefix
= cond_local_prefix
;
3374 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
3375 memcpy(&new_kernel_policy
->cond_remote_start
, cond_remote_start
, cond_remote_start
->sa
.sa_len
);
3377 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
3378 memcpy(&new_kernel_policy
->cond_remote_end
, cond_remote_end
, cond_remote_end
->sa
.sa_len
);
3380 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
3381 new_kernel_policy
->cond_remote_prefix
= cond_remote_prefix
;
3384 new_kernel_policy
->result
= result
;
3385 memcpy(&new_kernel_policy
->result_parameter
, &result_parameter
, sizeof(result_parameter
));
3388 NECPLOG(LOG_DEBUG
, "Added kernel policy: socket, id=%d, mask=%x\n", new_kernel_policy
->id
, new_kernel_policy
->condition_mask
);
3390 LIST_INSERT_SORTED_TWICE_ASCENDING(&necp_kernel_socket_policies
, new_kernel_policy
, chain
, session_order
, order
, tmp_kernel_policy
);
3392 return (new_kernel_policy
? new_kernel_policy
->id
: 0);
3395 static struct necp_kernel_socket_policy
*
3396 necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id
)
3398 struct necp_kernel_socket_policy
*kernel_policy
= NULL
;
3399 struct necp_kernel_socket_policy
*tmp_kernel_policy
= NULL
;
3401 if (policy_id
== 0) {
3405 LIST_FOREACH_SAFE(kernel_policy
, &necp_kernel_socket_policies
, chain
, tmp_kernel_policy
) {
3406 if (kernel_policy
->id
== policy_id
) {
3407 return (kernel_policy
);
3415 necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id
)
3417 struct necp_kernel_socket_policy
*policy
= NULL
;
3419 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
3421 policy
= necp_kernel_socket_policy_find(policy_id
);
3423 LIST_REMOVE(policy
, chain
);
3425 if (policy
->cond_bound_interface
) {
3426 ifnet_release(policy
->cond_bound_interface
);
3427 policy
->cond_bound_interface
= NULL
;
3430 if (policy
->cond_domain
) {
3431 FREE(policy
->cond_domain
, M_NECP
);
3432 policy
->cond_domain
= NULL
;
3435 if (policy
->cond_custom_entitlement
) {
3436 FREE(policy
->cond_custom_entitlement
, M_NECP
);
3437 policy
->cond_custom_entitlement
= NULL
;
3440 FREE_ZONE(policy
, sizeof(*policy
), M_NECP_SOCKET_POLICY
);
3447 static inline const char *
3448 necp_get_result_description(char *result_string
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
)
3450 uuid_string_t uuid_string
;
3452 case NECP_KERNEL_POLICY_RESULT_NONE
: {
3453 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "None");
3456 case NECP_KERNEL_POLICY_RESULT_PASS
: {
3457 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Pass");
3460 case NECP_KERNEL_POLICY_RESULT_SKIP
: {
3461 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Skip (%u)", result_parameter
.skip_policy_order
);
3464 case NECP_KERNEL_POLICY_RESULT_DROP
: {
3465 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Drop");
3468 case NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
: {
3469 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "SocketDivert (%d)", result_parameter
.flow_divert_control_unit
);
3472 case NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER
: {
3473 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "SocketFilter (%d)", result_parameter
.filter_control_unit
);
3476 case NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
: {
3477 ifnet_t interface
= ifindex2ifnet
[result_parameter
.tunnel_interface_index
];
3478 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "IPTunnel (%s%d)", ifnet_name(interface
), ifnet_unit(interface
));
3481 case NECP_KERNEL_POLICY_RESULT_IP_FILTER
: {
3482 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "IPFilter");
3485 case NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
: {
3486 ifnet_t interface
= ifindex2ifnet
[result_parameter
.scoped_interface_index
];
3487 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "SocketScoped (%s%d)", ifnet_name(interface
), ifnet_unit(interface
));
3490 case NECP_KERNEL_POLICY_RESULT_ROUTE_RULES
: {
3492 char interface_names
[IFXNAMSIZ
][MAX_ROUTE_RULE_INTERFACES
];
3493 struct necp_route_rule
*route_rule
= necp_lookup_route_rule_locked(&necp_route_rules
, result_parameter
.route_rule_id
);
3494 if (route_rule
!= NULL
) {
3495 for (index
= 0; index
< MAX_ROUTE_RULE_INTERFACES
; index
++) {
3496 if (route_rule
->exception_if_indices
[index
] != 0) {
3497 ifnet_t interface
= ifindex2ifnet
[route_rule
->exception_if_indices
[index
]];
3498 snprintf(interface_names
[index
], IFXNAMSIZ
, "%s%d", ifnet_name(interface
), ifnet_unit(interface
));
3500 memset(interface_names
[index
], 0, IFXNAMSIZ
);
3503 switch (route_rule
->default_action
) {
3504 case NECP_ROUTE_RULE_DENY_INTERFACE
:
3505 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)",
3506 (route_rule
->cellular_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "Cell " : "",
3507 (route_rule
->wifi_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "WiFi " : "",
3508 (route_rule
->wired_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "Wired " : "",
3509 (route_rule
->expensive_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "Exp " : "",
3510 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[0] : "",
3511 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
3512 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[1] : "",
3513 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
3514 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[2] : "",
3515 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
3516 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[3] : "",
3517 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
3518 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[4] : "",
3519 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
3520 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[5] : "",
3521 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
3522 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[6] : "",
3523 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
3524 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[7] : "",
3525 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
3526 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[8] : "",
3527 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
3528 (route_rule
->exception_if_actions
[9] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[9] : "");
3530 case NECP_ROUTE_RULE_ALLOW_INTERFACE
:
3531 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)",
3532 (route_rule
->cellular_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!Cell " : "",
3533 (route_rule
->wifi_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!WiFi " : "",
3534 (route_rule
->wired_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!Wired " : "",
3535 (route_rule
->expensive_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!Exp " : "",
3536 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
3537 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[0] : "",
3538 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
3539 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[1] : "",
3540 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
3541 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[2] : "",
3542 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
3543 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[3] : "",
3544 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
3545 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[4] : "",
3546 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
3547 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[5] : "",
3548 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
3549 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[6] : "",
3550 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
3551 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[7] : "",
3552 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
3553 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[8] : "",
3554 (route_rule
->exception_if_actions
[9] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
3555 (route_rule
->exception_if_actions
[9] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[9] : "");
3557 case NECP_ROUTE_RULE_QOS_MARKING
:
3558 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)",
3559 (route_rule
->cellular_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? "Cell " : "",
3560 (route_rule
->wifi_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? "WiFi " : "",
3561 (route_rule
->wired_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? "Wired " : "",
3562 (route_rule
->expensive_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? "Exp " : "",
3563 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[0] : "",
3564 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
3565 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[1] : "",
3566 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
3567 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[2] : "",
3568 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
3569 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[3] : "",
3570 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
3571 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[4] : "",
3572 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
3573 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[5] : "",
3574 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
3575 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[6] : "",
3576 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
3577 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[7] : "",
3578 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
3579 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[8] : "",
3580 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
3581 (route_rule
->exception_if_actions
[9] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[9] : "");
3584 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "RouteRules (Unknown)");
3590 case NECP_KERNEL_POLICY_RESULT_USE_NETAGENT
: {
3591 bool found_mapping
= FALSE
;
3592 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.netagent_id
);
3593 if (mapping
!= NULL
) {
3594 uuid_unparse(mapping
->uuid
, uuid_string
);
3595 found_mapping
= TRUE
;
3597 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "UseNetAgent (%s)", found_mapping
? uuid_string
: "Unknown");
3600 case NECP_POLICY_RESULT_TRIGGER
: {
3601 bool found_mapping
= FALSE
;
3602 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.service
.identifier
);
3603 if (mapping
!= NULL
) {
3604 uuid_unparse(mapping
->uuid
, uuid_string
);
3605 found_mapping
= TRUE
;
3607 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Trigger (%s.%d)", found_mapping
? uuid_string
: "Unknown", result_parameter
.service
.data
);
3610 case NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
: {
3611 bool found_mapping
= FALSE
;
3612 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.service
.identifier
);
3613 if (mapping
!= NULL
) {
3614 uuid_unparse(mapping
->uuid
, uuid_string
);
3615 found_mapping
= TRUE
;
3617 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "TriggerIfNeeded (%s.%d)", found_mapping
? uuid_string
: "Unknown", result_parameter
.service
.data
);
3620 case NECP_POLICY_RESULT_TRIGGER_SCOPED
: {
3621 bool found_mapping
= FALSE
;
3622 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.service
.identifier
);
3623 if (mapping
!= NULL
) {
3624 uuid_unparse(mapping
->uuid
, uuid_string
);
3625 found_mapping
= TRUE
;
3627 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "TriggerScoped (%s.%d)", found_mapping
? uuid_string
: "Unknown", result_parameter
.service
.data
);
3630 case NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
: {
3631 bool found_mapping
= FALSE
;
3632 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.service
.identifier
);
3633 if (mapping
!= NULL
) {
3634 uuid_unparse(mapping
->uuid
, uuid_string
);
3635 found_mapping
= TRUE
;
3637 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "NoTriggerScoped (%s.%d)", found_mapping
? uuid_string
: "Unknown", result_parameter
.service
.data
);
3641 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Unknown %d (%d)", result
, result_parameter
.tunnel_interface_index
);
3645 return (result_string
);
3649 necp_kernel_socket_policies_dump_all(void)
3652 struct necp_kernel_socket_policy
*policy
= NULL
;
3655 char result_string
[MAX_RESULT_STRING_LEN
];
3656 char proc_name_string
[MAXCOMLEN
+ 1];
3657 memset(result_string
, 0, MAX_RESULT_STRING_LEN
);
3658 memset(proc_name_string
, 0, MAXCOMLEN
+ 1);
3660 NECPLOG0(LOG_DEBUG
, "NECP Application Policies:\n");
3661 NECPLOG0(LOG_DEBUG
, "-----------\n");
3662 for (policy_i
= 0; necp_kernel_socket_policies_app_layer_map
!= NULL
&& necp_kernel_socket_policies_app_layer_map
[policy_i
] != NULL
; policy_i
++) {
3663 policy
= necp_kernel_socket_policies_app_layer_map
[policy_i
];
3664 proc_name(policy
->session_pid
, proc_name_string
, MAXCOMLEN
);
3665 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
));
3667 if (necp_kernel_socket_policies_app_layer_map
[0] != NULL
) {
3668 NECPLOG0(LOG_DEBUG
, "-----------\n");
3671 NECPLOG0(LOG_DEBUG
, "NECP Socket Policies:\n");
3672 NECPLOG0(LOG_DEBUG
, "-----------\n");
3673 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
3674 NECPLOG(LOG_DEBUG
, "\tApp Bucket: %d\n", app_i
);
3675 for (policy_i
= 0; necp_kernel_socket_policies_map
[app_i
] != NULL
&& (necp_kernel_socket_policies_map
[app_i
])[policy_i
] != NULL
; policy_i
++) {
3676 policy
= (necp_kernel_socket_policies_map
[app_i
])[policy_i
];
3677 proc_name(policy
->session_pid
, proc_name_string
, MAXCOMLEN
);
3678 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
));
3680 NECPLOG0(LOG_DEBUG
, "-----------\n");
3686 necp_kernel_socket_result_is_trigger_service_type(struct necp_kernel_socket_policy
*kernel_policy
)
3688 return (kernel_policy
->result
>= NECP_KERNEL_POLICY_RESULT_TRIGGER
&& kernel_policy
->result
<= NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED
);
3692 necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy
*upper_policy
, struct necp_kernel_socket_policy
*lower_policy
)
3694 if (upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_DROP
) {
3695 // Drop always cancels out lower policies
3697 } else if (upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER
||
3698 upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_ROUTE_RULES
||
3699 upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_USE_NETAGENT
) {
3700 // Filters and route rules never cancel out lower policies
3702 } else if (necp_kernel_socket_result_is_trigger_service_type(upper_policy
)) {
3703 // Trigger/Scoping policies can overlap one another, but not other results
3704 return (necp_kernel_socket_result_is_trigger_service_type(lower_policy
));
3705 } else if (upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
3706 if (upper_policy
->session_order
!= lower_policy
->session_order
) {
3707 // A skip cannot override a policy of a different session
3710 if (upper_policy
->result_parameter
.skip_policy_order
== 0 ||
3711 lower_policy
->order
>= upper_policy
->result_parameter
.skip_policy_order
) {
3712 // This policy is beyond the skip
3715 // This policy is inside the skip
3721 // A hard pass, flow divert, tunnel, or scope will currently block out lower policies
3726 necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy
*policy
, struct necp_kernel_socket_policy
**policy_array
, int valid_indices
)
3728 bool can_skip
= FALSE
;
3729 u_int32_t highest_skip_session_order
= 0;
3730 u_int32_t highest_skip_order
= 0;
3732 for (i
= 0; i
< valid_indices
; i
++) {
3733 struct necp_kernel_socket_policy
*compared_policy
= policy_array
[i
];
3735 // For policies in a skip window, we can't mark conflicting policies as unnecessary
3737 if (highest_skip_session_order
!= compared_policy
->session_order
||
3738 (highest_skip_order
!= 0 && compared_policy
->order
>= highest_skip_order
)) {
3739 // If we've moved on to the next session, or passed the skip window
3740 highest_skip_session_order
= 0;
3741 highest_skip_order
= 0;
3744 // If this policy is also a skip, in can increase the skip window
3745 if (compared_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
3746 if (compared_policy
->result_parameter
.skip_policy_order
> highest_skip_order
) {
3747 highest_skip_order
= compared_policy
->result_parameter
.skip_policy_order
;
3754 if (compared_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
3755 // This policy is a skip. Set the skip window accordingly
3757 highest_skip_session_order
= compared_policy
->session_order
;
3758 highest_skip_order
= compared_policy
->result_parameter
.skip_policy_order
;
3761 // The result of the compared policy must be able to block out this policy result
3762 if (!necp_kernel_socket_policy_results_overlap(compared_policy
, policy
)) {
3766 // If new policy matches All Interfaces, compared policy must also
3767 if ((policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && !(compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) {
3771 // Default makes lower policies unecessary always
3772 if (compared_policy
->condition_mask
== 0) {
3776 // Compared must be more general than policy, and include only conditions within policy
3777 if ((policy
->condition_mask
& compared_policy
->condition_mask
) != compared_policy
->condition_mask
) {
3781 // Negative conditions must match for the overlapping conditions
3782 if ((policy
->condition_negated_mask
& compared_policy
->condition_mask
) != (compared_policy
->condition_negated_mask
& compared_policy
->condition_mask
)) {
3786 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
&&
3787 strcmp(compared_policy
->cond_domain
, policy
->cond_domain
) != 0) {
3791 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
&&
3792 strcmp(compared_policy
->cond_custom_entitlement
, policy
->cond_custom_entitlement
) != 0) {
3796 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
&&
3797 compared_policy
->cond_account_id
!= policy
->cond_account_id
) {
3801 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
&&
3802 compared_policy
->cond_policy_id
!= policy
->cond_policy_id
) {
3806 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
&&
3807 compared_policy
->cond_app_id
!= policy
->cond_app_id
) {
3811 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
&&
3812 compared_policy
->cond_real_app_id
!= policy
->cond_real_app_id
) {
3816 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_PID
&&
3817 compared_policy
->cond_pid
!= policy
->cond_pid
) {
3821 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_UID
&&
3822 compared_policy
->cond_uid
!= policy
->cond_uid
) {
3826 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
&&
3827 compared_policy
->cond_bound_interface
!= policy
->cond_bound_interface
) {
3831 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
&&
3832 compared_policy
->cond_protocol
!= policy
->cond_protocol
) {
3836 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
&&
3837 !(compared_policy
->cond_traffic_class
.start_tc
<= policy
->cond_traffic_class
.start_tc
&&
3838 compared_policy
->cond_traffic_class
.end_tc
>= policy
->cond_traffic_class
.end_tc
)) {
3842 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
3843 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
3844 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
)) {
3847 } else if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
3848 if (compared_policy
->cond_local_prefix
> policy
->cond_local_prefix
||
3849 !necp_is_addr_in_subnet((struct sockaddr
*)&policy
->cond_local_start
, (struct sockaddr
*)&compared_policy
->cond_local_start
, compared_policy
->cond_local_prefix
)) {
3855 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
3856 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
3857 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
)) {
3860 } else if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
3861 if (compared_policy
->cond_remote_prefix
> policy
->cond_remote_prefix
||
3862 !necp_is_addr_in_subnet((struct sockaddr
*)&policy
->cond_remote_start
, (struct sockaddr
*)&compared_policy
->cond_remote_start
, compared_policy
->cond_remote_prefix
)) {
3875 necp_kernel_socket_policies_reprocess(void)
3878 int bucket_allocation_counts
[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
];
3879 int bucket_current_free_index
[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
];
3880 int app_layer_allocation_count
= 0;
3881 int app_layer_current_free_index
= 0;
3882 struct necp_kernel_socket_policy
*kernel_policy
= NULL
;
3884 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
3887 necp_kernel_application_policies_condition_mask
= 0;
3888 necp_kernel_socket_policies_condition_mask
= 0;
3889 necp_kernel_application_policies_count
= 0;
3890 necp_kernel_socket_policies_count
= 0;
3891 necp_kernel_socket_policies_non_app_count
= 0;
3893 // Reset all maps to NULL
3894 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
3895 if (necp_kernel_socket_policies_map
[app_i
] != NULL
) {
3896 FREE(necp_kernel_socket_policies_map
[app_i
], M_NECP
);
3897 necp_kernel_socket_policies_map
[app_i
] = NULL
;
3901 bucket_allocation_counts
[app_i
] = 0;
3903 if (necp_kernel_socket_policies_app_layer_map
!= NULL
) {
3904 FREE(necp_kernel_socket_policies_app_layer_map
, M_NECP
);
3905 necp_kernel_socket_policies_app_layer_map
= NULL
;
3908 // Create masks and counts
3909 LIST_FOREACH(kernel_policy
, &necp_kernel_socket_policies
, chain
) {
3910 // App layer mask/count
3911 necp_kernel_application_policies_condition_mask
|= kernel_policy
->condition_mask
;
3912 necp_kernel_application_policies_count
++;
3913 app_layer_allocation_count
++;
3915 // Update socket layer bucket mask/counts
3916 necp_kernel_socket_policies_condition_mask
|= kernel_policy
->condition_mask
;
3917 necp_kernel_socket_policies_count
++;
3919 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) ||
3920 kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
3921 necp_kernel_socket_policies_non_app_count
++;
3922 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
3923 bucket_allocation_counts
[app_i
]++;
3926 bucket_allocation_counts
[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy
->cond_app_id
)]++;
3931 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
3932 if (bucket_allocation_counts
[app_i
] > 0) {
3933 // Allocate a NULL-terminated array of policy pointers for each bucket
3934 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
);
3935 if (necp_kernel_socket_policies_map
[app_i
] == NULL
) {
3939 // Initialize the first entry to NULL
3940 (necp_kernel_socket_policies_map
[app_i
])[0] = NULL
;
3942 bucket_current_free_index
[app_i
] = 0;
3944 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
);
3945 if (necp_kernel_socket_policies_app_layer_map
== NULL
) {
3948 necp_kernel_socket_policies_app_layer_map
[0] = NULL
;
3951 LIST_FOREACH(kernel_policy
, &necp_kernel_socket_policies
, chain
) {
3952 // Insert pointers into map
3953 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) ||
3954 kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
3955 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
3956 if (!necp_kernel_socket_policy_is_unnecessary(kernel_policy
, necp_kernel_socket_policies_map
[app_i
], bucket_current_free_index
[app_i
])) {
3957 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = kernel_policy
;
3958 bucket_current_free_index
[app_i
]++;
3959 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = NULL
;
3963 app_i
= NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy
->cond_app_id
);
3964 if (!necp_kernel_socket_policy_is_unnecessary(kernel_policy
, necp_kernel_socket_policies_map
[app_i
], bucket_current_free_index
[app_i
])) {
3965 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = kernel_policy
;
3966 bucket_current_free_index
[app_i
]++;
3967 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = NULL
;
3971 if (!necp_kernel_socket_policy_is_unnecessary(kernel_policy
, necp_kernel_socket_policies_app_layer_map
, app_layer_current_free_index
)) {
3972 necp_kernel_socket_policies_app_layer_map
[app_layer_current_free_index
] = kernel_policy
;
3973 app_layer_current_free_index
++;
3974 necp_kernel_socket_policies_app_layer_map
[app_layer_current_free_index
] = NULL
;
3977 necp_kernel_socket_policies_dump_all();
3978 BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT();
3982 // Free memory, reset masks to 0
3983 necp_kernel_application_policies_condition_mask
= 0;
3984 necp_kernel_socket_policies_condition_mask
= 0;
3985 necp_kernel_application_policies_count
= 0;
3986 necp_kernel_socket_policies_count
= 0;
3987 necp_kernel_socket_policies_non_app_count
= 0;
3988 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
3989 if (necp_kernel_socket_policies_map
[app_i
] != NULL
) {
3990 FREE(necp_kernel_socket_policies_map
[app_i
], M_NECP
);
3991 necp_kernel_socket_policies_map
[app_i
] = NULL
;
3994 if (necp_kernel_socket_policies_app_layer_map
!= NULL
) {
3995 FREE(necp_kernel_socket_policies_app_layer_map
, M_NECP
);
3996 necp_kernel_socket_policies_app_layer_map
= NULL
;
4002 necp_get_new_string_id(void)
4004 u_int32_t newid
= 0;
4006 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4008 necp_last_string_id
++;
4009 if (necp_last_string_id
< 1) {
4010 necp_last_string_id
= 1;
4013 newid
= necp_last_string_id
;
4015 NECPLOG0(LOG_DEBUG
, "Allocate string id failed.\n");
4022 static struct necp_string_id_mapping
*
4023 necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list
*list
, char *string
)
4025 struct necp_string_id_mapping
*searchentry
= NULL
;
4026 struct necp_string_id_mapping
*foundentry
= NULL
;
4028 LIST_FOREACH(searchentry
, list
, chain
) {
4029 if (strcmp(searchentry
->string
, string
) == 0) {
4030 foundentry
= searchentry
;
4035 return (foundentry
);
4038 static struct necp_string_id_mapping
*
4039 necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list
*list
, u_int32_t local_id
)
4041 struct necp_string_id_mapping
*searchentry
= NULL
;
4042 struct necp_string_id_mapping
*foundentry
= NULL
;
4044 LIST_FOREACH(searchentry
, list
, chain
) {
4045 if (searchentry
->id
== local_id
) {
4046 foundentry
= searchentry
;
4051 return (foundentry
);
4055 necp_create_string_to_id_mapping(struct necp_string_id_mapping_list
*list
, char *string
)
4057 u_int32_t string_id
= 0;
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 string_id
= existing_mapping
->id
;
4065 existing_mapping
->refcount
++;
4067 struct necp_string_id_mapping
*new_mapping
= NULL
;
4068 MALLOC(new_mapping
, struct necp_string_id_mapping
*, sizeof(struct necp_string_id_mapping
), M_NECP
, M_WAITOK
);
4069 if (new_mapping
!= NULL
) {
4070 memset(new_mapping
, 0, sizeof(struct necp_string_id_mapping
));
4072 size_t length
= strlen(string
) + 1;
4073 MALLOC(new_mapping
->string
, char *, length
, M_NECP
, M_WAITOK
);
4074 if (new_mapping
->string
!= NULL
) {
4075 memcpy(new_mapping
->string
, string
, length
);
4076 new_mapping
->id
= necp_get_new_string_id();
4077 new_mapping
->refcount
= 1;
4078 LIST_INSERT_HEAD(list
, new_mapping
, chain
);
4079 string_id
= new_mapping
->id
;
4081 FREE(new_mapping
, M_NECP
);
4090 necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list
*list
, char *string
)
4092 struct necp_string_id_mapping
*existing_mapping
= NULL
;
4094 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4096 existing_mapping
= necp_lookup_string_to_id_locked(list
, string
);
4097 if (existing_mapping
!= NULL
) {
4098 if (--existing_mapping
->refcount
== 0) {
4099 LIST_REMOVE(existing_mapping
, chain
);
4100 FREE(existing_mapping
->string
, M_NECP
);
4101 FREE(existing_mapping
, M_NECP
);
4110 necp_get_new_route_rule_id(void)
4112 u_int32_t newid
= 0;
4114 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4116 necp_last_route_rule_id
++;
4117 if (necp_last_route_rule_id
< 1 || necp_last_route_rule_id
> UINT16_MAX
) {
4118 necp_last_route_rule_id
= 1;
4121 newid
= necp_last_route_rule_id
;
4123 NECPLOG0(LOG_DEBUG
, "Allocate route rule id failed.\n");
4131 necp_get_new_aggregate_route_rule_id(void)
4133 u_int32_t newid
= 0;
4135 lck_rw_assert(&necp_route_rule_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4137 necp_last_aggregate_route_rule_id
++;
4138 if (necp_last_aggregate_route_rule_id
<= UINT16_MAX
) {
4139 necp_last_aggregate_route_rule_id
= UINT16_MAX
+ 1;
4142 newid
= necp_last_aggregate_route_rule_id
;
4144 NECPLOG0(LOG_DEBUG
, "Allocate aggregate route rule id failed.\n");
4151 static struct necp_route_rule
*
4152 necp_lookup_route_rule_locked(struct necp_route_rule_list
*list
, u_int32_t route_rule_id
)
4154 struct necp_route_rule
*searchentry
= NULL
;
4155 struct necp_route_rule
*foundentry
= NULL
;
4157 LIST_FOREACH(searchentry
, list
, chain
) {
4158 if (searchentry
->id
== route_rule_id
) {
4159 foundentry
= searchentry
;
4164 return (foundentry
);
4167 static struct necp_route_rule
*
4168 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
)
4170 struct necp_route_rule
*searchentry
= NULL
;
4171 struct necp_route_rule
*foundentry
= NULL
;
4173 LIST_FOREACH(searchentry
, list
, chain
) {
4174 if (searchentry
->default_action
== default_action
&&
4175 searchentry
->cellular_action
== cellular_action
&&
4176 searchentry
->wifi_action
== wifi_action
&&
4177 searchentry
->wired_action
== wired_action
&&
4178 searchentry
->expensive_action
== expensive_action
) {
4179 bool match_failed
= FALSE
;
4184 for (index_a
= 0; index_a
< MAX_ROUTE_RULE_INTERFACES
; index_a
++) {
4185 bool found_index
= FALSE
;
4186 if (searchentry
->exception_if_indices
[index_a
] == 0) {
4190 for (index_b
= 0; index_b
< MAX_ROUTE_RULE_INTERFACES
; index_b
++) {
4191 if (if_indices
[index_b
] == 0) {
4194 if (index_b
>= count_b
) {
4195 count_b
= index_b
+ 1;
4197 if (searchentry
->exception_if_indices
[index_a
] == if_indices
[index_b
] &&
4198 searchentry
->exception_if_actions
[index_a
] == if_actions
[index_b
]) {
4204 match_failed
= TRUE
;
4208 if (!match_failed
&& count_a
== count_b
) {
4209 foundentry
= searchentry
;
4215 return (foundentry
);
4219 necp_create_route_rule(struct necp_route_rule_list
*list
, u_int8_t
*route_rules_array
, u_int32_t route_rules_array_size
)
4222 u_int32_t route_rule_id
= 0;
4223 struct necp_route_rule
*existing_rule
= NULL
;
4224 u_int32_t default_action
= NECP_ROUTE_RULE_ALLOW_INTERFACE
;
4225 u_int8_t cellular_action
= NECP_ROUTE_RULE_NONE
;
4226 u_int8_t wifi_action
= NECP_ROUTE_RULE_NONE
;
4227 u_int8_t wired_action
= NECP_ROUTE_RULE_NONE
;
4228 u_int8_t expensive_action
= NECP_ROUTE_RULE_NONE
;
4229 u_int32_t if_indices
[MAX_ROUTE_RULE_INTERFACES
];
4230 size_t num_valid_indices
= 0;
4231 memset(&if_indices
, 0, sizeof(if_indices
));
4232 u_int8_t if_actions
[MAX_ROUTE_RULE_INTERFACES
];
4233 memset(&if_actions
, 0, sizeof(if_actions
));
4235 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4237 if (route_rules_array
== NULL
|| route_rules_array_size
== 0) {
4242 while (offset
< route_rules_array_size
) {
4243 ifnet_t rule_interface
= NULL
;
4244 char interface_name
[IFXNAMSIZ
];
4245 u_int32_t length
= 0;
4246 u_int8_t
*value
= necp_buffer_get_tlv_value(route_rules_array
, offset
, &length
);
4248 u_int8_t rule_type
= necp_policy_condition_get_type_from_buffer(value
, length
);
4249 u_int8_t rule_flags
= necp_policy_condition_get_flags_from_buffer(value
, length
);
4250 u_int32_t rule_length
= necp_policy_condition_get_value_length_from_buffer(value
, length
);
4251 u_int8_t
*rule_value
= necp_policy_condition_get_value_pointer_from_buffer(value
, length
);
4253 if (rule_type
== NECP_ROUTE_RULE_NONE
) {
4254 // Don't allow an explicit rule to be None action
4258 if (rule_length
== 0) {
4259 if (rule_flags
& NECP_ROUTE_RULE_FLAG_CELLULAR
) {
4260 cellular_action
= rule_type
;
4262 if (rule_flags
& NECP_ROUTE_RULE_FLAG_WIFI
) {
4263 wifi_action
= rule_type
;
4265 if (rule_flags
& NECP_ROUTE_RULE_FLAG_WIRED
) {
4266 wired_action
= rule_type
;
4268 if (rule_flags
& NECP_ROUTE_RULE_FLAG_EXPENSIVE
) {
4269 expensive_action
= rule_type
;
4271 if (rule_flags
== 0) {
4272 default_action
= rule_type
;
4274 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
4278 if (num_valid_indices
>= MAX_ROUTE_RULE_INTERFACES
) {
4279 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
4283 if (rule_length
<= IFXNAMSIZ
) {
4284 memcpy(interface_name
, rule_value
, rule_length
);
4285 interface_name
[rule_length
- 1] = 0; // Make sure the string is NULL terminated
4286 if (ifnet_find_by_name(interface_name
, &rule_interface
) == 0) {
4287 if_actions
[num_valid_indices
] = rule_type
;
4288 if_indices
[num_valid_indices
++] = rule_interface
->if_index
;
4289 ifnet_release(rule_interface
);
4292 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
4295 existing_rule
= necp_lookup_route_rule_by_contents_locked(list
, default_action
, cellular_action
, wifi_action
, wired_action
, expensive_action
, if_indices
, if_actions
);
4296 if (existing_rule
!= NULL
) {
4297 route_rule_id
= existing_rule
->id
;
4298 existing_rule
->refcount
++;
4300 struct necp_route_rule
*new_rule
= NULL
;
4301 MALLOC(new_rule
, struct necp_route_rule
*, sizeof(struct necp_route_rule
), M_NECP
, M_WAITOK
);
4302 if (new_rule
!= NULL
) {
4303 memset(new_rule
, 0, sizeof(struct necp_route_rule
));
4304 route_rule_id
= new_rule
->id
= necp_get_new_route_rule_id();
4305 new_rule
->default_action
= default_action
;
4306 new_rule
->cellular_action
= cellular_action
;
4307 new_rule
->wifi_action
= wifi_action
;
4308 new_rule
->wired_action
= wired_action
;
4309 new_rule
->expensive_action
= expensive_action
;
4310 memcpy(&new_rule
->exception_if_indices
, &if_indices
, sizeof(if_indices
));
4311 memcpy(&new_rule
->exception_if_actions
, &if_actions
, sizeof(if_actions
));
4312 new_rule
->refcount
= 1;
4313 LIST_INSERT_HEAD(list
, new_rule
, chain
);
4316 return (route_rule_id
);
4320 necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id
)
4323 lck_rw_lock_exclusive(&necp_route_rule_lock
);
4325 struct necp_aggregate_route_rule
*existing_rule
= NULL
;
4326 struct necp_aggregate_route_rule
*tmp_rule
= NULL
;
4328 LIST_FOREACH_SAFE(existing_rule
, &necp_aggregate_route_rules
, chain
, tmp_rule
) {
4330 for (index
= 0; index
< MAX_AGGREGATE_ROUTE_RULES
; index
++) {
4331 u_int32_t route_rule_id
= existing_rule
->rule_ids
[index
];
4332 if (route_rule_id
== rule_id
) {
4333 LIST_REMOVE(existing_rule
, chain
);
4334 FREE(existing_rule
, M_NECP
);
4340 lck_rw_done(&necp_route_rule_lock
);
4345 necp_remove_route_rule(struct necp_route_rule_list
*list
, u_int32_t route_rule_id
)
4347 struct necp_route_rule
*existing_rule
= NULL
;
4349 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4351 existing_rule
= necp_lookup_route_rule_locked(list
, route_rule_id
);
4352 if (existing_rule
!= NULL
) {
4353 if (--existing_rule
->refcount
== 0) {
4354 necp_remove_aggregate_route_rule_for_id(existing_rule
->id
);
4355 LIST_REMOVE(existing_rule
, chain
);
4356 FREE(existing_rule
, M_NECP
);
4364 static struct necp_aggregate_route_rule
*
4365 necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id
)
4367 struct necp_aggregate_route_rule
*searchentry
= NULL
;
4368 struct necp_aggregate_route_rule
*foundentry
= NULL
;
4370 lck_rw_lock_shared(&necp_route_rule_lock
);
4372 LIST_FOREACH(searchentry
, &necp_aggregate_route_rules
, chain
) {
4373 if (searchentry
->id
== route_rule_id
) {
4374 foundentry
= searchentry
;
4379 lck_rw_done(&necp_route_rule_lock
);
4381 return (foundentry
);
4385 necp_create_aggregate_route_rule(u_int32_t
*rule_ids
)
4387 u_int32_t aggregate_route_rule_id
= 0;
4388 struct necp_aggregate_route_rule
*new_rule
= NULL
;
4389 struct necp_aggregate_route_rule
*existing_rule
= NULL
;
4391 LIST_FOREACH(existing_rule
, &necp_aggregate_route_rules
, chain
) {
4392 if (memcmp(existing_rule
->rule_ids
, rule_ids
, (sizeof(u_int32_t
) * MAX_AGGREGATE_ROUTE_RULES
)) == 0) {
4393 return (existing_rule
->id
);
4397 lck_rw_lock_exclusive(&necp_route_rule_lock
);
4399 LIST_FOREACH(existing_rule
, &necp_aggregate_route_rules
, chain
) {
4400 // Re-check, in case something else created the rule while we are waiting to lock
4401 if (memcmp(existing_rule
->rule_ids
, rule_ids
, (sizeof(u_int32_t
) * MAX_AGGREGATE_ROUTE_RULES
)) == 0) {
4402 lck_rw_done(&necp_route_rule_lock
);
4403 return (existing_rule
->id
);
4407 MALLOC(new_rule
, struct necp_aggregate_route_rule
*, sizeof(struct necp_aggregate_route_rule
), M_NECP
, M_WAITOK
);
4408 if (new_rule
!= NULL
) {
4409 memset(new_rule
, 0, sizeof(struct necp_aggregate_route_rule
));
4410 aggregate_route_rule_id
= new_rule
->id
= necp_get_new_aggregate_route_rule_id();
4411 new_rule
->id
= aggregate_route_rule_id
;
4412 memcpy(new_rule
->rule_ids
, rule_ids
, (sizeof(u_int32_t
) * MAX_AGGREGATE_ROUTE_RULES
));
4413 LIST_INSERT_HEAD(&necp_aggregate_route_rules
, new_rule
, chain
);
4415 lck_rw_done(&necp_route_rule_lock
);
4417 return (aggregate_route_rule_id
);
4420 #define NECP_NULL_SERVICE_ID 1
4422 necp_get_new_uuid_id(void)
4424 u_int32_t newid
= 0;
4426 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4428 necp_last_uuid_id
++;
4429 if (necp_last_uuid_id
< (NECP_NULL_SERVICE_ID
+ 1)) {
4430 necp_last_uuid_id
= (NECP_NULL_SERVICE_ID
+ 1);
4433 newid
= necp_last_uuid_id
;
4435 NECPLOG0(LOG_DEBUG
, "Allocate uuid id failed.\n");
4442 static struct necp_uuid_id_mapping
*
4443 necp_uuid_lookup_app_id_locked(uuid_t uuid
)
4445 struct necp_uuid_id_mapping
*searchentry
= NULL
;
4446 struct necp_uuid_id_mapping
*foundentry
= NULL
;
4448 LIST_FOREACH(searchentry
, APPUUIDHASH(uuid
), chain
) {
4449 if (uuid_compare(searchentry
->uuid
, uuid
) == 0) {
4450 foundentry
= searchentry
;
4455 return (foundentry
);
4458 static struct necp_uuid_id_mapping
*
4459 necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id
)
4461 struct necp_uuid_id_mapping
*searchentry
= NULL
;
4462 struct necp_uuid_id_mapping
*foundentry
= NULL
;
4464 struct necp_uuid_id_mapping_head
*uuid_list_head
= NULL
;
4465 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
--) {
4466 LIST_FOREACH(searchentry
, uuid_list_head
, chain
) {
4467 if (searchentry
->id
== local_id
) {
4468 foundentry
= searchentry
;
4474 return (foundentry
);
4478 necp_create_uuid_app_id_mapping(uuid_t uuid
, bool *allocated_mapping
, bool uuid_policy_table
)
4480 u_int32_t local_id
= 0;
4481 struct necp_uuid_id_mapping
*existing_mapping
= NULL
;
4483 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4485 if (allocated_mapping
) {
4486 *allocated_mapping
= FALSE
;
4489 existing_mapping
= necp_uuid_lookup_app_id_locked(uuid
);
4490 if (existing_mapping
!= NULL
) {
4491 local_id
= existing_mapping
->id
;
4492 existing_mapping
->refcount
++;
4493 if (uuid_policy_table
) {
4494 existing_mapping
->table_refcount
++;
4497 struct necp_uuid_id_mapping
*new_mapping
= NULL
;
4498 MALLOC(new_mapping
, struct necp_uuid_id_mapping
*, sizeof(*new_mapping
), M_NECP
, M_WAITOK
);
4499 if (new_mapping
!= NULL
) {
4500 uuid_copy(new_mapping
->uuid
, uuid
);
4501 new_mapping
->id
= necp_get_new_uuid_id();
4502 new_mapping
->refcount
= 1;
4503 if (uuid_policy_table
) {
4504 new_mapping
->table_refcount
= 1;
4506 new_mapping
->table_refcount
= 0;
4509 LIST_INSERT_HEAD(APPUUIDHASH(uuid
), new_mapping
, chain
);
4511 if (allocated_mapping
) {
4512 *allocated_mapping
= TRUE
;
4515 local_id
= new_mapping
->id
;
4523 necp_remove_uuid_app_id_mapping(uuid_t uuid
, bool *removed_mapping
, bool uuid_policy_table
)
4525 struct necp_uuid_id_mapping
*existing_mapping
= NULL
;
4527 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4529 if (removed_mapping
) {
4530 *removed_mapping
= FALSE
;
4533 existing_mapping
= necp_uuid_lookup_app_id_locked(uuid
);
4534 if (existing_mapping
!= NULL
) {
4535 if (uuid_policy_table
) {
4536 existing_mapping
->table_refcount
--;
4538 if (--existing_mapping
->refcount
== 0) {
4539 LIST_REMOVE(existing_mapping
, chain
);
4540 FREE(existing_mapping
, M_NECP
);
4541 if (removed_mapping
) {
4542 *removed_mapping
= TRUE
;
4551 static struct necp_uuid_id_mapping
*
4552 necp_uuid_get_null_service_id_mapping(void)
4554 static struct necp_uuid_id_mapping null_mapping
;
4555 uuid_clear(null_mapping
.uuid
);
4556 null_mapping
.id
= NECP_NULL_SERVICE_ID
;
4558 return (&null_mapping
);
4561 static struct necp_uuid_id_mapping
*
4562 necp_uuid_lookup_service_id_locked(uuid_t uuid
)
4564 struct necp_uuid_id_mapping
*searchentry
= NULL
;
4565 struct necp_uuid_id_mapping
*foundentry
= NULL
;
4567 if (uuid_is_null(uuid
)) {
4568 return necp_uuid_get_null_service_id_mapping();
4571 LIST_FOREACH(searchentry
, &necp_uuid_service_id_list
, chain
) {
4572 if (uuid_compare(searchentry
->uuid
, uuid
) == 0) {
4573 foundentry
= searchentry
;
4578 return (foundentry
);
4581 static struct necp_uuid_id_mapping
*
4582 necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id
)
4584 struct necp_uuid_id_mapping
*searchentry
= NULL
;
4585 struct necp_uuid_id_mapping
*foundentry
= NULL
;
4587 if (local_id
== NECP_NULL_SERVICE_ID
) {
4588 return necp_uuid_get_null_service_id_mapping();
4591 LIST_FOREACH(searchentry
, &necp_uuid_service_id_list
, chain
) {
4592 if (searchentry
->id
== local_id
) {
4593 foundentry
= searchentry
;
4598 return (foundentry
);
4602 necp_create_uuid_service_id_mapping(uuid_t uuid
)
4604 u_int32_t local_id
= 0;
4605 struct necp_uuid_id_mapping
*existing_mapping
= NULL
;
4607 if (uuid_is_null(uuid
)) {
4608 return (NECP_NULL_SERVICE_ID
);
4611 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4613 existing_mapping
= necp_uuid_lookup_service_id_locked(uuid
);
4614 if (existing_mapping
!= NULL
) {
4615 local_id
= existing_mapping
->id
;
4616 existing_mapping
->refcount
++;
4618 struct necp_uuid_id_mapping
*new_mapping
= NULL
;
4619 MALLOC(new_mapping
, struct necp_uuid_id_mapping
*, sizeof(*new_mapping
), M_NECP
, M_WAITOK
);
4620 if (new_mapping
!= NULL
) {
4621 uuid_copy(new_mapping
->uuid
, uuid
);
4622 new_mapping
->id
= necp_get_new_uuid_id();
4623 new_mapping
->refcount
= 1;
4625 LIST_INSERT_HEAD(&necp_uuid_service_id_list
, new_mapping
, chain
);
4627 local_id
= new_mapping
->id
;
4635 necp_remove_uuid_service_id_mapping(uuid_t uuid
)
4637 struct necp_uuid_id_mapping
*existing_mapping
= NULL
;
4639 if (uuid_is_null(uuid
)) {
4643 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4645 existing_mapping
= necp_uuid_lookup_app_id_locked(uuid
);
4646 if (existing_mapping
!= NULL
) {
4647 if (--existing_mapping
->refcount
== 0) {
4648 LIST_REMOVE(existing_mapping
, chain
);
4649 FREE(existing_mapping
, M_NECP
);
4659 necp_kernel_socket_policies_update_uuid_table(void)
4661 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4663 if (necp_uuid_app_id_mappings_dirty
) {
4664 if (proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_CLEAR
, NULL
, PROC_UUID_NECP_APP_POLICY
) < 0) {
4665 NECPLOG0(LOG_DEBUG
, "Error clearing uuids from policy table\n");
4669 if (necp_num_uuid_app_id_mappings
> 0) {
4670 struct necp_uuid_id_mapping_head
*uuid_list_head
= NULL
;
4671 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
--) {
4672 struct necp_uuid_id_mapping
*mapping
= NULL
;
4673 LIST_FOREACH(mapping
, uuid_list_head
, chain
) {
4674 if (mapping
->table_refcount
> 0 &&
4675 proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_ADD
, mapping
->uuid
, PROC_UUID_NECP_APP_POLICY
) < 0) {
4676 NECPLOG0(LOG_DEBUG
, "Error adding uuid to policy table\n");
4682 necp_uuid_app_id_mappings_dirty
= FALSE
;
4688 #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)
4689 static necp_kernel_policy_id
4690 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
)
4692 struct necp_kernel_ip_output_policy
*new_kernel_policy
= NULL
;
4693 struct necp_kernel_ip_output_policy
*tmp_kernel_policy
= NULL
;
4695 MALLOC_ZONE(new_kernel_policy
, struct necp_kernel_ip_output_policy
*, sizeof(*new_kernel_policy
), M_NECP_IP_POLICY
, M_WAITOK
);
4696 if (new_kernel_policy
== NULL
) {
4700 memset(new_kernel_policy
, 0, sizeof(*new_kernel_policy
));
4701 new_kernel_policy
->parent_policy_id
= parent_policy_id
;
4702 new_kernel_policy
->id
= necp_kernel_policy_get_new_id();
4703 new_kernel_policy
->suborder
= suborder
;
4704 new_kernel_policy
->order
= order
;
4705 new_kernel_policy
->session_order
= session_order
;
4706 new_kernel_policy
->session_pid
= session_pid
;
4708 // Sanitize condition mask
4709 new_kernel_policy
->condition_mask
= (condition_mask
& NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS
);
4710 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
)) {
4711 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE
;
4713 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
)) {
4714 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX
;
4716 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
)) {
4717 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX
;
4719 new_kernel_policy
->condition_negated_mask
= condition_negated_mask
& new_kernel_policy
->condition_mask
;
4721 // Set condition values
4722 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
) {
4723 new_kernel_policy
->cond_policy_id
= cond_policy_id
;
4725 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
4726 if (cond_bound_interface
) {
4727 ifnet_reference(cond_bound_interface
);
4729 new_kernel_policy
->cond_bound_interface
= cond_bound_interface
;
4731 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LAST_INTERFACE
) {
4732 new_kernel_policy
->cond_last_interface_index
= cond_last_interface_index
;
4734 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
4735 new_kernel_policy
->cond_protocol
= cond_protocol
;
4737 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
4738 memcpy(&new_kernel_policy
->cond_local_start
, cond_local_start
, cond_local_start
->sa
.sa_len
);
4740 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
4741 memcpy(&new_kernel_policy
->cond_local_end
, cond_local_end
, cond_local_end
->sa
.sa_len
);
4743 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
4744 new_kernel_policy
->cond_local_prefix
= cond_local_prefix
;
4746 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
4747 memcpy(&new_kernel_policy
->cond_remote_start
, cond_remote_start
, cond_remote_start
->sa
.sa_len
);
4749 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
4750 memcpy(&new_kernel_policy
->cond_remote_end
, cond_remote_end
, cond_remote_end
->sa
.sa_len
);
4752 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
4753 new_kernel_policy
->cond_remote_prefix
= cond_remote_prefix
;
4756 new_kernel_policy
->result
= result
;
4757 memcpy(&new_kernel_policy
->result_parameter
, &result_parameter
, sizeof(result_parameter
));
4760 NECPLOG(LOG_DEBUG
, "Added kernel policy: ip output, id=%d, mask=%x\n", new_kernel_policy
->id
, new_kernel_policy
->condition_mask
);
4762 LIST_INSERT_SORTED_THRICE_ASCENDING(&necp_kernel_ip_output_policies
, new_kernel_policy
, chain
, session_order
, order
, suborder
, tmp_kernel_policy
);
4764 return (new_kernel_policy
? new_kernel_policy
->id
: 0);
4767 static struct necp_kernel_ip_output_policy
*
4768 necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id
)
4770 struct necp_kernel_ip_output_policy
*kernel_policy
= NULL
;
4771 struct necp_kernel_ip_output_policy
*tmp_kernel_policy
= NULL
;
4773 if (policy_id
== 0) {
4777 LIST_FOREACH_SAFE(kernel_policy
, &necp_kernel_ip_output_policies
, chain
, tmp_kernel_policy
) {
4778 if (kernel_policy
->id
== policy_id
) {
4779 return (kernel_policy
);
4787 necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id
)
4789 struct necp_kernel_ip_output_policy
*policy
= NULL
;
4791 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4793 policy
= necp_kernel_ip_output_policy_find(policy_id
);
4795 LIST_REMOVE(policy
, chain
);
4797 if (policy
->cond_bound_interface
) {
4798 ifnet_release(policy
->cond_bound_interface
);
4799 policy
->cond_bound_interface
= NULL
;
4802 FREE_ZONE(policy
, sizeof(*policy
), M_NECP_IP_POLICY
);
4810 necp_kernel_ip_output_policies_dump_all(void)
4813 struct necp_kernel_ip_output_policy
*policy
= NULL
;
4816 char result_string
[MAX_RESULT_STRING_LEN
];
4817 char proc_name_string
[MAXCOMLEN
+ 1];
4818 memset(result_string
, 0, MAX_RESULT_STRING_LEN
);
4819 memset(proc_name_string
, 0, MAXCOMLEN
+ 1);
4821 NECPLOG0(LOG_DEBUG
, "NECP IP Output Policies:\n");
4822 NECPLOG0(LOG_DEBUG
, "-----------\n");
4823 for (id_i
= 0; id_i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; id_i
++) {
4824 NECPLOG(LOG_DEBUG
, " ID Bucket: %d\n", id_i
);
4825 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
++) {
4826 policy
= (necp_kernel_ip_output_policies_map
[id_i
])[policy_i
];
4827 proc_name(policy
->session_pid
, proc_name_string
, MAXCOMLEN
);
4828 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
));
4830 NECPLOG0(LOG_DEBUG
, "-----------\n");
4836 necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy
*upper_policy
, struct necp_kernel_ip_output_policy
*lower_policy
)
4838 if (upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
4839 if (upper_policy
->session_order
!= lower_policy
->session_order
) {
4840 // A skip cannot override a policy of a different session
4843 if (upper_policy
->result_parameter
.skip_policy_order
== 0 ||
4844 lower_policy
->order
>= upper_policy
->result_parameter
.skip_policy_order
) {
4845 // This policy is beyond the skip
4848 // This policy is inside the skip
4854 // All other IP Output policy results (drop, tunnel, hard pass) currently overlap
4859 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
)
4861 bool can_skip
= FALSE
;
4862 u_int32_t highest_skip_session_order
= 0;
4863 u_int32_t highest_skip_order
= 0;
4865 for (i
= 0; i
< valid_indices
; i
++) {
4866 struct necp_kernel_ip_output_policy
*compared_policy
= policy_array
[i
];
4868 // For policies in a skip window, we can't mark conflicting policies as unnecessary
4870 if (highest_skip_session_order
!= compared_policy
->session_order
||
4871 (highest_skip_order
!= 0 && compared_policy
->order
>= highest_skip_order
)) {
4872 // If we've moved on to the next session, or passed the skip window
4873 highest_skip_session_order
= 0;
4874 highest_skip_order
= 0;
4877 // If this policy is also a skip, in can increase the skip window
4878 if (compared_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
4879 if (compared_policy
->result_parameter
.skip_policy_order
> highest_skip_order
) {
4880 highest_skip_order
= compared_policy
->result_parameter
.skip_policy_order
;
4887 if (compared_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
4888 // This policy is a skip. Set the skip window accordingly
4890 highest_skip_session_order
= compared_policy
->session_order
;
4891 highest_skip_order
= compared_policy
->result_parameter
.skip_policy_order
;
4894 // The result of the compared policy must be able to block out this policy result
4895 if (!necp_kernel_ip_output_policy_results_overlap(compared_policy
, policy
)) {
4899 // If new policy matches All Interfaces, compared policy must also
4900 if ((policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && !(compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) {
4904 // Default makes lower policies unecessary always
4905 if (compared_policy
->condition_mask
== 0) {
4909 // Compared must be more general than policy, and include only conditions within policy
4910 if ((policy
->condition_mask
& compared_policy
->condition_mask
) != compared_policy
->condition_mask
) {
4914 // Negative conditions must match for the overlapping conditions
4915 if ((policy
->condition_negated_mask
& compared_policy
->condition_mask
) != (compared_policy
->condition_negated_mask
& compared_policy
->condition_mask
)) {
4919 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
&&
4920 compared_policy
->cond_policy_id
!= policy
->cond_policy_id
) {
4924 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
&&
4925 compared_policy
->cond_bound_interface
!= policy
->cond_bound_interface
) {
4929 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
&&
4930 compared_policy
->cond_protocol
!= policy
->cond_protocol
) {
4934 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
4935 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
4936 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
)) {
4939 } else if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
4940 if (compared_policy
->cond_local_prefix
> policy
->cond_local_prefix
||
4941 !necp_is_addr_in_subnet((struct sockaddr
*)&policy
->cond_local_start
, (struct sockaddr
*)&compared_policy
->cond_local_start
, compared_policy
->cond_local_prefix
)) {
4947 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
4948 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
4949 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
)) {
4952 } else if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
4953 if (compared_policy
->cond_remote_prefix
> policy
->cond_remote_prefix
||
4954 !necp_is_addr_in_subnet((struct sockaddr
*)&policy
->cond_remote_start
, (struct sockaddr
*)&compared_policy
->cond_remote_start
, compared_policy
->cond_remote_prefix
)) {
4967 necp_kernel_ip_output_policies_reprocess(void)
4970 int bucket_allocation_counts
[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
];
4971 int bucket_current_free_index
[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
];
4972 struct necp_kernel_ip_output_policy
*kernel_policy
= NULL
;
4974 lck_rw_assert(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4977 necp_kernel_ip_output_policies_condition_mask
= 0;
4978 necp_kernel_ip_output_policies_count
= 0;
4979 necp_kernel_ip_output_policies_non_id_count
= 0;
4981 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
4982 if (necp_kernel_ip_output_policies_map
[i
] != NULL
) {
4983 FREE(necp_kernel_ip_output_policies_map
[i
], M_NECP
);
4984 necp_kernel_ip_output_policies_map
[i
] = NULL
;
4988 bucket_allocation_counts
[i
] = 0;
4991 LIST_FOREACH(kernel_policy
, &necp_kernel_ip_output_policies
, chain
) {
4993 necp_kernel_ip_output_policies_condition_mask
|= kernel_policy
->condition_mask
;
4994 necp_kernel_ip_output_policies_count
++;
4996 // Update bucket counts
4997 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
)) {
4998 necp_kernel_ip_output_policies_non_id_count
++;
4999 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
5000 bucket_allocation_counts
[i
]++;
5003 bucket_allocation_counts
[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy
->cond_policy_id
)]++;
5007 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
5008 if (bucket_allocation_counts
[i
] > 0) {
5009 // Allocate a NULL-terminated array of policy pointers for each bucket
5010 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
);
5011 if (necp_kernel_ip_output_policies_map
[i
] == NULL
) {
5015 // Initialize the first entry to NULL
5016 (necp_kernel_ip_output_policies_map
[i
])[0] = NULL
;
5018 bucket_current_free_index
[i
] = 0;
5021 LIST_FOREACH(kernel_policy
, &necp_kernel_ip_output_policies
, chain
) {
5022 // Insert pointers into map
5023 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
)) {
5024 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
5025 if (!necp_kernel_ip_output_policy_is_unnecessary(kernel_policy
, necp_kernel_ip_output_policies_map
[i
], bucket_current_free_index
[i
])) {
5026 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = kernel_policy
;
5027 bucket_current_free_index
[i
]++;
5028 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = NULL
;
5032 i
= NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy
->cond_policy_id
);
5033 if (!necp_kernel_ip_output_policy_is_unnecessary(kernel_policy
, necp_kernel_ip_output_policies_map
[i
], bucket_current_free_index
[i
])) {
5034 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = kernel_policy
;
5035 bucket_current_free_index
[i
]++;
5036 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = NULL
;
5040 necp_kernel_ip_output_policies_dump_all();
5044 // Free memory, reset mask to 0
5045 necp_kernel_ip_output_policies_condition_mask
= 0;
5046 necp_kernel_ip_output_policies_count
= 0;
5047 necp_kernel_ip_output_policies_non_id_count
= 0;
5048 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
5049 if (necp_kernel_ip_output_policies_map
[i
] != NULL
) {
5050 FREE(necp_kernel_ip_output_policies_map
[i
], M_NECP
);
5051 necp_kernel_ip_output_policies_map
[i
] = NULL
;
5057 // Outbound Policy Matching
5058 // ---------------------
5064 static struct substring
5065 necp_trim_dots_and_stars(char *string
, size_t length
)
5067 struct substring sub
;
5068 sub
.string
= string
;
5069 sub
.length
= string
? length
: 0;
5071 while (sub
.length
&& (sub
.string
[0] == '.' || sub
.string
[0] == '*')) {
5076 while (sub
.length
&& (sub
.string
[sub
.length
- 1] == '.' || sub
.string
[sub
.length
- 1] == '*')) {
5084 necp_create_trimmed_domain(char *string
, size_t length
)
5086 char *trimmed_domain
= NULL
;
5087 struct substring sub
= necp_trim_dots_and_stars(string
, length
);
5089 MALLOC(trimmed_domain
, char *, sub
.length
+ 1, M_NECP
, M_WAITOK
);
5090 if (trimmed_domain
== NULL
) {
5094 memcpy(trimmed_domain
, sub
.string
, sub
.length
);
5095 trimmed_domain
[sub
.length
] = 0;
5097 return (trimmed_domain
);
5101 necp_count_dots(char *string
, size_t length
)
5106 for (i
= 0; i
< length
; i
++) {
5107 if (string
[i
] == '.') {
5116 necp_check_suffix(struct substring parent
, struct substring suffix
, bool require_dot_before_suffix
)
5118 if (parent
.length
<= suffix
.length
) {
5122 size_t length_difference
= (parent
.length
- suffix
.length
);
5124 if (require_dot_before_suffix
) {
5125 if (((char *)(parent
.string
+ length_difference
- 1))[0] != '.') {
5130 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
5131 return (strncasecmp(parent
.string
+ length_difference
, suffix
.string
, suffix
.length
) == 0);
5135 necp_hostname_matches_domain(struct substring hostname_substring
, u_int8_t hostname_dot_count
, char *domain
, u_int8_t domain_dot_count
)
5137 if (hostname_substring
.string
== NULL
|| domain
== NULL
) {
5138 return (hostname_substring
.string
== domain
);
5141 struct substring domain_substring
;
5142 domain_substring
.string
= domain
;
5143 domain_substring
.length
= strlen(domain
);
5145 if (hostname_dot_count
== domain_dot_count
) {
5146 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
5147 if (hostname_substring
.length
== domain_substring
.length
&&
5148 strncasecmp(hostname_substring
.string
, domain_substring
.string
, hostname_substring
.length
) == 0) {
5151 } else if (domain_dot_count
< hostname_dot_count
) {
5152 if (necp_check_suffix(hostname_substring
, domain_substring
, TRUE
)) {
5161 necp_copy_string(char *string
, size_t length
)
5163 char *copied_string
= NULL
;
5165 MALLOC(copied_string
, char *, length
+ 1, M_NECP
, M_WAITOK
);
5166 if (copied_string
== NULL
) {
5170 memcpy(copied_string
, string
, length
);
5171 copied_string
[length
] = 0;
5173 return (copied_string
);
5176 #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)
5178 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
)
5180 memset(info
, 0, sizeof(struct necp_socket_info
));
5184 info
->protocol
= protocol
;
5185 info
->bound_interface_index
= bound_interface_index
;
5186 info
->traffic_class
= traffic_class
;
5188 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
&& proc
!= NULL
) {
5189 info
->cred_result
= priv_check_cred(proc_ucred(proc
), PRIV_NET_PRIVILEGED_NECP_MATCH
, 0);
5192 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_APP_ID
&& !uuid_is_null(application_uuid
)) {
5193 struct necp_uuid_id_mapping
*existing_mapping
= necp_uuid_lookup_app_id_locked(application_uuid
);
5194 if (existing_mapping
) {
5195 info
->application_id
= existing_mapping
->id
;
5199 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
&& !uuid_is_null(real_application_uuid
)) {
5200 if (uuid_compare(application_uuid
, real_application_uuid
) == 0) {
5201 info
->real_application_id
= info
->application_id
;
5203 struct necp_uuid_id_mapping
*existing_mapping
= necp_uuid_lookup_app_id_locked(real_application_uuid
);
5204 if (existing_mapping
) {
5205 info
->real_application_id
= existing_mapping
->id
;
5210 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
&& account
!= NULL
) {
5211 struct necp_string_id_mapping
*existing_mapping
= necp_lookup_string_to_id_locked(&necp_account_id_list
, account
);
5212 if (existing_mapping
) {
5213 info
->account_id
= existing_mapping
->id
;
5217 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
5218 info
->domain
= domain
;
5221 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_ADDRESS_TYPE_CONDITIONS
) {
5222 if (local_addr
&& local_addr
->sa
.sa_len
> 0) {
5223 memcpy(&info
->local_addr
, local_addr
, local_addr
->sa
.sa_len
);
5225 if (remote_addr
&& remote_addr
->sa
.sa_len
> 0) {
5226 memcpy(&info
->remote_addr
, remote_addr
, remote_addr
->sa
.sa_len
);
5232 necp_send_application_interface_denied_event(pid_t pid
, uuid_t proc_uuid
, u_int32_t if_functional_type
)
5234 struct kev_netpolicy_ifdenied ev_ifdenied
;
5236 bzero(&ev_ifdenied
, sizeof(ev_ifdenied
));
5238 ev_ifdenied
.ev_data
.epid
= pid
;
5239 uuid_copy(ev_ifdenied
.ev_data
.euuid
, proc_uuid
);
5240 ev_ifdenied
.ev_if_functional_type
= if_functional_type
;
5242 netpolicy_post_msg(KEV_NETPOLICY_IFDENIED
, &ev_ifdenied
.ev_data
, sizeof(ev_ifdenied
));
5245 extern char *proc_name_address(void *p
);
5247 #define NECP_VERIFY_DELEGATION_ENTITLEMENT(_p, _d) \
5248 if (!has_checked_delegation_entitlement) { \
5249 has_delegation_entitlement = (priv_check_cred(proc_ucred(_p), PRIV_NET_PRIVILEGED_SOCKET_DELEGATE, 0) == 0); \
5250 has_checked_delegation_entitlement = TRUE; \
5252 if (!has_delegation_entitlement) { \
5253 NECPLOG(LOG_ERR, "%s(%d) does not hold the necessary entitlement to delegate network traffic for other processes by %s", \
5254 proc_name_address(_p), proc_pid(_p), _d); \
5259 necp_application_find_policy_match_internal(proc_t proc
,
5260 u_int8_t
*parameters
,
5261 u_int32_t parameters_size
,
5262 struct necp_aggregate_result
*returned_result
,
5264 u_int required_interface_index
)
5269 struct necp_kernel_socket_policy
*matched_policy
= NULL
;
5270 struct necp_socket_info info
;
5271 necp_kernel_policy_filter filter_control_unit
= 0;
5272 u_int32_t route_rule_id
= 0;
5273 necp_kernel_policy_result service_action
= 0;
5274 necp_kernel_policy_service service
= { 0, 0 };
5276 u_int16_t protocol
= 0;
5277 u_int32_t bound_interface_index
= required_interface_index
;
5278 u_int32_t traffic_class
= 0;
5279 union necp_sockaddr_union local_addr
;
5280 union necp_sockaddr_union remote_addr
;
5281 bool no_remote_addr
= FALSE
;
5282 u_int8_t remote_family
= 0;
5283 bool no_local_addr
= FALSE
;
5285 memset(&local_addr
, 0, sizeof(local_addr
));
5286 memset(&remote_addr
, 0, sizeof(remote_addr
));
5288 // Initialize UID, PID, and UUIDs to the current process
5289 uid_t uid
= kauth_cred_getuid(proc_ucred(proc
));
5290 pid_t pid
= proc_pid(proc
);
5291 uuid_t application_uuid
;
5292 uuid_clear(application_uuid
);
5293 uuid_t real_application_uuid
;
5294 uuid_clear(real_application_uuid
);
5295 proc_getexecutableuuid(proc
, real_application_uuid
, sizeof(real_application_uuid
));
5296 uuid_copy(application_uuid
, real_application_uuid
);
5298 char *domain
= NULL
;
5299 char *account
= NULL
;
5301 u_int32_t netagent_ids
[NECP_MAX_NETAGENTS
];
5302 memset(&netagent_ids
, 0, sizeof(netagent_ids
));
5303 int netagent_cursor
;
5305 bool has_checked_delegation_entitlement
= FALSE
;
5306 bool has_delegation_entitlement
= FALSE
;
5308 if (returned_result
== NULL
) {
5312 memset(returned_result
, 0, sizeof(struct necp_aggregate_result
));
5314 lck_rw_lock_shared(&necp_kernel_policy_lock
);
5315 if (necp_kernel_application_policies_count
== 0) {
5316 if (necp_drop_all_order
> 0) {
5317 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
5318 lck_rw_done(&necp_kernel_policy_lock
);
5322 lck_rw_done(&necp_kernel_policy_lock
);
5324 while ((offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)) <= parameters_size
) {
5325 u_int8_t type
= necp_buffer_get_tlv_type(parameters
, offset
);
5326 u_int32_t length
= necp_buffer_get_tlv_length(parameters
, offset
);
5328 if (length
> (parameters_size
- (offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)))) {
5329 // If the length is larger than what can fit in the remaining parameters size, bail
5330 NECPLOG(LOG_ERR
, "Invalid TLV length (%u)", length
);
5335 u_int8_t
*value
= necp_buffer_get_tlv_value(parameters
, offset
, NULL
);
5336 if (value
!= NULL
) {
5338 case NECP_CLIENT_PARAMETER_APPLICATION
: {
5339 if (length
>= sizeof(uuid_t
)) {
5340 if (uuid_compare(application_uuid
, value
) == 0) {
5345 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc
, "euuid");
5347 uuid_copy(application_uuid
, value
);
5351 case NECP_CLIENT_PARAMETER_REAL_APPLICATION
: {
5352 if (length
>= sizeof(uuid_t
)) {
5353 if (uuid_compare(real_application_uuid
, value
) == 0) {
5358 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc
, "uuid");
5360 uuid_copy(real_application_uuid
, value
);
5364 case NECP_CLIENT_PARAMETER_PID
: {
5365 if (length
>= sizeof(pid_t
)) {
5366 if (memcmp(&pid
, value
, sizeof(pid_t
)) == 0) {
5371 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc
, "pid");
5373 memcpy(&pid
, value
, sizeof(pid_t
));
5377 case NECP_CLIENT_PARAMETER_UID
: {
5378 if (length
>= sizeof(uid_t
)) {
5379 if (memcmp(&uid
, value
, sizeof(uid_t
)) == 0) {
5384 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc
, "uid");
5386 memcpy(&uid
, value
, sizeof(uid_t
));
5390 case NECP_CLIENT_PARAMETER_DOMAIN
: {
5391 domain
= (char *)value
;
5392 domain
[length
- 1] = 0;
5395 case NECP_CLIENT_PARAMETER_ACCOUNT
: {
5396 account
= (char *)value
;
5397 account
[length
- 1] = 0;
5400 case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS
: {
5401 if (length
>= sizeof(u_int32_t
)) {
5402 memcpy(&traffic_class
, value
, sizeof(u_int32_t
));
5406 case NECP_CLIENT_PARAMETER_IP_PROTOCOL
: {
5407 if (length
>= sizeof(u_int16_t
)) {
5408 memcpy(&protocol
, value
, sizeof(u_int16_t
));
5412 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE
: {
5413 if (length
<= IFXNAMSIZ
&& length
> 0) {
5414 ifnet_t bound_interface
= NULL
;
5415 char interface_name
[IFXNAMSIZ
];
5416 memcpy(interface_name
, value
, length
);
5417 interface_name
[length
- 1] = 0; // Make sure the string is NULL terminated
5418 if (ifnet_find_by_name(interface_name
, &bound_interface
) == 0) {
5419 bound_interface_index
= bound_interface
->if_index
;
5420 ifnet_release(bound_interface
);
5425 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS
: {
5426 if (length
>= sizeof(struct necp_policy_condition_addr
)) {
5427 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)value
;
5428 if (necp_address_is_valid(&address_struct
->address
.sa
)) {
5429 memcpy(&local_addr
, &address_struct
->address
, sizeof(address_struct
->address
));
5434 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS
: {
5435 if (length
>= sizeof(struct necp_policy_condition_addr
)) {
5436 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)value
;
5437 if (necp_address_is_valid(&address_struct
->address
.sa
)) {
5438 memcpy(&remote_addr
, &address_struct
->address
, sizeof(address_struct
->address
));
5450 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
5454 lck_rw_lock_shared(&necp_kernel_policy_lock
);
5456 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
);
5457 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
);
5458 if (matched_policy
) {
5459 returned_result
->policy_id
= matched_policy
->id
;
5460 returned_result
->routing_result
= matched_policy
->result
;
5461 memcpy(&returned_result
->routing_result_parameter
, &matched_policy
->result_parameter
, sizeof(returned_result
->routing_result_parameter
));
5463 returned_result
->policy_id
= 0;
5464 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_NONE
;
5466 returned_result
->filter_control_unit
= filter_control_unit
;
5467 returned_result
->service_action
= service_action
;
5469 // Handle trigger service
5470 if (service
.identifier
!= 0) {
5471 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(service
.identifier
);
5472 if (mapping
!= NULL
) {
5473 struct necp_service_registration
*service_registration
= NULL
;
5474 uuid_copy(returned_result
->service_uuid
, mapping
->uuid
);
5475 returned_result
->service_data
= service
.data
;
5476 if (service
.identifier
== NECP_NULL_SERVICE_ID
) {
5477 // NULL service is always 'registered'
5478 returned_result
->service_flags
|= NECP_SERVICE_FLAGS_REGISTERED
;
5480 LIST_FOREACH(service_registration
, &necp_registered_service_list
, kernel_chain
) {
5481 if (service
.identifier
== service_registration
->service_id
) {
5482 returned_result
->service_flags
|= NECP_SERVICE_FLAGS_REGISTERED
;
5491 for (netagent_cursor
= 0; netagent_cursor
< NECP_MAX_NETAGENTS
; netagent_cursor
++) {
5492 struct necp_uuid_id_mapping
*mapping
= NULL
;
5493 u_int32_t netagent_id
= netagent_ids
[netagent_cursor
];
5494 if (netagent_id
== 0) {
5497 mapping
= necp_uuid_lookup_uuid_with_service_id_locked(netagent_id
);
5498 if (mapping
!= NULL
) {
5499 uuid_copy(returned_result
->netagents
[netagent_cursor
], mapping
->uuid
);
5500 returned_result
->netagent_flags
[netagent_cursor
] = netagent_get_flags(mapping
->uuid
);
5504 // Do routing evaluation
5505 u_int output_bound_interface
= bound_interface_index
;
5506 if (returned_result
->routing_result
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
) {
5507 output_bound_interface
= returned_result
->routing_result_parameter
.scoped_interface_index
;
5508 } else if (returned_result
->routing_result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
) {
5509 output_bound_interface
= returned_result
->routing_result_parameter
.tunnel_interface_index
;
5512 if (local_addr
.sa
.sa_len
== 0 ||
5513 (local_addr
.sa
.sa_family
== AF_INET
&& local_addr
.sin
.sin_addr
.s_addr
== 0) ||
5514 (local_addr
.sa
.sa_family
== AF_INET6
&& IN6_IS_ADDR_UNSPECIFIED(&local_addr
.sin6
.sin6_addr
))) {
5515 no_local_addr
= TRUE
;
5518 if (remote_addr
.sa
.sa_len
== 0 ||
5519 (remote_addr
.sa
.sa_family
== AF_INET
&& remote_addr
.sin
.sin_addr
.s_addr
== 0) ||
5520 (remote_addr
.sa
.sa_family
== AF_INET6
&& IN6_IS_ADDR_UNSPECIFIED(&remote_addr
.sin6
.sin6_addr
))) {
5521 no_remote_addr
= TRUE
;
5522 remote_family
= remote_addr
.sa
.sa_family
;
5525 if (no_remote_addr
) {
5526 memset(&remote_addr
, 0, sizeof(remote_addr
));
5527 if (remote_family
== AF_INET6
) {
5528 // Reset address to ::
5529 remote_addr
.sa
.sa_family
= AF_INET6
;
5530 remote_addr
.sa
.sa_len
= sizeof(struct sockaddr_in6
);
5532 // Reset address to 0.0.0.0
5533 remote_addr
.sa
.sa_family
= AF_INET
;
5534 remote_addr
.sa
.sa_len
= sizeof(struct sockaddr_in
);
5538 struct rtentry
*rt
= NULL
;
5539 rt
= rtalloc1_scoped((struct sockaddr
*)&remote_addr
, 0, 0,
5540 output_bound_interface
);
5542 if (no_remote_addr
&& remote_family
== 0 &&
5543 (rt
== NULL
|| rt
->rt_ifp
== NULL
)) {
5544 // Route lookup for default IPv4 failed, try IPv6
5546 // Cleanup old route if necessary
5552 // Reset address to ::
5553 memset(&remote_addr
, 0, sizeof(remote_addr
));
5554 remote_addr
.sa
.sa_family
= AF_INET6
;
5555 remote_addr
.sa
.sa_len
= sizeof(struct sockaddr_in6
);
5558 rt
= rtalloc1_scoped((struct sockaddr
*)&remote_addr
, 0, 0,
5559 output_bound_interface
);
5562 returned_result
->routed_interface_index
= 0;
5564 rt
->rt_ifp
!= NULL
) {
5565 returned_result
->routed_interface_index
= rt
->rt_ifp
->if_index
;
5567 * For local addresses, we allow the interface scope to be
5568 * either the loopback interface or the interface hosting the
5571 if (bound_interface_index
!= IFSCOPE_NONE
&&
5572 rt
->rt_ifa
!= NULL
&& rt
->rt_ifa
->ifa_ifp
&&
5573 (output_bound_interface
== lo_ifp
->if_index
||
5574 rt
->rt_ifp
->if_index
== lo_ifp
->if_index
||
5575 rt
->rt_ifa
->ifa_ifp
->if_index
== bound_interface_index
)) {
5576 struct sockaddr_storage dst
;
5577 unsigned int ifscope
= bound_interface_index
;
5580 * Transform dst into the internal routing table form
5582 (void) sa_copy((struct sockaddr
*)&remote_addr
,
5585 if ((rt
->rt_ifp
->if_index
== lo_ifp
->if_index
) ||
5586 rt_ifa_is_dst((struct sockaddr
*)&dst
, rt
->rt_ifa
))
5587 returned_result
->routed_interface_index
=
5588 bound_interface_index
;
5592 if (returned_result
->routed_interface_index
!= 0 &&
5593 returned_result
->routed_interface_index
!= lo_ifp
->if_index
&& // Loopback can accept any local address
5596 // Transform local_addr into the ifaddr form
5597 // IPv6 Scope IDs are always embedded in the ifaddr list
5598 struct sockaddr_storage local_address_sanitized
;
5599 u_int ifscope
= IFSCOPE_NONE
;
5600 (void)sa_copy(&local_addr
.sa
, &local_address_sanitized
, &ifscope
);
5601 SIN(&local_address_sanitized
)->sin_port
= 0;
5602 if (local_address_sanitized
.ss_family
== AF_INET6
) {
5603 SIN6(&local_address_sanitized
)->sin6_scope_id
= 0;
5606 // Validate local address on routed interface
5607 struct ifaddr
*ifa
= ifa_ifwithaddr_scoped((struct sockaddr
*)&local_address_sanitized
, returned_result
->routed_interface_index
);
5609 // Interface address not found, reject route
5610 returned_result
->routed_interface_index
= 0;
5616 ifaddr_release(ifa
);
5621 if (flags
!= NULL
) {
5622 // Check for local/direct
5623 bool is_local
= FALSE
;
5624 if (rt
!= NULL
&& (rt
->rt_flags
& RTF_LOCAL
)) {
5626 } else if (returned_result
->routed_interface_index
!= 0 &&
5628 // Check if remote address is an interface address
5629 struct ifaddr
*ifa
= ifa_ifwithaddr(&remote_addr
.sa
);
5630 if (ifa
!= NULL
&& ifa
->ifa_ifp
!= NULL
) {
5631 u_int if_index_for_remote_addr
= ifa
->ifa_ifp
->if_index
;
5632 if (if_index_for_remote_addr
== returned_result
->routed_interface_index
||
5633 if_index_for_remote_addr
== lo_ifp
->if_index
) {
5638 ifaddr_release(ifa
);
5644 *flags
|= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL
| NECP_CLIENT_RESULT_FLAG_IS_DIRECT
);
5647 !(rt
->rt_flags
& RTF_GATEWAY
) &&
5648 (rt
->rt_ifa
&& rt
->rt_ifa
->ifa_ifp
&& !(rt
->rt_ifa
->ifa_ifp
->if_flags
& IFF_POINTOPOINT
))) {
5649 // Route is directly accessible
5650 *flags
|= NECP_CLIENT_RESULT_FLAG_IS_DIRECT
;
5654 if (returned_result
->routed_interface_index
!= 0) {
5655 union necp_sockaddr_union default_address
;
5656 struct rtentry
*v4Route
= NULL
;
5657 struct rtentry
*v6Route
= NULL
;
5659 memset(&default_address
, 0, sizeof(default_address
));
5661 // Reset address to 0.0.0.0
5662 default_address
.sa
.sa_family
= AF_INET
;
5663 default_address
.sa
.sa_len
= sizeof(struct sockaddr_in
);
5664 v4Route
= rtalloc1_scoped((struct sockaddr
*)&default_address
, 0, 0,
5665 returned_result
->routed_interface_index
);
5667 // Reset address to ::
5668 default_address
.sa
.sa_family
= AF_INET6
;
5669 default_address
.sa
.sa_len
= sizeof(struct sockaddr_in6
);
5670 v6Route
= rtalloc1_scoped((struct sockaddr
*)&default_address
, 0, 0,
5671 returned_result
->routed_interface_index
);
5673 if (v4Route
!= NULL
) {
5674 if (v4Route
->rt_ifp
!= NULL
) {
5675 *flags
|= NECP_CLIENT_RESULT_FLAG_HAS_IPV4
;
5681 if (v6Route
!= NULL
) {
5682 if (v6Route
->rt_ifp
!= NULL
) {
5683 *flags
|= NECP_CLIENT_RESULT_FLAG_HAS_IPV6
;
5691 u_int32_t interface_type_denied
= IFRTYPE_FUNCTIONAL_UNKNOWN
;
5692 bool route_is_allowed
= necp_route_is_allowed(rt
, NULL
, route_rule_id
, &interface_type_denied
);
5693 if (!route_is_allowed
) {
5694 // If the route is blocked, treat the lookup as a drop
5695 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
5696 memset(&returned_result
->routing_result_parameter
, 0, sizeof(returned_result
->routing_result_parameter
));
5698 if (interface_type_denied
!= IFRTYPE_FUNCTIONAL_UNKNOWN
) {
5699 necp_send_application_interface_denied_event(pid
, application_uuid
, interface_type_denied
);
5708 lck_rw_done(&necp_kernel_policy_lock
);
5714 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
)
5716 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) {
5717 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
5718 u_int32_t cond_bound_interface_index
= kernel_policy
->cond_bound_interface
? kernel_policy
->cond_bound_interface
->if_index
: 0;
5719 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
5720 if (bound_interface_index
== cond_bound_interface_index
) {
5721 // No match, matches forbidden interface
5725 if (bound_interface_index
!= cond_bound_interface_index
) {
5726 // No match, does not match required interface
5731 if (bound_interface_index
!= 0) {
5732 // No match, requires a non-bound packet
5738 if (kernel_policy
->condition_mask
== 0) {
5742 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
5743 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
5744 if (app_id
== kernel_policy
->cond_app_id
) {
5745 // No match, matches forbidden application
5749 if (app_id
!= kernel_policy
->cond_app_id
) {
5750 // No match, does not match required application
5756 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
5757 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
5758 if (real_app_id
== kernel_policy
->cond_real_app_id
) {
5759 // No match, matches forbidden application
5763 if (real_app_id
!= kernel_policy
->cond_real_app_id
) {
5764 // No match, does not match required application
5770 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
) {
5771 if (cred_result
!= 0) {
5772 // Process is missing entitlement
5777 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) {
5778 if (kernel_policy
->cond_custom_entitlement_matched
== necp_boolean_state_false
) {
5779 // Process is missing entitlement based on previous check
5781 } else if (kernel_policy
->cond_custom_entitlement_matched
== necp_boolean_state_unknown
) {
5782 if (kernel_policy
->cond_custom_entitlement
!= NULL
) {
5784 // No process found, cannot check entitlement
5787 task_t task
= proc_task(proc
);
5789 !IOTaskHasEntitlement(task
, kernel_policy
->cond_custom_entitlement
)) {
5790 // Process is missing custom entitlement
5791 kernel_policy
->cond_custom_entitlement_matched
= necp_boolean_state_false
;
5794 kernel_policy
->cond_custom_entitlement_matched
= necp_boolean_state_true
;
5800 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
5801 bool domain_matches
= necp_hostname_matches_domain(domain
, domain_dot_count
, kernel_policy
->cond_domain
, kernel_policy
->cond_domain_dot_count
);
5802 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
5803 if (domain_matches
) {
5804 // No match, matches forbidden domain
5808 if (!domain_matches
) {
5809 // No match, does not match required domain
5815 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
5816 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
5817 if (account_id
== kernel_policy
->cond_account_id
) {
5818 // No match, matches forbidden account
5822 if (account_id
!= kernel_policy
->cond_account_id
) {
5823 // No match, does not match required account
5829 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PID
) {
5830 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_PID
) {
5831 if (pid
== kernel_policy
->cond_pid
) {
5832 // No match, matches forbidden pid
5836 if (pid
!= kernel_policy
->cond_pid
) {
5837 // No match, does not match required pid
5843 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_UID
) {
5844 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_UID
) {
5845 if (uid
== kernel_policy
->cond_uid
) {
5846 // No match, matches forbidden uid
5850 if (uid
!= kernel_policy
->cond_uid
) {
5851 // No match, does not match required uid
5857 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
5858 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
5859 if (traffic_class
>= kernel_policy
->cond_traffic_class
.start_tc
&&
5860 traffic_class
<= kernel_policy
->cond_traffic_class
.end_tc
) {
5861 // No match, matches forbidden traffic class
5865 if (traffic_class
< kernel_policy
->cond_traffic_class
.start_tc
||
5866 traffic_class
> kernel_policy
->cond_traffic_class
.end_tc
) {
5867 // No match, does not match required traffic class
5873 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
5874 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
5875 if (protocol
== kernel_policy
->cond_protocol
) {
5876 // No match, matches forbidden protocol
5880 if (protocol
!= kernel_policy
->cond_protocol
) {
5881 // No match, does not match required protocol
5887 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
5888 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
5889 bool inRange
= necp_is_addr_in_range((struct sockaddr
*)local
, (struct sockaddr
*)&kernel_policy
->cond_local_start
, (struct sockaddr
*)&kernel_policy
->cond_local_end
);
5890 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
5899 } else if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
5900 bool inSubnet
= necp_is_addr_in_subnet((struct sockaddr
*)local
, (struct sockaddr
*)&kernel_policy
->cond_local_start
, kernel_policy
->cond_local_prefix
);
5901 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
5913 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
5914 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
5915 bool inRange
= necp_is_addr_in_range((struct sockaddr
*)remote
, (struct sockaddr
*)&kernel_policy
->cond_remote_start
, (struct sockaddr
*)&kernel_policy
->cond_remote_end
);
5916 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
5925 } else if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
5926 bool inSubnet
= necp_is_addr_in_subnet((struct sockaddr
*)remote
, (struct sockaddr
*)&kernel_policy
->cond_remote_start
, kernel_policy
->cond_remote_prefix
);
5927 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
5942 static inline u_int32_t
5943 necp_socket_calc_flowhash_locked(struct necp_socket_info
*info
)
5945 return (net_flowhash(info
, sizeof(*info
), necp_kernel_socket_policies_gencount
));
5949 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
)
5951 struct socket
*so
= NULL
;
5953 memset(info
, 0, sizeof(struct necp_socket_info
));
5955 so
= inp
->inp_socket
;
5957 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_PID
) {
5958 info
->pid
= ((so
->so_flags
& SOF_DELEGATED
) ? so
->e_pid
: so
->last_pid
);
5961 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_UID
) {
5962 info
->uid
= kauth_cred_getuid(so
->so_cred
);
5965 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
5966 info
->traffic_class
= so
->so_traffic_class
;
5969 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
5970 if (inp
->inp_ip_p
) {
5971 info
->protocol
= inp
->inp_ip_p
;
5973 info
->protocol
= SOCK_PROTO(so
);
5977 if (inp
->inp_flags2
& INP2_WANT_APP_POLICY
&& necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
5978 struct necp_uuid_id_mapping
*existing_mapping
= necp_uuid_lookup_app_id_locked(((so
->so_flags
& SOF_DELEGATED
) ? so
->e_uuid
: so
->last_uuid
));
5979 if (existing_mapping
) {
5980 info
->application_id
= existing_mapping
->id
;
5983 if (!(so
->so_flags
& SOF_DELEGATED
)) {
5984 info
->real_application_id
= info
->application_id
;
5985 } else if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
5986 struct necp_uuid_id_mapping
*real_existing_mapping
= necp_uuid_lookup_app_id_locked(so
->last_uuid
);
5987 if (real_existing_mapping
) {
5988 info
->real_application_id
= real_existing_mapping
->id
;
5992 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
) {
5993 info
->cred_result
= priv_check_cred(so
->so_cred
, PRIV_NET_PRIVILEGED_NECP_MATCH
, 0);
5997 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
&& inp
->inp_necp_attributes
.inp_account
!= NULL
) {
5998 struct necp_string_id_mapping
*existing_mapping
= necp_lookup_string_to_id_locked(&necp_account_id_list
, inp
->inp_necp_attributes
.inp_account
);
5999 if (existing_mapping
) {
6000 info
->account_id
= existing_mapping
->id
;
6004 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
6005 info
->domain
= inp
->inp_necp_attributes
.inp_domain
;
6008 if (override_bound_interface
) {
6009 info
->bound_interface_index
= override_bound_interface
;
6011 if ((inp
->inp_flags
& INP_BOUND_IF
) && inp
->inp_boundifp
) {
6012 info
->bound_interface_index
= inp
->inp_boundifp
->if_index
;
6016 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_ADDRESS_TYPE_CONDITIONS
) {
6017 if (inp
->inp_vflag
& INP_IPV4
) {
6018 if (override_local_addr
) {
6019 if (override_local_addr
->sa_len
<= sizeof(struct sockaddr_in
)) {
6020 memcpy(&info
->local_addr
, override_local_addr
, override_local_addr
->sa_len
);
6023 ((struct sockaddr_in
*)&info
->local_addr
)->sin_family
= AF_INET
;
6024 ((struct sockaddr_in
*)&info
->local_addr
)->sin_len
= sizeof(struct sockaddr_in
);
6025 ((struct sockaddr_in
*)&info
->local_addr
)->sin_port
= inp
->inp_lport
;
6026 memcpy(&((struct sockaddr_in
*)&info
->local_addr
)->sin_addr
, &inp
->inp_laddr
, sizeof(struct in_addr
));
6029 if (override_remote_addr
) {
6030 if (override_remote_addr
->sa_len
<= sizeof(struct sockaddr_in
)) {
6031 memcpy(&info
->remote_addr
, override_remote_addr
, override_remote_addr
->sa_len
);
6034 ((struct sockaddr_in
*)&info
->remote_addr
)->sin_family
= AF_INET
;
6035 ((struct sockaddr_in
*)&info
->remote_addr
)->sin_len
= sizeof(struct sockaddr_in
);
6036 ((struct sockaddr_in
*)&info
->remote_addr
)->sin_port
= inp
->inp_fport
;
6037 memcpy(&((struct sockaddr_in
*)&info
->remote_addr
)->sin_addr
, &inp
->inp_faddr
, sizeof(struct in_addr
));
6039 } else if (inp
->inp_vflag
& INP_IPV6
) {
6040 if (override_local_addr
) {
6041 if (override_local_addr
->sa_len
<= sizeof(struct sockaddr_in6
)) {
6042 memcpy(&info
->local_addr
, override_local_addr
, override_local_addr
->sa_len
);
6045 ((struct sockaddr_in6
*)&info
->local_addr
)->sin6_family
= AF_INET6
;
6046 ((struct sockaddr_in6
*)&info
->local_addr
)->sin6_len
= sizeof(struct sockaddr_in6
);
6047 ((struct sockaddr_in6
*)&info
->local_addr
)->sin6_port
= inp
->inp_lport
;
6048 memcpy(&((struct sockaddr_in6
*)&info
->local_addr
)->sin6_addr
, &inp
->in6p_laddr
, sizeof(struct in6_addr
));
6051 if (override_remote_addr
) {
6052 if (override_remote_addr
->sa_len
<= sizeof(struct sockaddr_in6
)) {
6053 memcpy(&info
->remote_addr
, override_remote_addr
, override_remote_addr
->sa_len
);
6056 ((struct sockaddr_in6
*)&info
->remote_addr
)->sin6_family
= AF_INET6
;
6057 ((struct sockaddr_in6
*)&info
->remote_addr
)->sin6_len
= sizeof(struct sockaddr_in6
);
6058 ((struct sockaddr_in6
*)&info
->remote_addr
)->sin6_port
= inp
->inp_fport
;
6059 memcpy(&((struct sockaddr_in6
*)&info
->remote_addr
)->sin6_addr
, &inp
->in6p_faddr
, sizeof(struct in6_addr
));
6065 static inline struct necp_kernel_socket_policy
*
6066 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
)
6068 struct necp_kernel_socket_policy
*matched_policy
= NULL
;
6069 u_int32_t skip_order
= 0;
6070 u_int32_t skip_session_order
= 0;
6071 u_int32_t route_rule_id_array
[MAX_AGGREGATE_ROUTE_RULES
];
6072 size_t route_rule_id_count
= 0;
6074 size_t netagent_cursor
= 0;
6076 // Pre-process domain for quick matching
6077 struct substring domain_substring
= necp_trim_dots_and_stars(info
->domain
, info
->domain
? strlen(info
->domain
) : 0);
6078 u_int8_t domain_dot_count
= necp_count_dots(domain_substring
.string
, domain_substring
.length
);
6080 if (return_filter
) {
6084 if (return_route_rule_id
) {
6085 *return_route_rule_id
= 0;
6088 if (return_service_action
) {
6089 *return_service_action
= 0;
6092 if (return_service
) {
6093 return_service
->identifier
= 0;
6094 return_service
->data
= 0;
6097 if (policy_search_array
!= NULL
) {
6098 for (i
= 0; policy_search_array
[i
] != NULL
; i
++) {
6099 if (necp_drop_all_order
!= 0 && policy_search_array
[i
]->session_order
>= necp_drop_all_order
) {
6100 // We've hit a drop all rule
6103 if (skip_session_order
&& policy_search_array
[i
]->session_order
>= skip_session_order
) {
6106 skip_session_order
= 0;
6109 if (policy_search_array
[i
]->order
< skip_order
) {
6115 skip_session_order
= 0;
6117 } else if (skip_session_order
) {
6121 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
)) {
6122 if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER
) {
6123 if (return_filter
&& *return_filter
== 0) {
6124 *return_filter
= policy_search_array
[i
]->result_parameter
.filter_control_unit
;
6125 if (necp_debug
> 1) {
6126 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
);
6130 } else if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_ROUTE_RULES
) {
6131 if (return_route_rule_id
&& route_rule_id_count
< MAX_AGGREGATE_ROUTE_RULES
) {
6132 route_rule_id_array
[route_rule_id_count
++] = policy_search_array
[i
]->result_parameter
.route_rule_id
;
6133 if (necp_debug
> 1) {
6134 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
);
6138 } else if (necp_kernel_socket_result_is_trigger_service_type(policy_search_array
[i
])) {
6139 if (return_service_action
&& *return_service_action
== 0) {
6140 *return_service_action
= policy_search_array
[i
]->result
;
6141 if (necp_debug
> 1) {
6142 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
);
6145 if (return_service
&& return_service
->identifier
== 0) {
6146 return_service
->identifier
= policy_search_array
[i
]->result_parameter
.service
.identifier
;
6147 return_service
->data
= policy_search_array
[i
]->result_parameter
.service
.data
;
6148 if (necp_debug
> 1) {
6149 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
);
6153 } else if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_USE_NETAGENT
) {
6154 if (return_netagent_array
!= NULL
&&
6155 netagent_cursor
< netagent_array_count
) {
6156 return_netagent_array
[netagent_cursor
] = policy_search_array
[i
]->result_parameter
.netagent_id
;
6158 if (necp_debug
> 1) {
6159 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
);
6165 // Matched policy is a skip. Do skip and continue.
6166 if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
6167 skip_order
= policy_search_array
[i
]->result_parameter
.skip_policy_order
;
6168 skip_session_order
= policy_search_array
[i
]->session_order
+ 1;
6172 // Passed all tests, found a match
6173 matched_policy
= policy_search_array
[i
];
6179 if (route_rule_id_count
== 1) {
6180 *return_route_rule_id
= route_rule_id_array
[0];
6181 } else if (route_rule_id_count
> 1) {
6182 *return_route_rule_id
= necp_create_aggregate_route_rule(route_rule_id_array
);
6184 return (matched_policy
);
6188 necp_socket_uses_interface(struct inpcb
*inp
, u_int32_t interface_index
)
6190 bool found_match
= FALSE
;
6192 ifaddr_t
*addresses
= NULL
;
6193 union necp_sockaddr_union address_storage
;
6195 int family
= AF_INET
;
6196 ifnet_t interface
= ifindex2ifnet
[interface_index
];
6198 if (inp
== NULL
|| interface
== NULL
) {
6202 if (inp
->inp_vflag
& INP_IPV4
) {
6204 } else if (inp
->inp_vflag
& INP_IPV6
) {
6208 result
= ifnet_get_address_list_family(interface
, &addresses
, family
);
6210 NECPLOG(LOG_ERR
, "Failed to get address list for %s%d", ifnet_name(interface
), ifnet_unit(interface
));
6214 for (i
= 0; addresses
[i
] != NULL
; i
++) {
6215 if (ifaddr_address(addresses
[i
], &address_storage
.sa
, sizeof(address_storage
)) == 0) {
6216 if (family
== AF_INET
) {
6217 if (memcmp(&address_storage
.sin
.sin_addr
, &inp
->inp_laddr
, sizeof(inp
->inp_laddr
)) == 0) {
6221 } else if (family
== AF_INET6
) {
6222 if (memcmp(&address_storage
.sin6
.sin6_addr
, &inp
->in6p_laddr
, sizeof(inp
->in6p_laddr
)) == 0) {
6231 ifnet_free_address_list(addresses
);
6233 return (found_match
);
6237 necp_socket_is_connected(struct inpcb
*inp
)
6239 return (inp
->inp_socket
->so_state
& (SS_ISCONNECTING
| SS_ISCONNECTED
| SS_ISDISCONNECTING
));
6243 necp_socket_bypass(struct sockaddr
*override_local_addr
, struct sockaddr
*override_remote_addr
, struct inpcb
*inp
)
6246 if (necp_pass_loopback
> 0 && necp_is_loopback(override_local_addr
, override_remote_addr
, inp
, NULL
)) {
6248 } else if (necp_is_intcoproc(inp
, NULL
)) {
6255 necp_kernel_policy_id
6256 necp_socket_find_policy_match(struct inpcb
*inp
, struct sockaddr
*override_local_addr
, struct sockaddr
*override_remote_addr
, u_int32_t override_bound_interface
)
6258 struct socket
*so
= NULL
;
6259 necp_kernel_policy_filter filter_control_unit
= 0;
6260 u_int32_t route_rule_id
= 0;
6261 struct necp_kernel_socket_policy
*matched_policy
= NULL
;
6262 necp_kernel_policy_id matched_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
6263 necp_kernel_policy_result service_action
= 0;
6264 necp_kernel_policy_service service
= { 0, 0 };
6266 u_int32_t netagent_ids
[NECP_MAX_NETAGENTS
];
6267 memset(&netagent_ids
, 0, sizeof(netagent_ids
));
6268 int netagent_cursor
;
6270 struct necp_socket_info info
;
6273 return (NECP_KERNEL_POLICY_ID_NONE
);
6276 // Ignore invalid addresses
6277 if (override_local_addr
!= NULL
&&
6278 !necp_address_is_valid(override_local_addr
)) {
6279 override_local_addr
= NULL
;
6281 if (override_remote_addr
!= NULL
&&
6282 !necp_address_is_valid(override_remote_addr
)) {
6283 override_remote_addr
= NULL
;
6286 so
= inp
->inp_socket
;
6288 // Don't lock. Possible race condition, but we don't want the performance hit.
6289 if (necp_kernel_socket_policies_count
== 0 ||
6290 (!(inp
->inp_flags2
& INP2_WANT_APP_POLICY
) && necp_kernel_socket_policies_non_app_count
== 0)) {
6291 if (necp_drop_all_order
> 0) {
6292 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6293 inp
->inp_policyresult
.policy_gencount
= 0;
6294 inp
->inp_policyresult
.app_id
= 0;
6295 inp
->inp_policyresult
.flowhash
= 0;
6296 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
6297 inp
->inp_policyresult
.results
.route_rule_id
= 0;
6298 if (necp_socket_bypass(override_local_addr
, override_remote_addr
, inp
)) {
6299 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_PASS
;
6301 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6304 return (NECP_KERNEL_POLICY_ID_NONE
);
6307 // Check for loopback exception
6308 if (necp_socket_bypass(override_local_addr
, override_remote_addr
, inp
)) {
6309 // Mark socket as a pass
6310 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6311 inp
->inp_policyresult
.policy_gencount
= 0;
6312 inp
->inp_policyresult
.app_id
= 0;
6313 inp
->inp_policyresult
.flowhash
= 0;
6314 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
6315 inp
->inp_policyresult
.results
.route_rule_id
= 0;
6316 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_PASS
;
6317 return (NECP_KERNEL_POLICY_ID_NONE
);
6321 lck_rw_lock_shared(&necp_kernel_policy_lock
);
6323 necp_socket_fillout_info_locked(inp
, override_local_addr
, override_remote_addr
, override_bound_interface
, &info
);
6324 inp
->inp_policyresult
.app_id
= info
.application_id
;
6327 u_int32_t flowhash
= necp_socket_calc_flowhash_locked(&info
);
6328 if (inp
->inp_policyresult
.policy_id
!= NECP_KERNEL_POLICY_ID_NONE
&&
6329 inp
->inp_policyresult
.policy_gencount
== necp_kernel_socket_policies_gencount
&&
6330 inp
->inp_policyresult
.flowhash
== flowhash
) {
6331 // If already matched this socket on this generation of table, skip
6334 lck_rw_done(&necp_kernel_policy_lock
);
6336 return (inp
->inp_policyresult
.policy_id
);
6339 // Match socket to policy
6340 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());
6341 // If the socket matched a scoped service policy, mark as Drop if not registered.
6342 // This covers the cases in which a service is required (on demand) but hasn't started yet.
6343 if ((service_action
== NECP_KERNEL_POLICY_RESULT_TRIGGER_SCOPED
||
6344 service_action
== NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED
) &&
6345 service
.identifier
!= 0 &&
6346 service
.identifier
!= NECP_NULL_SERVICE_ID
) {
6347 bool service_is_registered
= FALSE
;
6348 struct necp_service_registration
*service_registration
= NULL
;
6349 LIST_FOREACH(service_registration
, &necp_registered_service_list
, kernel_chain
) {
6350 if (service
.identifier
== service_registration
->service_id
) {
6351 service_is_registered
= TRUE
;
6355 if (!service_is_registered
) {
6356 // Mark socket as a drop if service is not registered
6357 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6358 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
6359 inp
->inp_policyresult
.flowhash
= flowhash
;
6360 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
6361 inp
->inp_policyresult
.results
.route_rule_id
= 0;
6362 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6364 if (necp_debug
> 1) {
6365 NECPLOG(LOG_DEBUG
, "Socket Policy: (BoundInterface %d Proto %d) Dropping packet because service is not registered", info
.bound_interface_index
, info
.protocol
);
6369 lck_rw_done(&necp_kernel_policy_lock
);
6370 return (NECP_KERNEL_POLICY_ID_NONE
);
6374 for (netagent_cursor
= 0; netagent_cursor
< NECP_MAX_NETAGENTS
; netagent_cursor
++) {
6375 struct necp_uuid_id_mapping
*mapping
= NULL
;
6376 u_int32_t netagent_id
= netagent_ids
[netagent_cursor
];
6377 if (netagent_id
== 0) {
6380 mapping
= necp_uuid_lookup_uuid_with_service_id_locked(netagent_id
);
6381 if (mapping
!= NULL
) {
6382 u_int32_t agent_flags
= 0;
6383 agent_flags
= netagent_get_flags(mapping
->uuid
);
6384 if (agent_flags
& NETAGENT_FLAG_REGISTERED
) {
6385 if (agent_flags
& NETAGENT_FLAG_ACTIVE
) {
6387 } else if ((agent_flags
& NETAGENT_FLAG_VOLUNTARY
) == 0) {
6388 if (agent_flags
& NETAGENT_FLAG_KERNEL_ACTIVATED
) {
6389 int trigger_error
= 0;
6390 trigger_error
= netagent_kernel_trigger(mapping
->uuid
);
6391 if (necp_debug
> 1) {
6392 NECPLOG(LOG_DEBUG
, "Socket Policy: Triggering inactive agent, error %d", trigger_error
);
6396 // Mark socket as a drop if required agent is not active
6397 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6398 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
6399 inp
->inp_policyresult
.flowhash
= flowhash
;
6400 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
6401 inp
->inp_policyresult
.results
.route_rule_id
= 0;
6402 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6404 if (necp_debug
> 1) {
6405 NECPLOG(LOG_DEBUG
, "Socket Policy: (BoundInterface %d Proto %d) Dropping packet because agent is not active", info
.bound_interface_index
, info
.protocol
);
6409 lck_rw_done(&necp_kernel_policy_lock
);
6410 return (NECP_KERNEL_POLICY_ID_NONE
);
6415 if (matched_policy
) {
6416 matched_policy_id
= matched_policy
->id
;
6417 inp
->inp_policyresult
.policy_id
= matched_policy
->id
;
6418 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
6419 inp
->inp_policyresult
.flowhash
= flowhash
;
6420 inp
->inp_policyresult
.results
.filter_control_unit
= filter_control_unit
;
6421 inp
->inp_policyresult
.results
.route_rule_id
= route_rule_id
;
6422 inp
->inp_policyresult
.results
.result
= matched_policy
->result
;
6423 memcpy(&inp
->inp_policyresult
.results
.result_parameter
, &matched_policy
->result_parameter
, sizeof(matched_policy
->result_parameter
));
6425 if (necp_socket_is_connected(inp
) &&
6426 (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_DROP
||
6427 (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&& !necp_socket_uses_interface(inp
, matched_policy
->result_parameter
.tunnel_interface_index
)))) {
6429 NECPLOG(LOG_DEBUG
, "Marking socket in state %d as defunct", so
->so_state
);
6431 sosetdefunct(current_proc(), so
, SHUTDOWN_SOCKET_LEVEL_NECP
| SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL
, TRUE
);
6432 } else if (necp_socket_is_connected(inp
) &&
6433 matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&&
6434 info
.protocol
== IPPROTO_TCP
) {
6435 // Reset MSS on TCP socket if tunnel policy changes
6436 tcp_mtudisc(inp
, 0);
6439 if (necp_debug
> 1) {
6440 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
);
6442 } else if (necp_drop_all_order
> 0) {
6443 // Mark socket as a drop if set
6444 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6445 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
6446 inp
->inp_policyresult
.flowhash
= flowhash
;
6447 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
6448 inp
->inp_policyresult
.results
.route_rule_id
= 0;
6449 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6451 // Mark non-matching socket so we don't re-check it
6452 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6453 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
6454 inp
->inp_policyresult
.flowhash
= flowhash
;
6455 inp
->inp_policyresult
.results
.filter_control_unit
= filter_control_unit
; // We may have matched a filter, so mark it!
6456 inp
->inp_policyresult
.results
.route_rule_id
= route_rule_id
; // We may have matched a route rule, so mark it!
6457 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_NONE
;
6461 lck_rw_done(&necp_kernel_policy_lock
);
6463 return (matched_policy_id
);
6467 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
)
6469 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) {
6470 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
6471 u_int32_t cond_bound_interface_index
= kernel_policy
->cond_bound_interface
? kernel_policy
->cond_bound_interface
->if_index
: 0;
6472 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
6473 if (bound_interface_index
== cond_bound_interface_index
) {
6474 // No match, matches forbidden interface
6478 if (bound_interface_index
!= cond_bound_interface_index
) {
6479 // No match, does not match required interface
6484 if (bound_interface_index
!= 0) {
6485 // No match, requires a non-bound packet
6491 if (kernel_policy
->condition_mask
== 0) {
6495 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
) {
6496 if (socket_policy_id
!= kernel_policy
->cond_policy_id
) {
6497 // No match, does not match required id
6502 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LAST_INTERFACE
) {
6503 if (last_interface_index
!= kernel_policy
->cond_last_interface_index
) {
6508 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
6509 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
6510 if (protocol
== kernel_policy
->cond_protocol
) {
6511 // No match, matches forbidden protocol
6515 if (protocol
!= kernel_policy
->cond_protocol
) {
6516 // No match, does not match required protocol
6522 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
6523 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
6524 bool inRange
= necp_is_addr_in_range((struct sockaddr
*)local
, (struct sockaddr
*)&kernel_policy
->cond_local_start
, (struct sockaddr
*)&kernel_policy
->cond_local_end
);
6525 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
6534 } else if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
6535 bool inSubnet
= necp_is_addr_in_subnet((struct sockaddr
*)local
, (struct sockaddr
*)&kernel_policy
->cond_local_start
, kernel_policy
->cond_local_prefix
);
6536 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
6548 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
6549 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
6550 bool inRange
= necp_is_addr_in_range((struct sockaddr
*)remote
, (struct sockaddr
*)&kernel_policy
->cond_remote_start
, (struct sockaddr
*)&kernel_policy
->cond_remote_end
);
6551 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
6560 } else if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
6561 bool inSubnet
= necp_is_addr_in_subnet((struct sockaddr
*)remote
, (struct sockaddr
*)&kernel_policy
->cond_remote_start
, kernel_policy
->cond_remote_prefix
);
6562 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
6577 static inline struct necp_kernel_ip_output_policy
*
6578 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
)
6580 u_int32_t skip_order
= 0;
6581 u_int32_t skip_session_order
= 0;
6583 struct necp_kernel_ip_output_policy
*matched_policy
= NULL
;
6584 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
)];
6585 if (policy_search_array
!= NULL
) {
6586 for (i
= 0; policy_search_array
[i
] != NULL
; i
++) {
6587 if (necp_drop_all_order
!= 0 && policy_search_array
[i
]->session_order
>= necp_drop_all_order
) {
6588 // We've hit a drop all rule
6591 if (skip_session_order
&& policy_search_array
[i
]->session_order
>= skip_session_order
) {
6594 skip_session_order
= 0;
6597 if (policy_search_array
[i
]->order
< skip_order
) {
6603 skip_session_order
= 0;
6605 } else if (skip_session_order
) {
6609 if (necp_ip_output_check_policy(policy_search_array
[i
], socket_policy_id
, bound_interface_index
, last_interface_index
, protocol
, local_addr
, remote_addr
)) {
6610 // Passed all tests, found a match
6611 matched_policy
= policy_search_array
[i
];
6613 if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
6614 skip_order
= policy_search_array
[i
]->result_parameter
.skip_policy_order
;
6615 skip_session_order
= policy_search_array
[i
]->session_order
+ 1;
6624 return (matched_policy
);
6628 necp_output_bypass(struct mbuf
*packet
)
6630 if (necp_pass_loopback
> 0 && necp_is_loopback(NULL
, NULL
, NULL
, packet
)) {
6633 if (necp_pass_keepalives
> 0 && necp_get_is_keepalive_from_packet(packet
)) {
6636 if (necp_is_intcoproc(NULL
, packet
)) {
6642 necp_kernel_policy_id
6643 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
)
6645 struct ip
*ip
= NULL
;
6646 int hlen
= sizeof(struct ip
);
6647 necp_kernel_policy_id socket_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
6648 necp_kernel_policy_id matched_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
6649 struct necp_kernel_ip_output_policy
*matched_policy
= NULL
;
6650 u_int16_t protocol
= 0;
6651 u_int32_t bound_interface_index
= 0;
6652 u_int32_t last_interface_index
= 0;
6653 union necp_sockaddr_union local_addr
;
6654 union necp_sockaddr_union remote_addr
;
6660 if (result_parameter
) {
6661 memset(result_parameter
, 0, sizeof(*result_parameter
));
6664 if (packet
== NULL
) {
6665 return (NECP_KERNEL_POLICY_ID_NONE
);
6668 socket_policy_id
= necp_get_policy_id_from_packet(packet
);
6670 // Exit early for an empty list
6671 // Don't lock. Possible race condition, but we don't want the performance hit.
6672 if (necp_kernel_ip_output_policies_count
== 0 ||
6673 ((socket_policy_id
== NECP_KERNEL_POLICY_ID_NONE
) && necp_kernel_ip_output_policies_non_id_count
== 0)) {
6674 if (necp_drop_all_order
> 0) {
6675 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6677 if (necp_output_bypass(packet
)) {
6678 *result
= NECP_KERNEL_POLICY_RESULT_PASS
;
6680 *result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6685 return (matched_policy_id
);
6688 // Check for loopback exception
6689 if (necp_output_bypass(packet
)) {
6690 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6692 *result
= NECP_KERNEL_POLICY_RESULT_PASS
;
6694 return (matched_policy_id
);
6697 last_interface_index
= necp_get_last_interface_index_from_packet(packet
);
6699 // Process packet to get relevant fields
6700 ip
= mtod(packet
, struct ip
*);
6702 hlen
= _IP_VHL_HL(ip
->ip_vhl
) << 2;
6704 hlen
= ip
->ip_hl
<< 2;
6707 protocol
= ip
->ip_p
;
6709 if ((flags
& IP_OUTARGS
) && (ipoa
!= NULL
) &&
6710 (ipoa
->ipoa_flags
& IPOAF_BOUND_IF
) &&
6711 ipoa
->ipoa_boundif
!= IFSCOPE_NONE
) {
6712 bound_interface_index
= ipoa
->ipoa_boundif
;
6715 local_addr
.sin
.sin_family
= AF_INET
;
6716 local_addr
.sin
.sin_len
= sizeof(struct sockaddr_in
);
6717 memcpy(&local_addr
.sin
.sin_addr
, &ip
->ip_src
, sizeof(ip
->ip_src
));
6719 remote_addr
.sin
.sin_family
= AF_INET
;
6720 remote_addr
.sin
.sin_len
= sizeof(struct sockaddr_in
);
6721 memcpy(&((struct sockaddr_in
*)&remote_addr
)->sin_addr
, &ip
->ip_dst
, sizeof(ip
->ip_dst
));
6726 if ((int)(hlen
+ sizeof(th
)) <= packet
->m_pkthdr
.len
) {
6727 m_copydata(packet
, hlen
, sizeof(th
), (u_int8_t
*)&th
);
6728 ((struct sockaddr_in
*)&local_addr
)->sin_port
= th
.th_sport
;
6729 ((struct sockaddr_in
*)&remote_addr
)->sin_port
= th
.th_dport
;
6735 if ((int)(hlen
+ sizeof(uh
)) <= packet
->m_pkthdr
.len
) {
6736 m_copydata(packet
, hlen
, sizeof(uh
), (u_int8_t
*)&uh
);
6737 ((struct sockaddr_in
*)&local_addr
)->sin_port
= uh
.uh_sport
;
6738 ((struct sockaddr_in
*)&remote_addr
)->sin_port
= uh
.uh_dport
;
6743 ((struct sockaddr_in
*)&local_addr
)->sin_port
= 0;
6744 ((struct sockaddr_in
*)&remote_addr
)->sin_port
= 0;
6749 // Match packet to policy
6750 lck_rw_lock_shared(&necp_kernel_policy_lock
);
6751 matched_policy
= necp_ip_output_find_policy_match_locked(socket_policy_id
, bound_interface_index
, last_interface_index
, protocol
, &local_addr
, &remote_addr
);
6752 if (matched_policy
) {
6753 matched_policy_id
= matched_policy
->id
;
6755 *result
= matched_policy
->result
;
6758 if (result_parameter
) {
6759 memcpy(result_parameter
, &matched_policy
->result_parameter
, sizeof(matched_policy
->result_parameter
));
6762 if (necp_debug
> 1) {
6763 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
);
6765 } else if (necp_drop_all_order
> 0) {
6766 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6768 *result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6772 lck_rw_done(&necp_kernel_policy_lock
);
6774 return (matched_policy_id
);
6777 necp_kernel_policy_id
6778 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
)
6780 struct ip6_hdr
*ip6
= NULL
;
6783 necp_kernel_policy_id socket_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
6784 necp_kernel_policy_id matched_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
6785 struct necp_kernel_ip_output_policy
*matched_policy
= NULL
;
6786 u_int16_t protocol
= 0;
6787 u_int32_t bound_interface_index
= 0;
6788 u_int32_t last_interface_index
= 0;
6789 union necp_sockaddr_union local_addr
;
6790 union necp_sockaddr_union remote_addr
;
6796 if (result_parameter
) {
6797 memset(result_parameter
, 0, sizeof(*result_parameter
));
6800 if (packet
== NULL
) {
6801 return (NECP_KERNEL_POLICY_ID_NONE
);
6804 socket_policy_id
= necp_get_policy_id_from_packet(packet
);
6806 // Exit early for an empty list
6807 // Don't lock. Possible race condition, but we don't want the performance hit.
6808 if (necp_kernel_ip_output_policies_count
== 0 ||
6809 ((socket_policy_id
== NECP_KERNEL_POLICY_ID_NONE
) && necp_kernel_ip_output_policies_non_id_count
== 0)) {
6810 if (necp_drop_all_order
> 0) {
6811 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6813 if (necp_output_bypass(packet
)) {
6814 *result
= NECP_KERNEL_POLICY_RESULT_PASS
;
6816 *result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6821 return (matched_policy_id
);
6824 // Check for loopback exception
6825 if (necp_output_bypass(packet
)) {
6826 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6828 *result
= NECP_KERNEL_POLICY_RESULT_PASS
;
6830 return (matched_policy_id
);
6833 last_interface_index
= necp_get_last_interface_index_from_packet(packet
);
6835 // Process packet to get relevant fields
6836 ip6
= mtod(packet
, struct ip6_hdr
*);
6838 if ((flags
& IPV6_OUTARGS
) && (ip6oa
!= NULL
) &&
6839 (ip6oa
->ip6oa_flags
& IP6OAF_BOUND_IF
) &&
6840 ip6oa
->ip6oa_boundif
!= IFSCOPE_NONE
) {
6841 bound_interface_index
= ip6oa
->ip6oa_boundif
;
6844 ((struct sockaddr_in6
*)&local_addr
)->sin6_family
= AF_INET6
;
6845 ((struct sockaddr_in6
*)&local_addr
)->sin6_len
= sizeof(struct sockaddr_in6
);
6846 memcpy(&((struct sockaddr_in6
*)&local_addr
)->sin6_addr
, &ip6
->ip6_src
, sizeof(ip6
->ip6_src
));
6848 ((struct sockaddr_in6
*)&remote_addr
)->sin6_family
= AF_INET6
;
6849 ((struct sockaddr_in6
*)&remote_addr
)->sin6_len
= sizeof(struct sockaddr_in6
);
6850 memcpy(&((struct sockaddr_in6
*)&remote_addr
)->sin6_addr
, &ip6
->ip6_dst
, sizeof(ip6
->ip6_dst
));
6852 offset
= ip6_lasthdr(packet
, 0, IPPROTO_IPV6
, &next
);
6853 if (offset
>= 0 && packet
->m_pkthdr
.len
>= offset
) {
6858 if ((int)(offset
+ sizeof(th
)) <= packet
->m_pkthdr
.len
) {
6859 m_copydata(packet
, offset
, sizeof(th
), (u_int8_t
*)&th
);
6860 ((struct sockaddr_in6
*)&local_addr
)->sin6_port
= th
.th_sport
;
6861 ((struct sockaddr_in6
*)&remote_addr
)->sin6_port
= th
.th_dport
;
6867 if ((int)(offset
+ sizeof(uh
)) <= packet
->m_pkthdr
.len
) {
6868 m_copydata(packet
, offset
, sizeof(uh
), (u_int8_t
*)&uh
);
6869 ((struct sockaddr_in6
*)&local_addr
)->sin6_port
= uh
.uh_sport
;
6870 ((struct sockaddr_in6
*)&remote_addr
)->sin6_port
= uh
.uh_dport
;
6875 ((struct sockaddr_in6
*)&local_addr
)->sin6_port
= 0;
6876 ((struct sockaddr_in6
*)&remote_addr
)->sin6_port
= 0;
6882 // Match packet to policy
6883 lck_rw_lock_shared(&necp_kernel_policy_lock
);
6884 matched_policy
= necp_ip_output_find_policy_match_locked(socket_policy_id
, bound_interface_index
, last_interface_index
, protocol
, &local_addr
, &remote_addr
);
6885 if (matched_policy
) {
6886 matched_policy_id
= matched_policy
->id
;
6888 *result
= matched_policy
->result
;
6891 if (result_parameter
) {
6892 memcpy(result_parameter
, &matched_policy
->result_parameter
, sizeof(matched_policy
->result_parameter
));
6895 if (necp_debug
> 1) {
6896 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
);
6898 } else if (necp_drop_all_order
> 0) {
6899 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6901 *result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6905 lck_rw_done(&necp_kernel_policy_lock
);
6907 return (matched_policy_id
);
6912 necp_is_addr_in_range(struct sockaddr
*addr
, struct sockaddr
*range_start
, struct sockaddr
*range_end
)
6916 if (addr
== NULL
|| range_start
== NULL
|| range_end
== NULL
) {
6920 /* Must be greater than or equal to start */
6921 cmp
= necp_addr_compare(addr
, range_start
, 1);
6922 if (cmp
!= 0 && cmp
!= 1) {
6926 /* Must be less than or equal to end */
6927 cmp
= necp_addr_compare(addr
, range_end
, 1);
6928 if (cmp
!= 0 && cmp
!= -1) {
6936 necp_is_range_in_range(struct sockaddr
*inner_range_start
, struct sockaddr
*inner_range_end
, struct sockaddr
*range_start
, struct sockaddr
*range_end
)
6940 if (inner_range_start
== NULL
|| inner_range_end
== NULL
|| range_start
== NULL
|| range_end
== NULL
) {
6944 /* Must be greater than or equal to start */
6945 cmp
= necp_addr_compare(inner_range_start
, range_start
, 1);
6946 if (cmp
!= 0 && cmp
!= 1) {
6950 /* Must be less than or equal to end */
6951 cmp
= necp_addr_compare(inner_range_end
, range_end
, 1);
6952 if (cmp
!= 0 && cmp
!= -1) {
6960 necp_is_addr_in_subnet(struct sockaddr
*addr
, struct sockaddr
*subnet_addr
, u_int8_t subnet_prefix
)
6962 if (addr
== NULL
|| subnet_addr
== NULL
) {
6966 if (addr
->sa_family
!= subnet_addr
->sa_family
|| addr
->sa_len
!= subnet_addr
->sa_len
) {
6970 switch (addr
->sa_family
) {
6972 if (satosin(subnet_addr
)->sin_port
!= 0 &&
6973 satosin(addr
)->sin_port
!= satosin(subnet_addr
)->sin_port
) {
6976 return (necp_buffer_compare_with_bit_prefix((u_int8_t
*)&satosin(addr
)->sin_addr
, (u_int8_t
*)&satosin(subnet_addr
)->sin_addr
, subnet_prefix
));
6979 if (satosin6(subnet_addr
)->sin6_port
!= 0 &&
6980 satosin6(addr
)->sin6_port
!= satosin6(subnet_addr
)->sin6_port
) {
6983 if (satosin6(addr
)->sin6_scope_id
&&
6984 satosin6(subnet_addr
)->sin6_scope_id
&&
6985 satosin6(addr
)->sin6_scope_id
!= satosin6(subnet_addr
)->sin6_scope_id
) {
6988 return (necp_buffer_compare_with_bit_prefix((u_int8_t
*)&satosin6(addr
)->sin6_addr
, (u_int8_t
*)&satosin6(subnet_addr
)->sin6_addr
, subnet_prefix
));
7003 * 2: Not comparable or error
7006 necp_addr_compare(struct sockaddr
*sa1
, struct sockaddr
*sa2
, int check_port
)
7009 int port_result
= 0;
7011 if (sa1
->sa_family
!= sa2
->sa_family
|| sa1
->sa_len
!= sa2
->sa_len
) {
7015 if (sa1
->sa_len
== 0) {
7019 switch (sa1
->sa_family
) {
7021 if (sa1
->sa_len
!= sizeof(struct sockaddr_in
)) {
7025 result
= memcmp(&satosin(sa1
)->sin_addr
.s_addr
, &satosin(sa2
)->sin_addr
.s_addr
, sizeof(satosin(sa1
)->sin_addr
.s_addr
));
7028 if (satosin(sa1
)->sin_port
< satosin(sa2
)->sin_port
) {
7030 } else if (satosin(sa1
)->sin_port
> satosin(sa2
)->sin_port
) {
7035 result
= port_result
;
7036 } else if ((result
> 0 && port_result
< 0) || (result
< 0 && port_result
> 0)) {
7044 if (sa1
->sa_len
!= sizeof(struct sockaddr_in6
)) {
7048 if (satosin6(sa1
)->sin6_scope_id
!= satosin6(sa2
)->sin6_scope_id
) {
7052 result
= memcmp(&satosin6(sa1
)->sin6_addr
.s6_addr
[0], &satosin6(sa2
)->sin6_addr
.s6_addr
[0], sizeof(struct in6_addr
));
7055 if (satosin6(sa1
)->sin6_port
< satosin6(sa2
)->sin6_port
) {
7057 } else if (satosin6(sa1
)->sin6_port
> satosin6(sa2
)->sin6_port
) {
7062 result
= port_result
;
7063 } else if ((result
> 0 && port_result
< 0) || (result
< 0 && port_result
> 0)) {
7071 result
= memcmp(sa1
, sa2
, sa1
->sa_len
);
7078 } else if (result
> 0) {
7086 necp_buffer_compare_with_bit_prefix(u_int8_t
*p1
, u_int8_t
*p2
, u_int32_t bits
)
7090 /* Handle null pointers */
7091 if (p1
== NULL
|| p2
== NULL
) {
7096 if (*p1
++ != *p2
++) {
7103 mask
= ~((1<<(8-bits
))-1);
7104 if ((*p1
& mask
) != (*p2
& mask
)) {
7112 necp_socket_update_qos_marking_inner(struct ifnet
*ifp
, u_int32_t route_rule_id
)
7114 bool qos_marking
= FALSE
;
7115 int exception_index
= 0;
7116 struct necp_route_rule
*route_rule
= NULL
;
7118 route_rule
= necp_lookup_route_rule_locked(&necp_route_rules
, route_rule_id
);
7119 if (route_rule
== NULL
) {
7120 qos_marking
= FALSE
;
7124 qos_marking
= (route_rule
->default_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? TRUE
: FALSE
;
7130 for (exception_index
= 0; exception_index
< MAX_ROUTE_RULE_INTERFACES
; exception_index
++) {
7131 if (route_rule
->exception_if_indices
[exception_index
] == 0) {
7134 if (route_rule
->exception_if_actions
[exception_index
] != NECP_ROUTE_RULE_QOS_MARKING
) {
7137 if (route_rule
->exception_if_indices
[exception_index
] == ifp
->if_index
) {
7139 if (necp_debug
> 2) {
7140 NECPLOG(LOG_DEBUG
, "QoS Marking : Interface match %d for Rule %d Allowed %d",
7141 route_rule
->exception_if_indices
[exception_index
], route_rule_id
, qos_marking
);
7147 if ((route_rule
->cellular_action
== NECP_ROUTE_RULE_QOS_MARKING
&& IFNET_IS_CELLULAR(ifp
)) ||
7148 (route_rule
->wifi_action
== NECP_ROUTE_RULE_QOS_MARKING
&& IFNET_IS_WIFI(ifp
)) ||
7149 (route_rule
->wired_action
== NECP_ROUTE_RULE_QOS_MARKING
&& IFNET_IS_WIRED(ifp
)) ||
7150 (route_rule
->expensive_action
== NECP_ROUTE_RULE_QOS_MARKING
&& IFNET_IS_EXPENSIVE(ifp
))) {
7152 if (necp_debug
> 2) {
7153 NECPLOG(LOG_DEBUG
, "QoS Marking: C:%d WF:%d W:%d E:%d for Rule %d Allowed %d",
7154 route_rule
->cellular_action
, route_rule
->wifi_action
, route_rule
->wired_action
,
7155 route_rule
->expensive_action
, route_rule_id
, qos_marking
);
7160 if (necp_debug
> 1) {
7161 NECPLOG(LOG_DEBUG
, "QoS Marking: Rule %d ifp %s Allowed %d",
7162 route_rule_id
, ifp
? ifp
->if_xname
: "", qos_marking
);
7164 return (qos_marking
);
7168 necp_socket_update_qos_marking(struct inpcb
*inp
, struct rtentry
*route
, struct ifnet
*interface
, u_int32_t route_rule_id
)
7170 bool qos_marking
= FALSE
;
7171 struct ifnet
*ifp
= interface
= NULL
;
7173 ASSERT(net_qos_policy_restricted
!= 0);
7175 if (inp
->inp_socket
== NULL
) {
7178 if ((inp
->inp_socket
->so_flags1
& SOF1_QOSMARKING_POLICY_OVERRIDE
)) {
7182 * This is racy but we do not need the performance hit of taking necp_kernel_policy_lock
7184 if (inp
->inp_policyresult
.results
.qos_marking_gencount
== necp_kernel_socket_policies_gencount
) {
7188 lck_rw_lock_shared(&necp_kernel_policy_lock
);
7190 if (ifp
== NULL
&& route
!= NULL
) {
7191 ifp
= route
->rt_ifp
;
7194 * By default, until we have a interface, do not mark and reevaluate the Qos marking policy
7196 if (ifp
== NULL
|| route_rule_id
== 0) {
7197 qos_marking
= FALSE
;
7201 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id
)) {
7202 struct necp_aggregate_route_rule
*aggregate_route_rule
= necp_lookup_aggregate_route_rule_locked(route_rule_id
);
7203 if (aggregate_route_rule
!= NULL
) {
7205 for (index
= 0; index
< MAX_AGGREGATE_ROUTE_RULES
; index
++) {
7206 u_int32_t sub_route_rule_id
= aggregate_route_rule
->rule_ids
[index
];
7207 if (sub_route_rule_id
== 0) {
7210 qos_marking
= necp_socket_update_qos_marking_inner(ifp
, sub_route_rule_id
);
7211 if (qos_marking
== TRUE
) {
7217 qos_marking
= necp_socket_update_qos_marking_inner(ifp
, route_rule_id
);
7220 * Now that we have an interface we remember the gencount
7222 inp
->inp_policyresult
.results
.qos_marking_gencount
= necp_kernel_socket_policies_gencount
;
7225 lck_rw_done(&necp_kernel_policy_lock
);
7227 if (qos_marking
== TRUE
) {
7228 inp
->inp_socket
->so_flags1
|= SOF1_QOSMARKING_ALLOWED
;
7230 inp
->inp_socket
->so_flags1
&= ~SOF1_QOSMARKING_ALLOWED
;
7235 necp_route_is_allowed_inner(struct rtentry
*route
, struct ifnet
*ifp
, u_int32_t route_rule_id
, u_int32_t
*interface_type_denied
)
7237 bool default_is_allowed
= TRUE
;
7238 u_int8_t type_aggregate_action
= NECP_ROUTE_RULE_NONE
;
7239 int exception_index
= 0;
7240 struct ifnet
*delegated_ifp
= NULL
;
7241 struct necp_route_rule
*route_rule
= NULL
;
7243 route_rule
= necp_lookup_route_rule_locked(&necp_route_rules
, route_rule_id
);
7244 if (route_rule
== NULL
) {
7248 default_is_allowed
= (route_rule
->default_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? FALSE
: TRUE
;
7250 ifp
= route
->rt_ifp
;
7253 if (necp_debug
> 1 && !default_is_allowed
) {
7254 NECPLOG(LOG_DEBUG
, "Route Allowed: No interface for route, using default for Rule %d Allowed %d", route_rule_id
, default_is_allowed
);
7256 return (default_is_allowed
);
7259 delegated_ifp
= ifp
->if_delegated
.ifp
;
7260 for (exception_index
= 0; exception_index
< MAX_ROUTE_RULE_INTERFACES
; exception_index
++) {
7261 if (route_rule
->exception_if_indices
[exception_index
] == 0) {
7264 if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->exception_if_actions
[exception_index
]) == FALSE
) {
7267 if (route_rule
->exception_if_indices
[exception_index
] == ifp
->if_index
||
7268 (delegated_ifp
!= NULL
&& route_rule
->exception_if_indices
[exception_index
] == delegated_ifp
->if_index
)) {
7269 if (necp_debug
> 1) {
7270 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
));
7272 return ((route_rule
->exception_if_actions
[exception_index
] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? FALSE
: TRUE
);
7276 if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->cellular_action
) &&
7277 IFNET_IS_CELLULAR(ifp
)) {
7278 if (interface_type_denied
!= NULL
) {
7279 *interface_type_denied
= IFRTYPE_FUNCTIONAL_CELLULAR
;
7281 if (type_aggregate_action
== NECP_ROUTE_RULE_NONE
||
7282 (type_aggregate_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
&&
7283 route_rule
->cellular_action
== NECP_ROUTE_RULE_DENY_INTERFACE
)) {
7284 // Deny wins if there is a conflict
7285 type_aggregate_action
= route_rule
->cellular_action
;
7289 if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->wifi_action
) &&
7290 IFNET_IS_WIFI(ifp
)) {
7291 if (interface_type_denied
!= NULL
) {
7292 *interface_type_denied
= IFRTYPE_FUNCTIONAL_WIFI_INFRA
;
7294 if (type_aggregate_action
== NECP_ROUTE_RULE_NONE
||
7295 (type_aggregate_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
&&
7296 route_rule
->wifi_action
== NECP_ROUTE_RULE_DENY_INTERFACE
)) {
7297 // Deny wins if there is a conflict
7298 type_aggregate_action
= route_rule
->wifi_action
;
7302 if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->wired_action
) &&
7303 IFNET_IS_WIRED(ifp
)) {
7304 if (interface_type_denied
!= NULL
) {
7305 *interface_type_denied
= IFRTYPE_FUNCTIONAL_WIRED
;
7307 if (type_aggregate_action
== NECP_ROUTE_RULE_NONE
||
7308 (type_aggregate_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
&&
7309 route_rule
->wired_action
== NECP_ROUTE_RULE_DENY_INTERFACE
)) {
7310 // Deny wins if there is a conflict
7311 type_aggregate_action
= route_rule
->wired_action
;
7315 if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->expensive_action
) &&
7316 IFNET_IS_EXPENSIVE(ifp
)) {
7317 if (type_aggregate_action
== NECP_ROUTE_RULE_NONE
||
7318 (type_aggregate_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
&&
7319 route_rule
->expensive_action
== NECP_ROUTE_RULE_DENY_INTERFACE
)) {
7320 // Deny wins if there is a conflict
7321 type_aggregate_action
= route_rule
->expensive_action
;
7325 if (type_aggregate_action
!= NECP_ROUTE_RULE_NONE
) {
7326 if (necp_debug
> 1) {
7327 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
));
7329 return ((type_aggregate_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? FALSE
: TRUE
);
7332 if (necp_debug
> 1 && !default_is_allowed
) {
7333 NECPLOG(LOG_DEBUG
, "Route Allowed: Using default for Rule %d Allowed %d", route_rule_id
, default_is_allowed
);
7335 return (default_is_allowed
);
7339 necp_route_is_allowed(struct rtentry
*route
, struct ifnet
*interface
, u_int32_t route_rule_id
, u_int32_t
*interface_type_denied
)
7341 if ((route
== NULL
&& interface
== NULL
) || route_rule_id
== 0) {
7342 if (necp_debug
> 1) {
7343 NECPLOG(LOG_DEBUG
, "Route Allowed: no route or interface, Rule %d Allowed %d", route_rule_id
, TRUE
);
7348 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id
)) {
7349 struct necp_aggregate_route_rule
*aggregate_route_rule
= necp_lookup_aggregate_route_rule_locked(route_rule_id
);
7350 if (aggregate_route_rule
!= NULL
) {
7352 for (index
= 0; index
< MAX_AGGREGATE_ROUTE_RULES
; index
++) {
7353 u_int32_t sub_route_rule_id
= aggregate_route_rule
->rule_ids
[index
];
7354 if (sub_route_rule_id
== 0) {
7357 if (!necp_route_is_allowed_inner(route
, interface
, sub_route_rule_id
, interface_type_denied
)) {
7363 return (necp_route_is_allowed_inner(route
, interface
, route_rule_id
, interface_type_denied
));
7370 necp_packet_is_allowed_over_interface(struct mbuf
*packet
, struct ifnet
*interface
)
7372 bool is_allowed
= TRUE
;
7373 u_int32_t route_rule_id
= necp_get_route_rule_id_from_packet(packet
);
7374 if (route_rule_id
!= 0 &&
7375 interface
!= NULL
) {
7376 lck_rw_lock_shared(&necp_kernel_policy_lock
);
7377 is_allowed
= necp_route_is_allowed(NULL
, interface
, necp_get_route_rule_id_from_packet(packet
), NULL
);
7378 lck_rw_done(&necp_kernel_policy_lock
);
7380 return (is_allowed
);
7384 necp_netagents_allow_traffic(u_int32_t
*netagent_ids
, size_t netagent_id_count
)
7386 size_t netagent_cursor
;
7387 for (netagent_cursor
= 0; netagent_cursor
< netagent_id_count
; netagent_cursor
++) {
7388 struct necp_uuid_id_mapping
*mapping
= NULL
;
7389 u_int32_t netagent_id
= netagent_ids
[netagent_cursor
];
7390 if (netagent_id
== 0) {
7393 mapping
= necp_uuid_lookup_uuid_with_service_id_locked(netagent_id
);
7394 if (mapping
!= NULL
) {
7395 u_int32_t agent_flags
= 0;
7396 agent_flags
= netagent_get_flags(mapping
->uuid
);
7397 if (agent_flags
& NETAGENT_FLAG_REGISTERED
) {
7398 if (agent_flags
& NETAGENT_FLAG_ACTIVE
) {
7400 } else if ((agent_flags
& NETAGENT_FLAG_VOLUNTARY
) == 0) {
7410 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
)
7412 u_int32_t verifyifindex
= interface
? interface
->if_index
: 0;
7413 bool allowed_to_receive
= TRUE
;
7414 struct necp_socket_info info
;
7415 u_int32_t flowhash
= 0;
7416 necp_kernel_policy_result service_action
= 0;
7417 necp_kernel_policy_service service
= { 0, 0 };
7418 u_int32_t route_rule_id
= 0;
7419 struct rtentry
*route
= NULL
;
7420 u_int32_t interface_type_denied
= IFRTYPE_FUNCTIONAL_UNKNOWN
;
7422 u_int32_t netagent_ids
[NECP_MAX_NETAGENTS
];
7423 memset(&netagent_ids
, 0, sizeof(netagent_ids
));
7425 if (return_policy_id
) {
7426 *return_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
7428 if (return_route_rule_id
) {
7429 *return_route_rule_id
= 0;
7436 route
= inp
->inp_route
.ro_rt
;
7438 // Don't lock. Possible race condition, but we don't want the performance hit.
7439 if (necp_kernel_socket_policies_count
== 0 ||
7440 (!(inp
->inp_flags2
& INP2_WANT_APP_POLICY
) && necp_kernel_socket_policies_non_app_count
== 0)) {
7441 if (necp_drop_all_order
> 0) {
7442 if (necp_socket_bypass(override_local_addr
, override_remote_addr
, inp
)) {
7443 allowed_to_receive
= TRUE
;
7445 allowed_to_receive
= FALSE
;
7451 // If this socket is connected, or we are not taking addresses into account, try to reuse last result
7452 if ((necp_socket_is_connected(inp
) || (override_local_addr
== NULL
&& override_remote_addr
== NULL
)) && inp
->inp_policyresult
.policy_id
!= NECP_KERNEL_POLICY_ID_NONE
) {
7453 bool policies_have_changed
= FALSE
;
7454 bool route_allowed
= TRUE
;
7455 lck_rw_lock_shared(&necp_kernel_policy_lock
);
7456 if (inp
->inp_policyresult
.policy_gencount
!= necp_kernel_socket_policies_gencount
) {
7457 policies_have_changed
= TRUE
;
7459 if (inp
->inp_policyresult
.results
.route_rule_id
!= 0 &&
7460 !necp_route_is_allowed(route
, interface
, inp
->inp_policyresult
.results
.route_rule_id
, &interface_type_denied
)) {
7461 route_allowed
= FALSE
;
7464 lck_rw_done(&necp_kernel_policy_lock
);
7466 if (!policies_have_changed
) {
7467 if (!route_allowed
||
7468 inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_DROP
||
7469 inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
||
7470 (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&& interface
&&
7471 inp
->inp_policyresult
.results
.result_parameter
.tunnel_interface_index
!= verifyifindex
)) {
7472 allowed_to_receive
= FALSE
;
7474 if (return_policy_id
) {
7475 *return_policy_id
= inp
->inp_policyresult
.policy_id
;
7477 if (return_route_rule_id
) {
7478 *return_route_rule_id
= inp
->inp_policyresult
.results
.route_rule_id
;
7485 // Check for loopback exception
7486 if (necp_socket_bypass(override_local_addr
, override_remote_addr
, inp
)) {
7487 allowed_to_receive
= TRUE
;
7491 // Actually calculate policy result
7492 lck_rw_lock_shared(&necp_kernel_policy_lock
);
7493 necp_socket_fillout_info_locked(inp
, override_local_addr
, override_remote_addr
, 0, &info
);
7495 flowhash
= necp_socket_calc_flowhash_locked(&info
);
7496 if (inp
->inp_policyresult
.policy_id
!= NECP_KERNEL_POLICY_ID_NONE
&&
7497 inp
->inp_policyresult
.policy_gencount
== necp_kernel_socket_policies_gencount
&&
7498 inp
->inp_policyresult
.flowhash
== flowhash
) {
7499 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_DROP
||
7500 inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
||
7501 (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&& interface
&&
7502 inp
->inp_policyresult
.results
.result_parameter
.tunnel_interface_index
!= verifyifindex
) ||
7503 (inp
->inp_policyresult
.results
.route_rule_id
!= 0 &&
7504 !necp_route_is_allowed(route
, interface
, inp
->inp_policyresult
.results
.route_rule_id
, &interface_type_denied
))) {
7505 allowed_to_receive
= FALSE
;
7507 if (return_policy_id
) {
7508 *return_policy_id
= inp
->inp_policyresult
.policy_id
;
7510 if (return_route_rule_id
) {
7511 *return_route_rule_id
= inp
->inp_policyresult
.results
.route_rule_id
;
7514 lck_rw_done(&necp_kernel_policy_lock
);
7518 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());
7519 if (matched_policy
!= NULL
) {
7520 if (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_DROP
||
7521 matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
||
7522 (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&& interface
&&
7523 matched_policy
->result_parameter
.tunnel_interface_index
!= verifyifindex
) ||
7524 ((service_action
== NECP_KERNEL_POLICY_RESULT_TRIGGER_SCOPED
||
7525 service_action
== NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED
) &&
7526 service
.identifier
!= 0 && service
.identifier
!= NECP_NULL_SERVICE_ID
) ||
7527 (route_rule_id
!= 0 &&
7528 !necp_route_is_allowed(route
, interface
, route_rule_id
, &interface_type_denied
)) ||
7529 !necp_netagents_allow_traffic(netagent_ids
, NECP_MAX_NETAGENTS
)) {
7530 allowed_to_receive
= FALSE
;
7532 if (return_policy_id
) {
7533 *return_policy_id
= matched_policy
->id
;
7535 if (return_route_rule_id
) {
7536 *return_route_rule_id
= route_rule_id
;
7539 lck_rw_done(&necp_kernel_policy_lock
);
7541 if (necp_debug
> 1 && matched_policy
->id
!= inp
->inp_policyresult
.policy_id
) {
7542 NECPLOG(LOG_DEBUG
, "Socket Send/Recv Policy: Policy %d Allowed %d", return_policy_id
? *return_policy_id
: 0, allowed_to_receive
);
7545 } else if (necp_drop_all_order
> 0) {
7546 allowed_to_receive
= FALSE
;
7548 if (return_policy_id
) {
7549 *return_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
7551 if (return_route_rule_id
) {
7552 *return_route_rule_id
= route_rule_id
;
7556 lck_rw_done(&necp_kernel_policy_lock
);
7559 if (!allowed_to_receive
&& interface_type_denied
!= IFRTYPE_FUNCTIONAL_UNKNOWN
) {
7560 soevent(inp
->inp_socket
, (SO_FILT_HINT_LOCKED
| SO_FILT_HINT_IFDENIED
));
7563 return (allowed_to_receive
);
7567 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
)
7569 struct sockaddr_in local
;
7570 struct sockaddr_in remote
;
7571 local
.sin_family
= remote
.sin_family
= AF_INET
;
7572 local
.sin_len
= remote
.sin_len
= sizeof(struct sockaddr_in
);
7573 local
.sin_port
= local_port
;
7574 remote
.sin_port
= remote_port
;
7575 memcpy(&local
.sin_addr
, local_addr
, sizeof(local
.sin_addr
));
7576 memcpy(&remote
.sin_addr
, remote_addr
, sizeof(remote
.sin_addr
));
7578 return (necp_socket_is_allowed_to_send_recv_internal(inp
, (struct sockaddr
*)&local
, (struct sockaddr
*)&remote
, interface
, return_policy_id
, return_route_rule_id
));
7582 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
)
7584 struct sockaddr_in6 local
;
7585 struct sockaddr_in6 remote
;
7586 local
.sin6_family
= remote
.sin6_family
= AF_INET6
;
7587 local
.sin6_len
= remote
.sin6_len
= sizeof(struct sockaddr_in6
);
7588 local
.sin6_port
= local_port
;
7589 remote
.sin6_port
= remote_port
;
7590 memcpy(&local
.sin6_addr
, local_addr
, sizeof(local
.sin6_addr
));
7591 memcpy(&remote
.sin6_addr
, remote_addr
, sizeof(remote
.sin6_addr
));
7593 return (necp_socket_is_allowed_to_send_recv_internal(inp
, (struct sockaddr
*)&local
, (struct sockaddr
*)&remote
, interface
, return_policy_id
, return_route_rule_id
));
7597 necp_socket_is_allowed_to_send_recv(struct inpcb
*inp
, necp_kernel_policy_id
*return_policy_id
, u_int32_t
*return_route_rule_id
)
7599 return (necp_socket_is_allowed_to_send_recv_internal(inp
, NULL
, NULL
, NULL
, return_policy_id
, return_route_rule_id
));
7603 necp_mark_packet_from_socket(struct mbuf
*packet
, struct inpcb
*inp
, necp_kernel_policy_id policy_id
, u_int32_t route_rule_id
)
7605 if (packet
== NULL
|| inp
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
7609 // Mark ID for Pass and IP Tunnel
7610 if (policy_id
!= NECP_KERNEL_POLICY_ID_NONE
) {
7611 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= policy_id
;
7612 } else if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_PASS
||
7613 inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
) {
7614 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= inp
->inp_policyresult
.policy_id
;
7616 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
7618 packet
->m_pkthdr
.necp_mtag
.necp_last_interface_index
= 0;
7619 if (route_rule_id
!= 0) {
7620 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
= route_rule_id
;
7622 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
= inp
->inp_policyresult
.results
.route_rule_id
;
7624 packet
->m_pkthdr
.necp_mtag
.necp_app_id
= inp
->inp_policyresult
.app_id
;
7630 necp_mark_packet_from_ip(struct mbuf
*packet
, necp_kernel_policy_id policy_id
)
7632 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
7636 // Mark ID for Pass and IP Tunnel
7637 if (policy_id
!= NECP_KERNEL_POLICY_ID_NONE
) {
7638 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= policy_id
;
7640 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
7647 necp_mark_packet_from_interface(struct mbuf
*packet
, ifnet_t interface
)
7649 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
7653 // Mark ID for Pass and IP Tunnel
7654 if (interface
!= NULL
) {
7655 packet
->m_pkthdr
.necp_mtag
.necp_last_interface_index
= interface
->if_index
;
7662 necp_mark_packet_as_keepalive(struct mbuf
*packet
, bool is_keepalive
)
7664 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
7669 packet
->m_pkthdr
.pkt_flags
|= PKTF_KEEPALIVE
;
7671 packet
->m_pkthdr
.pkt_flags
&= ~PKTF_KEEPALIVE
;
7677 necp_kernel_policy_id
7678 necp_get_policy_id_from_packet(struct mbuf
*packet
)
7680 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
7681 return (NECP_KERNEL_POLICY_ID_NONE
);
7684 return (packet
->m_pkthdr
.necp_mtag
.necp_policy_id
);
7688 necp_get_last_interface_index_from_packet(struct mbuf
*packet
)
7690 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
7694 return (packet
->m_pkthdr
.necp_mtag
.necp_last_interface_index
);
7698 necp_get_route_rule_id_from_packet(struct mbuf
*packet
)
7700 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
7704 return (packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
);
7708 necp_get_app_uuid_from_packet(struct mbuf
*packet
,
7711 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
7715 bool found_mapping
= FALSE
;
7716 if (packet
->m_pkthdr
.necp_mtag
.necp_app_id
!= 0) {
7717 lck_rw_lock_shared(&necp_kernel_policy_lock
);
7718 struct necp_uuid_id_mapping
*entry
= necp_uuid_lookup_uuid_with_app_id_locked(packet
->m_pkthdr
.necp_mtag
.necp_app_id
);
7719 if (entry
!= NULL
) {
7720 uuid_copy(app_uuid
, entry
->uuid
);
7721 found_mapping
= true;
7723 lck_rw_done(&necp_kernel_policy_lock
);
7725 if (!found_mapping
) {
7726 uuid_clear(app_uuid
);
7732 necp_get_is_keepalive_from_packet(struct mbuf
*packet
)
7734 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
7738 return (packet
->m_pkthdr
.pkt_flags
& PKTF_KEEPALIVE
);
7742 necp_socket_get_content_filter_control_unit(struct socket
*so
)
7744 struct inpcb
*inp
= sotoinpcb(so
);
7749 return (inp
->inp_policyresult
.results
.filter_control_unit
);
7753 necp_socket_should_use_flow_divert(struct inpcb
*inp
)
7759 return (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
);
7763 necp_socket_get_flow_divert_control_unit(struct inpcb
*inp
)
7769 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
) {
7770 return (inp
->inp_policyresult
.results
.result_parameter
.flow_divert_control_unit
);
7777 necp_socket_should_rescope(struct inpcb
*inp
)
7783 return (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
);
7787 necp_socket_get_rescope_if_index(struct inpcb
*inp
)
7793 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
) {
7794 return (inp
->inp_policyresult
.results
.result_parameter
.scoped_interface_index
);
7801 necp_socket_get_effective_mtu(struct inpcb
*inp
, u_int32_t current_mtu
)
7804 return (current_mtu
);
7807 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&&
7808 (inp
->inp_flags
& INP_BOUND_IF
) &&
7809 inp
->inp_boundifp
) {
7811 u_int bound_interface_index
= inp
->inp_boundifp
->if_index
;
7812 u_int tunnel_interface_index
= inp
->inp_policyresult
.results
.result_parameter
.tunnel_interface_index
;
7814 // The result is IP Tunnel, and is rescoping from one interface to another. Recalculate MTU.
7815 if (bound_interface_index
!= tunnel_interface_index
) {
7816 ifnet_t tunnel_interface
= NULL
;
7818 ifnet_head_lock_shared();
7819 tunnel_interface
= ifindex2ifnet
[tunnel_interface_index
];
7822 if (tunnel_interface
!= NULL
) {
7823 u_int32_t direct_tunnel_mtu
= tunnel_interface
->if_mtu
;
7824 u_int32_t delegate_tunnel_mtu
= (tunnel_interface
->if_delegated
.ifp
!= NULL
) ? tunnel_interface
->if_delegated
.ifp
->if_mtu
: 0;
7825 if (delegate_tunnel_mtu
!= 0 &&
7826 strncmp(tunnel_interface
->if_name
, "ipsec", strlen("ipsec")) == 0) {
7827 // For ipsec interfaces, calculate the overhead from the delegate interface
7828 u_int32_t tunnel_overhead
= (u_int32_t
)(esp_hdrsiz(NULL
) + sizeof(struct ip6_hdr
));
7829 if (delegate_tunnel_mtu
> tunnel_overhead
) {
7830 delegate_tunnel_mtu
-= tunnel_overhead
;
7833 if (delegate_tunnel_mtu
< direct_tunnel_mtu
) {
7834 // If the (delegate - overhead) < direct, return (delegate - overhead)
7835 return (delegate_tunnel_mtu
);
7837 // Otherwise return direct
7838 return (direct_tunnel_mtu
);
7841 // For non-ipsec interfaces, just return the tunnel MTU
7842 return (direct_tunnel_mtu
);
7848 // By default, just return the MTU passed in
7849 return (current_mtu
);
7853 necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter
*result_parameter
)
7855 if (result_parameter
== NULL
) {
7859 return (ifindex2ifnet
[result_parameter
->tunnel_interface_index
]);
7863 necp_packet_can_rebind_to_ifnet(struct mbuf
*packet
, struct ifnet
*interface
, struct route
*new_route
, int family
)
7865 bool found_match
= FALSE
;
7867 ifaddr_t
*addresses
= NULL
;
7868 union necp_sockaddr_union address_storage
;
7871 if (packet
== NULL
|| interface
== NULL
|| new_route
== NULL
|| (family
!= AF_INET
&& family
!= AF_INET6
)) {
7875 result
= ifnet_get_address_list_family(interface
, &addresses
, family
);
7877 NECPLOG(LOG_ERR
, "Failed to get address list for %s%d", ifnet_name(interface
), ifnet_unit(interface
));
7881 for (i
= 0; addresses
[i
] != NULL
; i
++) {
7882 ROUTE_RELEASE(new_route
);
7883 if (ifaddr_address(addresses
[i
], &address_storage
.sa
, sizeof(address_storage
)) == 0) {
7884 if (family
== AF_INET
) {
7885 struct ip
*ip
= mtod(packet
, struct ip
*);
7886 if (memcmp(&address_storage
.sin
.sin_addr
, &ip
->ip_src
, sizeof(ip
->ip_src
)) == 0) {
7887 struct sockaddr_in
*dst4
= (struct sockaddr_in
*)(void *)&new_route
->ro_dst
;
7888 dst4
->sin_family
= AF_INET
;
7889 dst4
->sin_len
= sizeof(struct sockaddr_in
);
7890 dst4
->sin_addr
= ip
->ip_dst
;
7891 rtalloc_scoped(new_route
, interface
->if_index
);
7892 if (!ROUTE_UNUSABLE(new_route
)) {
7897 } else if (family
== AF_INET6
) {
7898 struct ip6_hdr
*ip6
= mtod(packet
, struct ip6_hdr
*);
7899 if (memcmp(&address_storage
.sin6
.sin6_addr
, &ip6
->ip6_src
, sizeof(ip6
->ip6_src
)) == 0) {
7900 struct sockaddr_in6
*dst6
= (struct sockaddr_in6
*)(void *)&new_route
->ro_dst
;
7901 dst6
->sin6_family
= AF_INET6
;
7902 dst6
->sin6_len
= sizeof(struct sockaddr_in6
);
7903 dst6
->sin6_addr
= ip6
->ip6_dst
;
7904 rtalloc_scoped(new_route
, interface
->if_index
);
7905 if (!ROUTE_UNUSABLE(new_route
)) {
7915 ifnet_free_address_list(addresses
);
7917 return (found_match
);
7921 necp_addr_is_loopback(struct sockaddr
*address
)
7923 if (address
== NULL
) {
7927 if (address
->sa_family
== AF_INET
) {
7928 return (ntohl(((struct sockaddr_in
*)(void *)address
)->sin_addr
.s_addr
) == INADDR_LOOPBACK
);
7929 } else if (address
->sa_family
== AF_INET6
) {
7930 return IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6
*)(void *)address
)->sin6_addr
);
7937 necp_is_loopback(struct sockaddr
*local_addr
, struct sockaddr
*remote_addr
, struct inpcb
*inp
, struct mbuf
*packet
)
7939 // Note: This function only checks for the loopback addresses.
7940 // In the future, we may want to expand to also allow any traffic
7941 // going through the loopback interface, but until then, this
7942 // check is cheaper.
7944 if (local_addr
!= NULL
&& necp_addr_is_loopback(local_addr
)) {
7948 if (remote_addr
!= NULL
&& necp_addr_is_loopback(remote_addr
)) {
7953 if ((inp
->inp_flags
& INP_BOUND_IF
) && inp
->inp_boundifp
&& (inp
->inp_boundifp
->if_flags
& IFF_LOOPBACK
)) {
7956 if (inp
->inp_vflag
& INP_IPV4
) {
7957 if (ntohl(inp
->inp_laddr
.s_addr
) == INADDR_LOOPBACK
||
7958 ntohl(inp
->inp_faddr
.s_addr
) == INADDR_LOOPBACK
) {
7961 } else if (inp
->inp_vflag
& INP_IPV6
) {
7962 if (IN6_IS_ADDR_LOOPBACK(&inp
->in6p_laddr
) ||
7963 IN6_IS_ADDR_LOOPBACK(&inp
->in6p_faddr
)) {
7969 if (packet
!= NULL
) {
7970 struct ip
*ip
= mtod(packet
, struct ip
*);
7971 if (ip
->ip_v
== 4) {
7972 if (ntohl(ip
->ip_src
.s_addr
) == INADDR_LOOPBACK
) {
7975 if (ntohl(ip
->ip_dst
.s_addr
) == INADDR_LOOPBACK
) {
7978 } else if (ip
->ip_v
== 6) {
7979 struct ip6_hdr
*ip6
= mtod(packet
, struct ip6_hdr
*);
7980 if (IN6_IS_ADDR_LOOPBACK(&ip6
->ip6_src
)) {
7983 if (IN6_IS_ADDR_LOOPBACK(&ip6
->ip6_dst
)) {
7993 necp_is_intcoproc(struct inpcb
*inp
, struct mbuf
*packet
)
7997 return (sflt_permission_check(inp
) ? true : false);
7999 if (packet
!= NULL
) {
8000 struct ip6_hdr
*ip6
= mtod(packet
, struct ip6_hdr
*);
8001 if ((ip6
->ip6_vfc
& IPV6_VERSION_MASK
) == IPV6_VERSION
&&
8002 IN6_IS_ADDR_LINKLOCAL(&ip6
->ip6_dst
) &&
8003 ip6
->ip6_dst
.s6_addr32
[2] == ntohl(0xaede48ff) &&
8004 ip6
->ip6_dst
.s6_addr32
[3] == ntohl(0xfe334455)) {